@agent-native/core 0.28.3 → 0.28.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/connect.js +1 -1
- package/dist/cli/connect.js.map +1 -1
- package/dist/cli/mcp-config-writers.d.ts +2 -1
- package/dist/cli/mcp-config-writers.d.ts.map +1 -1
- package/dist/cli/mcp-config-writers.js +5 -1
- package/dist/cli/mcp-config-writers.js.map +1 -1
- package/dist/cli/mcp.d.ts.map +1 -1
- package/dist/cli/mcp.js +3 -0
- package/dist/cli/mcp.js.map +1 -1
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +46 -3
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/mcp-app-host.d.ts +1 -0
- package/dist/client/mcp-app-host.d.ts.map +1 -1
- package/dist/client/mcp-app-host.js +12 -1
- package/dist/client/mcp-app-host.js.map +1 -1
- package/dist/mcp/embed-app.d.ts.map +1 -1
- package/dist/mcp/embed-app.js +13 -9
- package/dist/mcp/embed-app.js.map +1 -1
- package/docs/content/external-agents.md +1 -1
- package/docs/content/template-assets.md +5 -1
- package/package.json +1 -1
|
@@ -247,6 +247,9 @@ function postWrapperHostChat(chat) {
|
|
|
247
247
|
context: chat.context?.trim() || "",
|
|
248
248
|
submit: true,
|
|
249
249
|
...(chat.content?.length ? { content: chat.content } : {}),
|
|
250
|
+
...(chat.structuredContent !== undefined
|
|
251
|
+
? { structuredContent: chat.structuredContent }
|
|
252
|
+
: {}),
|
|
250
253
|
},
|
|
251
254
|
}, "*");
|
|
252
255
|
}
|
|
@@ -398,7 +401,12 @@ export function sendMcpAppHostMessage(chat) {
|
|
|
398
401
|
openAiBridge.setWidgetState({
|
|
399
402
|
...objectValue(openAiBridge.widgetState),
|
|
400
403
|
agentNativeChatContext: context,
|
|
401
|
-
agentNativeModelContext: {
|
|
404
|
+
agentNativeModelContext: {
|
|
405
|
+
content: contextContent,
|
|
406
|
+
...(chat.structuredContent !== undefined
|
|
407
|
+
? { structuredContent: chat.structuredContent }
|
|
408
|
+
: {}),
|
|
409
|
+
},
|
|
402
410
|
});
|
|
403
411
|
}
|
|
404
412
|
await openAiBridge.sendFollowUpMessage({
|
|
@@ -411,6 +419,9 @@ export function sendMcpAppHostMessage(chat) {
|
|
|
411
419
|
try {
|
|
412
420
|
await postJsonRpcRequest("ui/update-model-context", {
|
|
413
421
|
content: contextContent,
|
|
422
|
+
...(chat.structuredContent !== undefined
|
|
423
|
+
? { structuredContent: chat.structuredContent }
|
|
424
|
+
: {}),
|
|
414
425
|
});
|
|
415
426
|
}
|
|
416
427
|
catch {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-app-host.js","sourceRoot":"","sources":["../../src/client/mcp-app-host.ts"],"names":[],"mappings":"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","sourcesContent":["import { useSyncExternalStore } from \"react\";\nimport { getFrameOrigin } from \"./frame.js\";\nimport {\n getEmbedAuthToken,\n isEmbedAuthActive,\n markEmbedMcpChatBridgeActive,\n isEmbedMcpChatBridgeActive,\n readEmbedMcpChatBridgeFlagFromUrl,\n} from \"./embed-auth.js\";\nimport {\n EMBED_MODE_QUERY_PARAM,\n EMBED_TOKEN_QUERY_PARAM,\n MCP_APP_CHAT_BRIDGE_QUERY_PARAM,\n} from \"../shared/embed-auth.js\";\n\nexport const AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES = {\n HOST_CONTEXT: \"agentNative.mcpHostContext\",\n UPDATE_MODEL_CONTEXT: \"agentNative.mcpHost.updateModelContext\",\n OPEN_LINK: \"agentNative.mcpHost.openLink\",\n REQUEST_DISPLAY_MODE: \"agentNative.mcpHost.requestDisplayMode\",\n RESPONSE: \"agentNative.mcpHost.response\",\n} as const;\n\nexport type AgentNativeMcpAppHostMessageType =\n (typeof AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES)[keyof typeof AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES];\n\nexport type McpAppDisplayMode = \"inline\" | \"pip\" | \"fullscreen\" | (string & {});\n\nexport interface McpAppModelContextContentPart {\n type: string;\n [key: string]: unknown;\n}\n\nexport interface McpAppModelContextUpdate {\n content?: McpAppModelContextContentPart[];\n structuredContent?: unknown;\n}\n\nexport interface McpAppHostChatMessage {\n message: string;\n context?: string;\n content?: McpAppModelContextContentPart[];\n}\n\nexport interface McpAppHostCapabilities {\n updateModelContext?: boolean;\n openLink?: boolean;\n displayModes?: McpAppDisplayMode[];\n [key: string]: unknown;\n}\n\nexport interface McpAppHostContext {\n capabilities?: McpAppHostCapabilities;\n [key: string]: unknown;\n}\n\nexport interface McpAppHostContextSnapshot {\n context: McpAppHostContext | null;\n capabilities: McpAppHostCapabilities | null;\n version: unknown;\n}\n\ntype PendingRequest = {\n resolve: (ok: boolean) => void;\n timeout: ReturnType<typeof setTimeout>;\n};\n\ntype PendingJsonRpcRequest = {\n resolve: (result: unknown) => void;\n reject: (error: Error) => void;\n timeout: ReturnType<typeof setTimeout>;\n};\n\ntype HostContextMessage = {\n type: typeof AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES.HOST_CONTEXT;\n data?: {\n context?: unknown;\n capabilities?: unknown;\n version?: unknown;\n };\n};\n\ntype HostResponseMessage = {\n type: typeof AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES.RESPONSE;\n data?: {\n requestId?: unknown;\n ok?: unknown;\n result?: unknown;\n error?: unknown;\n };\n};\n\nconst REQUEST_TIMEOUT_MS = 5000;\nconst DIRECT_MCP_APP_PROTOCOL_VERSION = \"2026-01-26\";\n\nlet snapshot: McpAppHostContextSnapshot = {\n context: null,\n capabilities: null,\n version: null,\n};\nconst listeners = new Set<() => void>();\nconst pending = new Map<string, PendingRequest>();\nconst jsonRpcPending = new Map<string, PendingJsonRpcRequest>();\nlet directMcpAppInit: Promise<boolean> | null = null;\nlet listenerInstalled = false;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction isBrowserWindow(): boolean {\n return (\n typeof window !== \"undefined\" && typeof window.postMessage === \"function\"\n );\n}\n\nfunction isInChildFrame(): boolean {\n if (!isBrowserWindow()) return false;\n try {\n return window.parent !== window;\n } catch {\n return false;\n }\n}\n\nfunction isMcpAppBridgeEnabled(): boolean {\n if (!isBrowserWindow()) return false;\n if (readEmbedMcpChatBridgeFlagFromUrl()) markEmbedMcpChatBridgeActive();\n if (isEmbedMcpChatBridgeActive() && isEmbedAuthActive()) return true;\n const params = new URLSearchParams(window.location.search || \"\");\n return (\n params.get(EMBED_MODE_QUERY_PARAM) === \"1\" &&\n (params.has(EMBED_TOKEN_QUERY_PARAM) || Boolean(getEmbedAuthToken())) &&\n params.get(MCP_APP_CHAT_BRIDGE_QUERY_PARAM) === \"1\"\n );\n}\n\nfunction isClaudeMcpContentHost(): boolean {\n if (!isBrowserWindow()) return false;\n try {\n return /(^|\\.)claudemcpcontent\\.com$/i.test(window.location.hostname || \"\");\n } catch {\n return false;\n }\n}\n\nfunction hasWrapperBridge(): boolean {\n if (!isBrowserWindow()) return false;\n const params = new URLSearchParams(window.location.search || \"\");\n const mode =\n params.get(\"embedMode\") ??\n params.get(\"renderMode\") ??\n params.get(\"embed_mode\") ??\n \"\";\n if (mode === \"iframe\" || mode === \"nested\") return true;\n if (params.get(\"nested\") === \"1\" || params.get(\"frame\") === \"iframe\") {\n return true;\n }\n if (isClaudeMcpContentHost()) return false;\n return Boolean(getFrameOrigin());\n}\n\nfunction isTrustedParentMessage(event: MessageEvent): boolean {\n if (!isInChildFrame()) return false;\n return event.source === window.parent;\n}\n\nfunction requestId(): string {\n return `mcp-host-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\nfunction jsonRpcRequestId(): string {\n return `mcp-ui-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\nfunction notify() {\n for (const listener of listeners) listener();\n}\n\nfunction updateSnapshot(data: HostContextMessage[\"data\"]): void {\n if (!isRecord(data)) return;\n snapshot = {\n context: isRecord(data.context)\n ? (data.context as McpAppHostContext)\n : snapshot.context,\n capabilities: isRecord(data.capabilities)\n ? (data.capabilities as McpAppHostCapabilities)\n : snapshot.capabilities,\n version: data.version !== undefined ? data.version : snapshot.version,\n };\n notify();\n}\n\nfunction updateSnapshotFromInitialize(result: unknown): void {\n if (!isRecord(result)) return;\n updateSnapshot({\n context: result.hostContext,\n capabilities: result.hostCapabilities,\n version: result.hostInfo ?? result.protocolVersion,\n });\n}\n\nfunction updateSnapshotFromOpenAiBridge(bridge: OpenAiAppBridge): void {\n updateSnapshot({\n context: {\n displayMode: bridge.displayMode,\n availableDisplayModes:\n typeof bridge.requestDisplayMode === \"function\"\n ? [\"inline\", \"fullscreen\", \"pip\"]\n : [],\n maxHeight: bridge.maxHeight,\n locale: bridge.locale,\n theme: bridge.theme,\n view: bridge.view,\n },\n capabilities: {\n updateModelContext: typeof bridge.setWidgetState === \"function\",\n openLink: typeof bridge.openExternal === \"function\",\n displayModes:\n typeof bridge.requestDisplayMode === \"function\"\n ? [\"inline\", \"fullscreen\", \"pip\"]\n : [],\n openai: true,\n },\n version: bridge.userAgent,\n });\n}\n\nfunction resolvePending(data: HostResponseMessage[\"data\"]): void {\n if (!isRecord(data) || typeof data.requestId !== \"string\") return;\n const request = pending.get(data.requestId);\n if (!request) return;\n pending.delete(data.requestId);\n clearTimeout(request.timeout);\n request.resolve(data.ok === true);\n}\n\nfunction resolveJsonRpc(data: Record<string, unknown>): void {\n const id = typeof data.id === \"string\" ? data.id : String(data.id ?? \"\");\n if (!id) return;\n const request = jsonRpcPending.get(id);\n if (!request) return;\n jsonRpcPending.delete(id);\n clearTimeout(request.timeout);\n if (isRecord(data.error)) {\n const message =\n typeof data.error.message === \"string\"\n ? data.error.message\n : \"MCP Apps host request failed.\";\n request.reject(new Error(message));\n return;\n }\n request.resolve(data.result ?? {});\n}\n\nfunction handleJsonRpcNotification(message: Record<string, unknown>): void {\n if (message.method !== \"ui/notifications/host-context-changed\") return;\n updateSnapshot({\n context: isRecord(message.params) ? message.params : undefined,\n });\n}\n\nfunction onMessage(event: MessageEvent): void {\n if (!isTrustedParentMessage(event)) return;\n const message = event.data;\n if (!isRecord(message)) return;\n\n if (message.type === AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES.HOST_CONTEXT) {\n updateSnapshot((message as HostContextMessage).data);\n return;\n }\n\n if (message.type === AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES.RESPONSE) {\n resolvePending((message as HostResponseMessage).data);\n return;\n }\n\n if (message.jsonrpc === \"2.0\") {\n if (\"id\" in message && (\"result\" in message || \"error\" in message)) {\n resolveJsonRpc(message);\n return;\n }\n if (typeof message.method === \"string\") {\n handleJsonRpcNotification(message);\n }\n }\n}\n\nfunction ensureListener(): void {\n if (!isBrowserWindow() || listenerInstalled) return;\n window.addEventListener(\"message\", onMessage);\n listenerInstalled = true;\n}\n\nfunction postHostRequest(\n type:\n | typeof AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES.UPDATE_MODEL_CONTEXT\n | typeof AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES.OPEN_LINK\n | typeof AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES.REQUEST_DISPLAY_MODE,\n data: Record<string, unknown>,\n): Promise<boolean> | false {\n ensureListener();\n if (!isInChildFrame() || !isMcpAppBridgeEnabled()) return false;\n\n if (!hasWrapperBridge()) {\n return postDirectHostRequest(type, data);\n }\n\n const id =\n typeof data.requestId === \"string\" && data.requestId\n ? data.requestId\n : requestId();\n const payload = { ...data, requestId: id };\n\n return new Promise((resolve) => {\n const timeout = setTimeout(() => {\n pending.delete(id);\n resolve(false);\n }, REQUEST_TIMEOUT_MS);\n pending.set(id, { resolve, timeout });\n\n try {\n window.parent.postMessage({ type, data: payload }, \"*\");\n } catch {\n pending.delete(id);\n clearTimeout(timeout);\n resolve(false);\n }\n });\n}\n\nfunction postWrapperHostChat(chat: McpAppHostChatMessage): Promise<boolean> {\n ensureListener();\n const id = requestId();\n return new Promise((resolve) => {\n const timeout = setTimeout(() => {\n pending.delete(id);\n resolve(false);\n }, REQUEST_TIMEOUT_MS);\n pending.set(id, { resolve, timeout });\n\n try {\n window.parent.postMessage(\n {\n type: \"agentNative.submitChat\",\n data: {\n requestId: id,\n message: chat.message,\n context: chat.context?.trim() || \"\",\n submit: true,\n ...(chat.content?.length ? { content: chat.content } : {}),\n },\n },\n \"*\",\n );\n } catch {\n pending.delete(id);\n clearTimeout(timeout);\n resolve(false);\n }\n });\n}\n\ninterface OpenAiAppBridge {\n widgetState?: unknown;\n displayMode?: unknown;\n maxHeight?: unknown;\n locale?: unknown;\n theme?: unknown;\n view?: unknown;\n userAgent?: unknown;\n setWidgetState?: (state: unknown) => void;\n sendFollowUpMessage?: (args: {\n prompt: string;\n scrollToBottom?: boolean;\n }) => unknown | Promise<unknown>;\n openExternal?: (args: {\n href: string;\n redirectUrl?: boolean;\n }) => unknown | Promise<unknown>;\n requestDisplayMode?: (args: {\n mode: McpAppDisplayMode;\n }) => unknown | Promise<unknown>;\n}\n\nfunction readOpenAiBridge(): OpenAiAppBridge | null {\n if (!isBrowserWindow()) return null;\n const bridge = (window as unknown as { openai?: unknown }).openai;\n return bridge && typeof bridge === \"object\"\n ? (bridge as OpenAiAppBridge)\n : null;\n}\n\nfunction objectValue(value: unknown): Record<string, unknown> {\n return isRecord(value) ? value : {};\n}\n\nfunction postJsonRpcNotification(method: string, params?: unknown): void {\n if (!isInChildFrame()) return;\n try {\n window.parent.postMessage({ jsonrpc: \"2.0\", method, params }, \"*\");\n } catch {\n // Best-effort lifecycle notification.\n }\n}\n\nfunction postJsonRpcRequest(\n method: string,\n params?: unknown,\n): Promise<unknown> | false {\n ensureListener();\n if (!isInChildFrame()) return false;\n\n const id = jsonRpcRequestId();\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n jsonRpcPending.delete(id);\n reject(new Error(\"MCP Apps host did not respond.\"));\n }, REQUEST_TIMEOUT_MS);\n jsonRpcPending.set(id, { resolve, reject, timeout });\n\n try {\n window.parent.postMessage({ jsonrpc: \"2.0\", id, method, params }, \"*\");\n } catch (err) {\n jsonRpcPending.delete(id);\n clearTimeout(timeout);\n reject(err instanceof Error ? err : new Error(String(err)));\n }\n });\n}\n\nasync function ensureDirectMcpAppInitialized(): Promise<boolean> {\n if (!isInChildFrame() || !isMcpAppBridgeEnabled()) return false;\n if (hasWrapperBridge()) return true;\n\n const openAiBridge = readOpenAiBridge();\n if (openAiBridge) {\n updateSnapshotFromOpenAiBridge(openAiBridge);\n return true;\n }\n\n if (!directMcpAppInit) {\n directMcpAppInit = (async () => {\n const result = await postJsonRpcRequest(\"ui/initialize\", {\n protocolVersion: DIRECT_MCP_APP_PROTOCOL_VERSION,\n appInfo: { name: \"Agent Native App\", version: \"1.0.0\" },\n appCapabilities: {\n availableDisplayModes: [\"inline\", \"fullscreen\", \"pip\"],\n },\n });\n updateSnapshotFromInitialize(result);\n postJsonRpcNotification(\"ui/notifications/initialized\", {});\n return true;\n })().catch(() => false);\n }\n\n return directMcpAppInit;\n}\n\nasync function waitForDirectMcpAppInitialized(): Promise<void> {\n const ok = await ensureDirectMcpAppInitialized();\n if (!ok) throw new Error(\"MCP Apps host bridge is not available.\");\n}\n\nasync function postDirectHostRequest(\n type:\n | typeof AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES.UPDATE_MODEL_CONTEXT\n | typeof AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES.OPEN_LINK\n | typeof AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES.REQUEST_DISPLAY_MODE,\n data: Record<string, unknown>,\n): Promise<boolean> {\n const openAiBridge = readOpenAiBridge();\n if (openAiBridge) {\n updateSnapshotFromOpenAiBridge(openAiBridge);\n if (\n type === AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES.UPDATE_MODEL_CONTEXT &&\n typeof openAiBridge.setWidgetState === \"function\"\n ) {\n openAiBridge.setWidgetState({\n ...objectValue(openAiBridge.widgetState),\n agentNativeModelContext: {\n ...(Array.isArray(data.content) ? { content: data.content } : {}),\n ...(data.structuredContent !== undefined\n ? { structuredContent: data.structuredContent }\n : {}),\n },\n });\n return true;\n }\n if (\n type === AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES.OPEN_LINK &&\n typeof openAiBridge.openExternal === \"function\" &&\n typeof data.url === \"string\"\n ) {\n await openAiBridge.openExternal({\n href: data.url,\n redirectUrl: false,\n });\n return true;\n }\n if (\n type === AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES.REQUEST_DISPLAY_MODE &&\n typeof openAiBridge.requestDisplayMode === \"function\" &&\n typeof data.mode === \"string\"\n ) {\n await openAiBridge.requestDisplayMode({ mode: data.mode });\n updateSnapshotFromOpenAiBridge(openAiBridge);\n return true;\n }\n }\n\n await waitForDirectMcpAppInitialized();\n const method =\n type === AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES.UPDATE_MODEL_CONTEXT\n ? \"ui/update-model-context\"\n : type === AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES.OPEN_LINK\n ? \"ui/open-link\"\n : \"ui/request-display-mode\";\n await postJsonRpcRequest(method, data);\n return true;\n}\n\nexport function sendMcpAppHostMessage(\n chat: McpAppHostChatMessage,\n): Promise<boolean> | false {\n if (!chat.message.trim() || !isInChildFrame() || !isMcpAppBridgeEnabled()) {\n return false;\n }\n\n if (hasWrapperBridge()) return postWrapperHostChat(chat);\n\n return (async () => {\n const openAiBridge = readOpenAiBridge();\n const context = chat.context?.trim() || null;\n const content = chat.content?.length\n ? chat.content\n : [{ type: \"text\", text: chat.message }];\n const contextContent = context\n ? [\n { type: \"text\", text: context },\n ...content.filter((part) => part && part.type !== \"text\"),\n ]\n : content.filter((part) => part && part.type !== \"text\");\n if (\n openAiBridge &&\n typeof openAiBridge.sendFollowUpMessage === \"function\"\n ) {\n updateSnapshotFromOpenAiBridge(openAiBridge);\n if (typeof openAiBridge.setWidgetState === \"function\") {\n openAiBridge.setWidgetState({\n ...objectValue(openAiBridge.widgetState),\n agentNativeChatContext: context,\n agentNativeModelContext: { content: contextContent },\n });\n }\n await openAiBridge.sendFollowUpMessage({\n prompt: chat.message,\n scrollToBottom: true,\n });\n return true;\n }\n\n await waitForDirectMcpAppInitialized();\n try {\n await postJsonRpcRequest(\"ui/update-model-context\", {\n content: contextContent,\n });\n } catch {\n // Best effort: a host without model-context support should still receive\n // the visible chat message.\n }\n await postJsonRpcRequest(\"ui/message\", {\n role: \"user\",\n content,\n });\n return true;\n })().catch(() => false);\n}\n\nexport function getMcpAppHostContext(): McpAppHostContextSnapshot {\n ensureListener();\n const bridge = readOpenAiBridge();\n if (bridge) updateSnapshotFromOpenAiBridge(bridge);\n return snapshot;\n}\n\nexport function useMcpAppHostContext(): McpAppHostContextSnapshot {\n ensureListener();\n return useSyncExternalStore(\n (listener) => {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n () => snapshot,\n () => ({ context: null, capabilities: null, version: null }),\n );\n}\n\nexport function updateMcpAppModelContext(\n update: McpAppModelContextUpdate,\n): Promise<boolean> | false {\n return postHostRequest(\n AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES.UPDATE_MODEL_CONTEXT,\n {\n ...(Array.isArray(update.content) ? { content: update.content } : {}),\n ...(update.structuredContent !== undefined\n ? { structuredContent: update.structuredContent }\n : {}),\n },\n );\n}\n\nexport function openMcpAppHostLink(url: string): Promise<boolean> | false {\n if (!url) return false;\n return postHostRequest(AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES.OPEN_LINK, {\n url,\n });\n}\n\nexport function requestMcpAppDisplayMode(\n mode: McpAppDisplayMode,\n): Promise<boolean> | false {\n if (!mode) return false;\n return postHostRequest(\n AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES.REQUEST_DISPLAY_MODE,\n { mode },\n );\n}\n\nensureListener();\n\n/** Internal test helper. Do not use in app code. */\nexport function _resetMcpAppHostForTests(): void {\n for (const request of pending.values()) clearTimeout(request.timeout);\n for (const request of jsonRpcPending.values()) clearTimeout(request.timeout);\n pending.clear();\n jsonRpcPending.clear();\n directMcpAppInit = null;\n snapshot = { context: null, capabilities: null, version: null };\n listeners.clear();\n}\n\nif (isBrowserWindow()) {\n window.addEventListener(\n \"openai:set_globals\",\n () => {\n const bridge = readOpenAiBridge();\n if (bridge) updateSnapshotFromOpenAiBridge(bridge);\n },\n { passive: true },\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"mcp-app-host.js","sourceRoot":"","sources":["../../src/client/mcp-app-host.ts"],"names":[],"mappings":"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","sourcesContent":["import { useSyncExternalStore } from \"react\";\nimport { getFrameOrigin } from \"./frame.js\";\nimport {\n getEmbedAuthToken,\n isEmbedAuthActive,\n markEmbedMcpChatBridgeActive,\n isEmbedMcpChatBridgeActive,\n readEmbedMcpChatBridgeFlagFromUrl,\n} from \"./embed-auth.js\";\nimport {\n EMBED_MODE_QUERY_PARAM,\n EMBED_TOKEN_QUERY_PARAM,\n MCP_APP_CHAT_BRIDGE_QUERY_PARAM,\n} from \"../shared/embed-auth.js\";\n\nexport const AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES = {\n HOST_CONTEXT: \"agentNative.mcpHostContext\",\n UPDATE_MODEL_CONTEXT: \"agentNative.mcpHost.updateModelContext\",\n OPEN_LINK: \"agentNative.mcpHost.openLink\",\n REQUEST_DISPLAY_MODE: \"agentNative.mcpHost.requestDisplayMode\",\n RESPONSE: \"agentNative.mcpHost.response\",\n} as const;\n\nexport type AgentNativeMcpAppHostMessageType =\n (typeof AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES)[keyof typeof AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES];\n\nexport type McpAppDisplayMode = \"inline\" | \"pip\" | \"fullscreen\" | (string & {});\n\nexport interface McpAppModelContextContentPart {\n type: string;\n [key: string]: unknown;\n}\n\nexport interface McpAppModelContextUpdate {\n content?: McpAppModelContextContentPart[];\n structuredContent?: unknown;\n}\n\nexport interface McpAppHostChatMessage {\n message: string;\n context?: string;\n content?: McpAppModelContextContentPart[];\n structuredContent?: unknown;\n}\n\nexport interface McpAppHostCapabilities {\n updateModelContext?: boolean;\n openLink?: boolean;\n displayModes?: McpAppDisplayMode[];\n [key: string]: unknown;\n}\n\nexport interface McpAppHostContext {\n capabilities?: McpAppHostCapabilities;\n [key: string]: unknown;\n}\n\nexport interface McpAppHostContextSnapshot {\n context: McpAppHostContext | null;\n capabilities: McpAppHostCapabilities | null;\n version: unknown;\n}\n\ntype PendingRequest = {\n resolve: (ok: boolean) => void;\n timeout: ReturnType<typeof setTimeout>;\n};\n\ntype PendingJsonRpcRequest = {\n resolve: (result: unknown) => void;\n reject: (error: Error) => void;\n timeout: ReturnType<typeof setTimeout>;\n};\n\ntype HostContextMessage = {\n type: typeof AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES.HOST_CONTEXT;\n data?: {\n context?: unknown;\n capabilities?: unknown;\n version?: unknown;\n };\n};\n\ntype HostResponseMessage = {\n type: typeof AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES.RESPONSE;\n data?: {\n requestId?: unknown;\n ok?: unknown;\n result?: unknown;\n error?: unknown;\n };\n};\n\nconst REQUEST_TIMEOUT_MS = 5000;\nconst DIRECT_MCP_APP_PROTOCOL_VERSION = \"2026-01-26\";\n\nlet snapshot: McpAppHostContextSnapshot = {\n context: null,\n capabilities: null,\n version: null,\n};\nconst listeners = new Set<() => void>();\nconst pending = new Map<string, PendingRequest>();\nconst jsonRpcPending = new Map<string, PendingJsonRpcRequest>();\nlet directMcpAppInit: Promise<boolean> | null = null;\nlet listenerInstalled = false;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction isBrowserWindow(): boolean {\n return (\n typeof window !== \"undefined\" && typeof window.postMessage === \"function\"\n );\n}\n\nfunction isInChildFrame(): boolean {\n if (!isBrowserWindow()) return false;\n try {\n return window.parent !== window;\n } catch {\n return false;\n }\n}\n\nfunction isMcpAppBridgeEnabled(): boolean {\n if (!isBrowserWindow()) return false;\n if (readEmbedMcpChatBridgeFlagFromUrl()) markEmbedMcpChatBridgeActive();\n if (isEmbedMcpChatBridgeActive() && isEmbedAuthActive()) return true;\n const params = new URLSearchParams(window.location.search || \"\");\n return (\n params.get(EMBED_MODE_QUERY_PARAM) === \"1\" &&\n (params.has(EMBED_TOKEN_QUERY_PARAM) || Boolean(getEmbedAuthToken())) &&\n params.get(MCP_APP_CHAT_BRIDGE_QUERY_PARAM) === \"1\"\n );\n}\n\nfunction isClaudeMcpContentHost(): boolean {\n if (!isBrowserWindow()) return false;\n try {\n return /(^|\\.)claudemcpcontent\\.com$/i.test(window.location.hostname || \"\");\n } catch {\n return false;\n }\n}\n\nfunction hasWrapperBridge(): boolean {\n if (!isBrowserWindow()) return false;\n const params = new URLSearchParams(window.location.search || \"\");\n const mode =\n params.get(\"embedMode\") ??\n params.get(\"renderMode\") ??\n params.get(\"embed_mode\") ??\n \"\";\n if (mode === \"iframe\" || mode === \"nested\") return true;\n if (params.get(\"nested\") === \"1\" || params.get(\"frame\") === \"iframe\") {\n return true;\n }\n if (isClaudeMcpContentHost()) return false;\n return Boolean(getFrameOrigin());\n}\n\nfunction isTrustedParentMessage(event: MessageEvent): boolean {\n if (!isInChildFrame()) return false;\n return event.source === window.parent;\n}\n\nfunction requestId(): string {\n return `mcp-host-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\nfunction jsonRpcRequestId(): string {\n return `mcp-ui-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\nfunction notify() {\n for (const listener of listeners) listener();\n}\n\nfunction updateSnapshot(data: HostContextMessage[\"data\"]): void {\n if (!isRecord(data)) return;\n snapshot = {\n context: isRecord(data.context)\n ? (data.context as McpAppHostContext)\n : snapshot.context,\n capabilities: isRecord(data.capabilities)\n ? (data.capabilities as McpAppHostCapabilities)\n : snapshot.capabilities,\n version: data.version !== undefined ? data.version : snapshot.version,\n };\n notify();\n}\n\nfunction updateSnapshotFromInitialize(result: unknown): void {\n if (!isRecord(result)) return;\n updateSnapshot({\n context: result.hostContext,\n capabilities: result.hostCapabilities,\n version: result.hostInfo ?? result.protocolVersion,\n });\n}\n\nfunction updateSnapshotFromOpenAiBridge(bridge: OpenAiAppBridge): void {\n updateSnapshot({\n context: {\n displayMode: bridge.displayMode,\n availableDisplayModes:\n typeof bridge.requestDisplayMode === \"function\"\n ? [\"inline\", \"fullscreen\", \"pip\"]\n : [],\n maxHeight: bridge.maxHeight,\n locale: bridge.locale,\n theme: bridge.theme,\n view: bridge.view,\n },\n capabilities: {\n updateModelContext: typeof bridge.setWidgetState === \"function\",\n openLink: typeof bridge.openExternal === \"function\",\n displayModes:\n typeof bridge.requestDisplayMode === \"function\"\n ? [\"inline\", \"fullscreen\", \"pip\"]\n : [],\n openai: true,\n },\n version: bridge.userAgent,\n });\n}\n\nfunction resolvePending(data: HostResponseMessage[\"data\"]): void {\n if (!isRecord(data) || typeof data.requestId !== \"string\") return;\n const request = pending.get(data.requestId);\n if (!request) return;\n pending.delete(data.requestId);\n clearTimeout(request.timeout);\n request.resolve(data.ok === true);\n}\n\nfunction resolveJsonRpc(data: Record<string, unknown>): void {\n const id = typeof data.id === \"string\" ? data.id : String(data.id ?? \"\");\n if (!id) return;\n const request = jsonRpcPending.get(id);\n if (!request) return;\n jsonRpcPending.delete(id);\n clearTimeout(request.timeout);\n if (isRecord(data.error)) {\n const message =\n typeof data.error.message === \"string\"\n ? data.error.message\n : \"MCP Apps host request failed.\";\n request.reject(new Error(message));\n return;\n }\n request.resolve(data.result ?? {});\n}\n\nfunction handleJsonRpcNotification(message: Record<string, unknown>): void {\n if (message.method !== \"ui/notifications/host-context-changed\") return;\n updateSnapshot({\n context: isRecord(message.params) ? message.params : undefined,\n });\n}\n\nfunction onMessage(event: MessageEvent): void {\n if (!isTrustedParentMessage(event)) return;\n const message = event.data;\n if (!isRecord(message)) return;\n\n if (message.type === AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES.HOST_CONTEXT) {\n updateSnapshot((message as HostContextMessage).data);\n return;\n }\n\n if (message.type === AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES.RESPONSE) {\n resolvePending((message as HostResponseMessage).data);\n return;\n }\n\n if (message.jsonrpc === \"2.0\") {\n if (\"id\" in message && (\"result\" in message || \"error\" in message)) {\n resolveJsonRpc(message);\n return;\n }\n if (typeof message.method === \"string\") {\n handleJsonRpcNotification(message);\n }\n }\n}\n\nfunction ensureListener(): void {\n if (!isBrowserWindow() || listenerInstalled) return;\n window.addEventListener(\"message\", onMessage);\n listenerInstalled = true;\n}\n\nfunction postHostRequest(\n type:\n | typeof AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES.UPDATE_MODEL_CONTEXT\n | typeof AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES.OPEN_LINK\n | typeof AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES.REQUEST_DISPLAY_MODE,\n data: Record<string, unknown>,\n): Promise<boolean> | false {\n ensureListener();\n if (!isInChildFrame() || !isMcpAppBridgeEnabled()) return false;\n\n if (!hasWrapperBridge()) {\n return postDirectHostRequest(type, data);\n }\n\n const id =\n typeof data.requestId === \"string\" && data.requestId\n ? data.requestId\n : requestId();\n const payload = { ...data, requestId: id };\n\n return new Promise((resolve) => {\n const timeout = setTimeout(() => {\n pending.delete(id);\n resolve(false);\n }, REQUEST_TIMEOUT_MS);\n pending.set(id, { resolve, timeout });\n\n try {\n window.parent.postMessage({ type, data: payload }, \"*\");\n } catch {\n pending.delete(id);\n clearTimeout(timeout);\n resolve(false);\n }\n });\n}\n\nfunction postWrapperHostChat(chat: McpAppHostChatMessage): Promise<boolean> {\n ensureListener();\n const id = requestId();\n return new Promise((resolve) => {\n const timeout = setTimeout(() => {\n pending.delete(id);\n resolve(false);\n }, REQUEST_TIMEOUT_MS);\n pending.set(id, { resolve, timeout });\n\n try {\n window.parent.postMessage(\n {\n type: \"agentNative.submitChat\",\n data: {\n requestId: id,\n message: chat.message,\n context: chat.context?.trim() || \"\",\n submit: true,\n ...(chat.content?.length ? { content: chat.content } : {}),\n ...(chat.structuredContent !== undefined\n ? { structuredContent: chat.structuredContent }\n : {}),\n },\n },\n \"*\",\n );\n } catch {\n pending.delete(id);\n clearTimeout(timeout);\n resolve(false);\n }\n });\n}\n\ninterface OpenAiAppBridge {\n widgetState?: unknown;\n displayMode?: unknown;\n maxHeight?: unknown;\n locale?: unknown;\n theme?: unknown;\n view?: unknown;\n userAgent?: unknown;\n setWidgetState?: (state: unknown) => void;\n sendFollowUpMessage?: (args: {\n prompt: string;\n scrollToBottom?: boolean;\n }) => unknown | Promise<unknown>;\n openExternal?: (args: {\n href: string;\n redirectUrl?: boolean;\n }) => unknown | Promise<unknown>;\n requestDisplayMode?: (args: {\n mode: McpAppDisplayMode;\n }) => unknown | Promise<unknown>;\n}\n\nfunction readOpenAiBridge(): OpenAiAppBridge | null {\n if (!isBrowserWindow()) return null;\n const bridge = (window as unknown as { openai?: unknown }).openai;\n return bridge && typeof bridge === \"object\"\n ? (bridge as OpenAiAppBridge)\n : null;\n}\n\nfunction objectValue(value: unknown): Record<string, unknown> {\n return isRecord(value) ? value : {};\n}\n\nfunction postJsonRpcNotification(method: string, params?: unknown): void {\n if (!isInChildFrame()) return;\n try {\n window.parent.postMessage({ jsonrpc: \"2.0\", method, params }, \"*\");\n } catch {\n // Best-effort lifecycle notification.\n }\n}\n\nfunction postJsonRpcRequest(\n method: string,\n params?: unknown,\n): Promise<unknown> | false {\n ensureListener();\n if (!isInChildFrame()) return false;\n\n const id = jsonRpcRequestId();\n return new Promise((resolve, reject) => {\n const timeout = setTimeout(() => {\n jsonRpcPending.delete(id);\n reject(new Error(\"MCP Apps host did not respond.\"));\n }, REQUEST_TIMEOUT_MS);\n jsonRpcPending.set(id, { resolve, reject, timeout });\n\n try {\n window.parent.postMessage({ jsonrpc: \"2.0\", id, method, params }, \"*\");\n } catch (err) {\n jsonRpcPending.delete(id);\n clearTimeout(timeout);\n reject(err instanceof Error ? err : new Error(String(err)));\n }\n });\n}\n\nasync function ensureDirectMcpAppInitialized(): Promise<boolean> {\n if (!isInChildFrame() || !isMcpAppBridgeEnabled()) return false;\n if (hasWrapperBridge()) return true;\n\n const openAiBridge = readOpenAiBridge();\n if (openAiBridge) {\n updateSnapshotFromOpenAiBridge(openAiBridge);\n return true;\n }\n\n if (!directMcpAppInit) {\n directMcpAppInit = (async () => {\n const result = await postJsonRpcRequest(\"ui/initialize\", {\n protocolVersion: DIRECT_MCP_APP_PROTOCOL_VERSION,\n appInfo: { name: \"Agent Native App\", version: \"1.0.0\" },\n appCapabilities: {\n availableDisplayModes: [\"inline\", \"fullscreen\", \"pip\"],\n },\n });\n updateSnapshotFromInitialize(result);\n postJsonRpcNotification(\"ui/notifications/initialized\", {});\n return true;\n })().catch(() => false);\n }\n\n return directMcpAppInit;\n}\n\nasync function waitForDirectMcpAppInitialized(): Promise<void> {\n const ok = await ensureDirectMcpAppInitialized();\n if (!ok) throw new Error(\"MCP Apps host bridge is not available.\");\n}\n\nasync function postDirectHostRequest(\n type:\n | typeof AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES.UPDATE_MODEL_CONTEXT\n | typeof AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES.OPEN_LINK\n | typeof AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES.REQUEST_DISPLAY_MODE,\n data: Record<string, unknown>,\n): Promise<boolean> {\n const openAiBridge = readOpenAiBridge();\n if (openAiBridge) {\n updateSnapshotFromOpenAiBridge(openAiBridge);\n if (\n type === AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES.UPDATE_MODEL_CONTEXT &&\n typeof openAiBridge.setWidgetState === \"function\"\n ) {\n openAiBridge.setWidgetState({\n ...objectValue(openAiBridge.widgetState),\n agentNativeModelContext: {\n ...(Array.isArray(data.content) ? { content: data.content } : {}),\n ...(data.structuredContent !== undefined\n ? { structuredContent: data.structuredContent }\n : {}),\n },\n });\n return true;\n }\n if (\n type === AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES.OPEN_LINK &&\n typeof openAiBridge.openExternal === \"function\" &&\n typeof data.url === \"string\"\n ) {\n await openAiBridge.openExternal({\n href: data.url,\n redirectUrl: false,\n });\n return true;\n }\n if (\n type === AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES.REQUEST_DISPLAY_MODE &&\n typeof openAiBridge.requestDisplayMode === \"function\" &&\n typeof data.mode === \"string\"\n ) {\n await openAiBridge.requestDisplayMode({ mode: data.mode });\n updateSnapshotFromOpenAiBridge(openAiBridge);\n return true;\n }\n }\n\n await waitForDirectMcpAppInitialized();\n const method =\n type === AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES.UPDATE_MODEL_CONTEXT\n ? \"ui/update-model-context\"\n : type === AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES.OPEN_LINK\n ? \"ui/open-link\"\n : \"ui/request-display-mode\";\n await postJsonRpcRequest(method, data);\n return true;\n}\n\nexport function sendMcpAppHostMessage(\n chat: McpAppHostChatMessage,\n): Promise<boolean> | false {\n if (!chat.message.trim() || !isInChildFrame() || !isMcpAppBridgeEnabled()) {\n return false;\n }\n\n if (hasWrapperBridge()) return postWrapperHostChat(chat);\n\n return (async () => {\n const openAiBridge = readOpenAiBridge();\n const context = chat.context?.trim() || null;\n const content = chat.content?.length\n ? chat.content\n : [{ type: \"text\", text: chat.message }];\n const contextContent = context\n ? [\n { type: \"text\", text: context },\n ...content.filter((part) => part && part.type !== \"text\"),\n ]\n : content.filter((part) => part && part.type !== \"text\");\n if (\n openAiBridge &&\n typeof openAiBridge.sendFollowUpMessage === \"function\"\n ) {\n updateSnapshotFromOpenAiBridge(openAiBridge);\n if (typeof openAiBridge.setWidgetState === \"function\") {\n openAiBridge.setWidgetState({\n ...objectValue(openAiBridge.widgetState),\n agentNativeChatContext: context,\n agentNativeModelContext: {\n content: contextContent,\n ...(chat.structuredContent !== undefined\n ? { structuredContent: chat.structuredContent }\n : {}),\n },\n });\n }\n await openAiBridge.sendFollowUpMessage({\n prompt: chat.message,\n scrollToBottom: true,\n });\n return true;\n }\n\n await waitForDirectMcpAppInitialized();\n try {\n await postJsonRpcRequest(\"ui/update-model-context\", {\n content: contextContent,\n ...(chat.structuredContent !== undefined\n ? { structuredContent: chat.structuredContent }\n : {}),\n });\n } catch {\n // Best effort: a host without model-context support should still receive\n // the visible chat message.\n }\n await postJsonRpcRequest(\"ui/message\", {\n role: \"user\",\n content,\n });\n return true;\n })().catch(() => false);\n}\n\nexport function getMcpAppHostContext(): McpAppHostContextSnapshot {\n ensureListener();\n const bridge = readOpenAiBridge();\n if (bridge) updateSnapshotFromOpenAiBridge(bridge);\n return snapshot;\n}\n\nexport function useMcpAppHostContext(): McpAppHostContextSnapshot {\n ensureListener();\n return useSyncExternalStore(\n (listener) => {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n () => snapshot,\n () => ({ context: null, capabilities: null, version: null }),\n );\n}\n\nexport function updateMcpAppModelContext(\n update: McpAppModelContextUpdate,\n): Promise<boolean> | false {\n return postHostRequest(\n AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES.UPDATE_MODEL_CONTEXT,\n {\n ...(Array.isArray(update.content) ? { content: update.content } : {}),\n ...(update.structuredContent !== undefined\n ? { structuredContent: update.structuredContent }\n : {}),\n },\n );\n}\n\nexport function openMcpAppHostLink(url: string): Promise<boolean> | false {\n if (!url) return false;\n return postHostRequest(AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES.OPEN_LINK, {\n url,\n });\n}\n\nexport function requestMcpAppDisplayMode(\n mode: McpAppDisplayMode,\n): Promise<boolean> | false {\n if (!mode) return false;\n return postHostRequest(\n AGENT_NATIVE_MCP_APP_HOST_MESSAGE_TYPES.REQUEST_DISPLAY_MODE,\n { mode },\n );\n}\n\nensureListener();\n\n/** Internal test helper. Do not use in app code. */\nexport function _resetMcpAppHostForTests(): void {\n for (const request of pending.values()) clearTimeout(request.timeout);\n for (const request of jsonRpcPending.values()) clearTimeout(request.timeout);\n pending.clear();\n jsonRpcPending.clear();\n directMcpAppInit = null;\n snapshot = { context: null, capabilities: null, version: null };\n listeners.clear();\n}\n\nif (isBrowserWindow()) {\n window.addEventListener(\n \"openai:set_globals\",\n () => {\n const bridge = readOpenAiBridge();\n if (bridge) updateSnapshotFromOpenAiBridge(bridge);\n },\n { passive: true },\n );\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"embed-app.d.ts","sourceRoot":"","sources":["../../src/mcp/embed-app.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAC;AAM/D,eAAO,MAAM,iCAAiC,mBAAmB,CAAC;AAElE,eAAO,MAAM,4BAA4B,MAAM,CAAC;AAChD,eAAO,MAAM,+BAA+B,QACkB,CAAC;AAE/D,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAUD,wBAAgB,QAAQ,CACtB,OAAO,GAAE,eAAoB,GAC5B,0BAA0B,
|
|
1
|
+
{"version":3,"file":"embed-app.d.ts","sourceRoot":"","sources":["../../src/mcp/embed-app.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAC;AAM/D,eAAO,MAAM,iCAAiC,mBAAmB,CAAC;AAElE,eAAO,MAAM,4BAA4B,MAAM,CAAC;AAChD,eAAO,MAAM,+BAA+B,QACkB,CAAC;AAE/D,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAUD,wBAAgB,QAAQ,CACtB,OAAO,GAAE,eAAoB,GAC5B,0BAA0B,CAwpD5B"}
|
package/dist/mcp/embed-app.js
CHANGED
|
@@ -1151,22 +1151,26 @@ export function embedApp(options = {}) {
|
|
|
1151
1151
|
const content = Array.isArray(chat.content) && chat.content.length
|
|
1152
1152
|
? chat.content
|
|
1153
1153
|
: [{ type: "text", text: message }];
|
|
1154
|
+
const structuredContent =
|
|
1155
|
+
chat && chat.structuredContent !== undefined
|
|
1156
|
+
? chat.structuredContent
|
|
1157
|
+
: undefined;
|
|
1154
1158
|
try {
|
|
1159
|
+
const contextContent = context
|
|
1160
|
+
? [{ type: "text", text: context }, ...content.filter((part) => part && part.type !== "text")]
|
|
1161
|
+
: content.filter((part) => part && part.type !== "text");
|
|
1162
|
+
const modelContext = {
|
|
1163
|
+
content: contextContent,
|
|
1164
|
+
...(structuredContent !== undefined ? { structuredContent } : {})
|
|
1165
|
+
};
|
|
1155
1166
|
if (openAiBridge && typeof openAiBridge.setWidgetState === "function") {
|
|
1156
|
-
const contextContent = context
|
|
1157
|
-
? [{ type: "text", text: context }, ...content.filter((part) => part && part.type !== "text")]
|
|
1158
|
-
: content.filter((part) => part && part.type !== "text");
|
|
1159
1167
|
openAiBridge.setWidgetState({
|
|
1160
1168
|
...objectValue(openAiBridge.widgetState),
|
|
1161
1169
|
agentNativeChatContext: context || null,
|
|
1162
|
-
agentNativeModelContext:
|
|
1170
|
+
agentNativeModelContext: modelContext
|
|
1163
1171
|
});
|
|
1164
1172
|
} else if (app && typeof app.updateModelContext === "function") {
|
|
1165
|
-
await app.updateModelContext(
|
|
1166
|
-
content: context
|
|
1167
|
-
? [{ type: "text", text: context }, ...content.filter((part) => part && part.type !== "text")]
|
|
1168
|
-
: content.filter((part) => part && part.type !== "text")
|
|
1169
|
-
});
|
|
1173
|
+
await app.updateModelContext(modelContext);
|
|
1170
1174
|
}
|
|
1171
1175
|
} catch (err) {
|
|
1172
1176
|
console.warn("[agent-native] MCP host rejected model context update", err);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"embed-app.js","sourceRoot":"","sources":["../../src/mcp/embed-app.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,+BAA+B,EAAE,MAAM,yBAAyB,CAAC;AAE1E,MAAM,cAAc,GAClB,mEAAmE,CAAC;AAEtE,MAAM,CAAC,MAAM,iCAAiC,GAAG,gBAAgB,CAAC;AAClE,MAAM,6BAA6B,GAAG,EAAE,CAAC;AACzC,MAAM,CAAC,MAAM,4BAA4B,GAAG,GAAG,CAAC;AAChD,MAAM,CAAC,MAAM,+BAA+B,GAC1C,4BAA4B,GAAG,6BAA6B,CAAC;AAgB/D,SAAS,IAAI,CAAC,KAAyB;IACrC,OAAO,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,QAAQ,CACtB,UAA2B,EAAE;IAE7B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,UAAU,CAAC;IAC1C,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,kBAAkB,CAAC;IAC9D,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,aAAa,CAAC;IACrD,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,IAAI,sBAAsB,CAAC;IACtE,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,KAAK,KAAK,CAAC;IACxD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CACrB,GAAG,EACH,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,MAAM,IAAI,4BAA4B,CAAC,CAC9D,CAAC;IACF,MAAM,cAAc,GAAG,MAAM,GAAG,6BAA6B,CAAC;IAC9D,MAAM,YAAY,GAAG;QACnB,iCAAiC;QACjC,GAAG,CAAC,OAAO,CAAC,YAAY,IAAI,EAAE,CAAC;KAChC,CAAC;IAEF,OAAO;QACL,KAAK;QACL,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACpE,IAAI,EAAE,GAAG,EAAE,CAAC;;;;;;8MAM8L,MAAM,uCAAuC,cAAc;;;;;;;;;;;;;;;;;;;;oBAoBrP,IAAI,CAAC,KAAK,CAAC;uBACR,IAAI,CAAC,WAAW,CAAC;qBACnB,IAAI,CAAC,SAAS,CAAC;qBACf,IAAI,CAAC,aAAa,CAAC;wBAChB,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG;;;;4CAIN,IAAI,CAAC,KAAK,CAAC;;;mDAGJ,IAAI,CAAC,SAAS,CAAC;;;;;;;;;;;;;;;;8BAgBpC,IAAI,CAAC,SAAS,CAAC,+BAA+B,CAAC;qCACxC,MAAM;2BAChB,6BAA6B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sCAsgDlB,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QA8C5C;QACJ,GAAG,EAAE;YACH,cAAc,EAAE;gBACd,gBAAgB;gBAChB,iCAAiC;gBACjC,GAAG,CAAC,OAAO,CAAC,cAAc,IAAI,EAAE,CAAC;gBACjC,GAAG,CAAC,OAAO,CAAC,YAAY,IAAI,EAAE,CAAC;aAChC;YACD,eAAe,EAAE;gBACf,gBAAgB;gBAChB,iCAAiC;gBACjC,GAAG,CAAC,OAAO,CAAC,eAAe,IAAI,EAAE,CAAC;gBAClC,GAAG,CAAC,OAAO,CAAC,YAAY,IAAI,EAAE,CAAC;aAChC;YACD,cAAc,EAAE;gBACd,iCAAiC;gBACjC,GAAG,CAAC,OAAO,CAAC,cAAc,IAAI,EAAE,CAAC;aAClC;YACD,YAAY;SACb;QACD,aAAa,EAAE,KAAK;KACrB,CAAC;AACJ,CAAC","sourcesContent":["import type { ActionMcpAppResourceConfig } from \"../action.js\";\nimport { MCP_APP_CHAT_BRIDGE_QUERY_PARAM } from \"../shared/embed-auth.js\";\n\nconst MCP_APP_IMPORT =\n \"https://esm.sh/@modelcontextprotocol/ext-apps@1.7.2/app-with-deps\";\n\nexport const MCP_APP_REQUEST_ORIGIN_CSP_SOURCE = \"$requestOrigin\";\nconst MCP_APP_WRAPPER_CHROME_HEIGHT = 44;\nexport const DEFAULT_MCP_APP_SHELL_HEIGHT = 560;\nexport const DEFAULT_MCP_APP_VIEWPORT_HEIGHT =\n DEFAULT_MCP_APP_SHELL_HEIGHT - MCP_APP_WRAPPER_CHROME_HEIGHT;\n\nexport interface EmbedAppOptions {\n title?: string;\n description?: string;\n iframeTitle?: string;\n openLabel?: string;\n embedByDefault?: boolean;\n startToolName?: string;\n connectDomains?: string[];\n resourceDomains?: string[];\n baseUriDomains?: string[];\n frameDomains?: string[];\n height?: number;\n}\n\nfunction attr(value: string | undefined): string {\n return String(value ?? \"\")\n .replace(/&/g, \"&\")\n .replace(/\"/g, \""\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\");\n}\n\nexport function embedApp(\n options: EmbedAppOptions = {},\n): ActionMcpAppResourceConfig {\n const title = options.title ?? \"Open app\";\n const iframeTitle = options.iframeTitle ?? \"Agent Native app\";\n const openLabel = options.openLabel ?? \"Open in app\";\n const startToolName = options.startToolName ?? \"create_embed_session\";\n const embedByDefault = options.embedByDefault !== false;\n const height = Math.max(\n 320,\n Math.min(900, options.height ?? DEFAULT_MCP_APP_SHELL_HEIGHT),\n );\n const viewportHeight = height - MCP_APP_WRAPPER_CHROME_HEIGHT;\n const frameDomains = [\n MCP_APP_REQUEST_ORIGIN_CSP_SOURCE,\n ...(options.frameDomains ?? []),\n ];\n\n return {\n title,\n ...(options.description ? { description: options.description } : {}),\n html: () => `<!doctype html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <style>\n :root { color-scheme: light dark; font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif; background: Canvas; color: CanvasText; --agent-native-shell-height: ${height}px; --agent-native-viewport-height: ${viewportHeight}px; }\n * { box-sizing: border-box; }\n body { margin: 0; }\n .shell { display: grid; gap: 8px; min-height: var(--agent-native-shell-height); padding: 0; }\n .bar { display: flex; align-items: center; justify-content: space-between; gap: 8px; min-height: 36px; padding: 6px 8px; border-bottom: 1px solid color-mix(in srgb, CanvasText 12%, Canvas); }\n .title { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12px; font-weight: 700; color: color-mix(in srgb, CanvasText 72%, Canvas); }\n .actions { display: flex; align-items: center; gap: 6px; }\n button { min-height: 28px; border: 1px solid color-mix(in srgb, CanvasText 14%, Canvas); border-radius: 7px; background: Canvas; color: CanvasText; cursor: pointer; font: inherit; font-size: 12px; font-weight: 700; padding: 0 9px; }\n button:disabled { opacity: .55; cursor: default; }\n .stage { position: relative; min-height: var(--agent-native-viewport-height); }\n iframe { display: block; width: 100%; height: var(--agent-native-viewport-height); border: 0; background: Canvas; }\n .message { display: grid; place-items: center; min-height: var(--agent-native-viewport-height); padding: 18px; color: color-mix(in srgb, CanvasText 62%, Canvas); font-size: 13px; line-height: 1.45; text-align: center; }\n .fallback { display: grid; align-content: center; justify-items: center; gap: 12px; min-height: var(--agent-native-viewport-height); padding: 24px; background: Canvas; color: CanvasText; text-align: center; }\n .fallback-title { max-width: 440px; font-size: 14px; font-weight: 700; }\n .fallback-copy { max-width: 520px; color: color-mix(in srgb, CanvasText 64%, Canvas); font-size: 13px; line-height: 1.45; }\n .fallback-actions { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 8px; }\n .fallback-url { max-width: min(560px, 100%); overflow-wrap: anywhere; color: color-mix(in srgb, CanvasText 76%, Canvas); font-size: 12px; }\n </style>\n</head>\n<body\n data-app-title=\"${attr(title)}\"\n data-iframe-title=\"${attr(iframeTitle)}\"\n data-open-label=\"${attr(openLabel)}\"\n data-start-tool=\"${attr(startToolName)}\"\n data-embed-default=\"${embedByDefault ? \"1\" : \"0\"}\"\n>\n <main class=\"shell\">\n <div class=\"bar\">\n <div class=\"title\" data-title-label>${attr(title)}</div>\n <div class=\"actions\">\n <button type=\"button\" data-display hidden disabled>Fullscreen</button>\n <button type=\"button\" data-open disabled>${attr(openLabel)}</button>\n </div>\n </div>\n <section class=\"stage\" data-stage>\n <div class=\"message\">Preparing app</div>\n </section>\n </main>\n <script>\n (async () => {\n const body = document.body;\n const stage = document.querySelector(\"[data-stage]\");\n const titleEl = document.querySelector(\"[data-title-label]\");\n const openButton = document.querySelector(\"[data-open]\");\n const displayButton = document.querySelector(\"[data-display]\");\n const startTool = body.dataset.startTool || \"create_embed_session\";\n const embedByDefault = body.dataset.embedDefault !== \"0\";\n const chatBridgeParam = ${JSON.stringify(MCP_APP_CHAT_BRIDGE_QUERY_PARAM)};\n const defaultIntrinsicHeight = ${height};\n const chromeHeight = ${MCP_APP_WRAPPER_CHROME_HEIGHT};\n const frameReadyMessageDelays = [0, 200, 500, 1500, 3000, 7000, 15000, 30000];\n const frameReadyTimeoutMs = 45000;\n const frameLoadTimeoutMs = 45000;\n const defaultOpenAiBridgeWaitMs = 200;\n const chatGptOpenAiBridgeWaitMs = 5000;\n const openAiBridgePollMs = 50;\n const nativeBridgeInitializeTimeoutMs = 5000;\n const nativeBridgeRequestTimeoutMs = 30000;\n const wrapperRequestTimeoutMs = 5000;\n let app = null;\n let openAiBridge = null;\n let wrapperRequestId = 0;\n const wrapperRequests = new Map();\n let toolInput = {};\n let toolResultData = {};\n let openUrl = \"\";\n let openStartUrl = \"\";\n let startedFor = \"\";\n let appFrame = null;\n let appFrameReady = false;\n let appFrameReadyTimer = null;\n let appFrameLoadTimer = null;\n let lastFrameSrc = \"\";\n\n function esc(value) {\n return String(value ?? \"\")\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\");\n }\n\n function parseJson(value, fallback) {\n if (value && typeof value === \"object\") return value;\n if (typeof value !== \"string\" || !value.trim()) return fallback;\n try { return JSON.parse(value); } catch { return fallback; }\n }\n\n function objectValue(value) {\n return value && typeof value === \"object\" && !Array.isArray(value)\n ? value\n : {};\n }\n\n function finiteNumber(value) {\n return typeof value === \"number\" && Number.isFinite(value) && value > 0\n ? value\n : null;\n }\n\n function contextMaxHeight(context) {\n if (!context || typeof context !== \"object\") return null;\n return finiteNumber(context.maxHeight) ||\n finiteNumber(context.containerDimensions && context.containerDimensions.maxHeight);\n }\n\n function visibleIntrinsicHeight() {\n const context = hostState().context || {};\n const hostMaxHeight = contextMaxHeight(context);\n if (hostMaxHeight) return Math.floor(hostMaxHeight);\n const viewportHeight = finiteNumber(window.visualViewport && window.visualViewport.height) ||\n finiteNumber(window.innerHeight);\n return Math.floor(viewportHeight || defaultIntrinsicHeight);\n }\n\n function applyIntrinsicHeight(nextHeight) {\n const boundedHeight = Math.min(\n defaultIntrinsicHeight,\n Math.floor(nextHeight || defaultIntrinsicHeight)\n );\n const height = Math.max(320, boundedHeight);\n const viewportHeight = Math.max(0, height - chromeHeight);\n document.documentElement.style.setProperty(\"--agent-native-shell-height\", height + \"px\");\n document.documentElement.style.setProperty(\"--agent-native-viewport-height\", viewportHeight + \"px\");\n if (appFrame) appFrame.style.height = viewportHeight + \"px\";\n return height;\n }\n\n function parseToolResult(params) {\n if (!params) return {};\n if (params.result && typeof params.result === \"object\") {\n return parseToolResult(params.result);\n }\n if (params.toolResult && typeof params.toolResult === \"object\") {\n return parseToolResult(params.toolResult);\n }\n if (params.structuredContent && typeof params.structuredContent === \"object\") {\n return params.structuredContent;\n }\n const parts = Array.isArray(params.content) ? params.content : [];\n const textPart = parts.find((part) => part && part.type === \"text\" && typeof part.text === \"string\");\n const text = textPart ? textPart.text : \"\";\n if (params.isError && typeof text === \"string\" && text.trim()) {\n return { error: text.trim() };\n }\n return parseJson(text, {});\n }\n\n function metadataRecord(value) {\n const meta = value && typeof value === \"object\" && !Array.isArray(value)\n ? value._meta\n : null;\n return meta && typeof meta === \"object\" && !Array.isArray(meta)\n ? meta\n : null;\n }\n\n function toolResultMeta(params) {\n if (!params || typeof params !== \"object\") return {};\n const direct = metadataRecord(params);\n if (direct) return direct;\n if (params.result && typeof params.result === \"object\") {\n return toolResultMeta(params.result);\n }\n if (params.toolResult && typeof params.toolResult === \"object\") {\n return toolResultMeta(params.toolResult);\n }\n return {};\n }\n\n function openLinkRecordFrom(value) {\n return value && typeof value === \"object\" && !Array.isArray(value)\n ? value\n : {};\n }\n\n function openLinkWebUrlFrom(value) {\n const record = openLinkRecordFrom(value);\n return typeof record.webUrl === \"string\" ? record.webUrl : \"\";\n }\n\n function firstNonEmbedStartUrl(values) {\n for (const value of values) {\n if (typeof value === \"string\" && value && !isEmbedStartUrl(value)) return value;\n }\n return \"\";\n }\n\n function firstEmbedStartUrl(values) {\n for (const value of values) {\n if (typeof value === \"string\" && value && isEmbedStartUrl(value)) {\n return withChatBridgeParam(value);\n }\n }\n return \"\";\n }\n\n function openLinkFrom(params, data) {\n const meta = toolResultMeta(params);\n const openLink = meta[\"agent-native/openLink\"];\n const metaUrl = openLinkWebUrlFrom(openLink);\n const record = data && typeof data === \"object\" ? data : {};\n const structuredOpenLinkUrl = openLinkWebUrlFrom(record.openLink);\n return firstNonEmbedStartUrl([\n record.embedTargetPath,\n record.deepLinkUrl,\n record.deepLink,\n record.openUrl,\n record.url,\n structuredOpenLinkUrl,\n metaUrl\n ]);\n }\n\n function embedStartUrlFrom(params, data) {\n const meta = toolResultMeta(params);\n const embedStart = meta[\"agent-native/embedStart\"];\n const embedStartRecord =\n embedStart && typeof embedStart === \"object\" && !Array.isArray(embedStart)\n ? embedStart\n : {};\n const openLink = meta[\"agent-native/openLink\"];\n const metaUrl = openLinkWebUrlFrom(openLink);\n const record = data && typeof data === \"object\" ? data : {};\n return firstEmbedStartUrl([\n embedStartRecord.startUrl,\n record.embedStartUrl,\n record.startUrl,\n record.url,\n openLinkWebUrlFrom(record.openLink),\n metaUrl\n ]);\n }\n\n function hostState() {\n if (openAiBridge) {\n return {\n context: {\n displayMode: openAiBridge.displayMode,\n availableDisplayModes: typeof openAiBridge.requestDisplayMode === \"function\"\n ? [\"inline\", \"fullscreen\", \"pip\"]\n : [],\n maxHeight: openAiBridge.maxHeight,\n locale: openAiBridge.locale,\n theme: openAiBridge.theme,\n view: openAiBridge.view\n },\n capabilities: { openai: true },\n version: openAiBridge.userAgent\n };\n }\n return {\n context: app && app.getHostContext ? app.getHostContext() : undefined,\n capabilities: app && app.getHostCapabilities ? app.getHostCapabilities() : undefined,\n version: app && app.getHostVersion ? app.getHostVersion() : undefined\n };\n }\n\n function sendToAppFrame(message) {\n if (!appFrame || !appFrame.contentWindow) return;\n try { appFrame.contentWindow.postMessage(message, \"*\"); } catch {}\n }\n\n function nextWrapperRequestId() {\n wrapperRequestId += 1;\n return \"mcp-wrapper-\" + Date.now() + \"-\" + wrapperRequestId;\n }\n\n function respondToWrapperRequest(requestId, result) {\n if (!requestId) return;\n sendToAppFrame({\n type: \"agentNative.mcpHost.response\",\n data: {\n requestId,\n ok: !!(result && result.ok),\n result: result || {}\n }\n });\n }\n\n function wrapperRpcRequest(method, params, timeoutMs) {\n return new Promise((resolve) => {\n const id = nextWrapperRequestId();\n const timer = window.setTimeout(() => {\n wrapperRequests.delete(id);\n resolve({ ok: false, error: \"MCP host bridge request timed out.\" });\n }, timeoutMs || wrapperRequestTimeoutMs);\n wrapperRequests.set(id, { resolve, timer });\n try {\n window.parent.postMessage(\n { jsonrpc: \"2.0\", id, method, params: params || {} },\n \"*\"\n );\n } catch (err) {\n wrapperRequests.delete(id);\n clearTimeout(timer);\n resolve({ ok: false, error: err && err.message ? err.message : String(err) });\n }\n });\n }\n\n function settleWrapperRpcResponse(message) {\n const id = typeof (message && message.id) === \"string\" ? message.id : \"\";\n if (!id) return false;\n const pending = wrapperRequests.get(id);\n if (!pending) return false;\n wrapperRequests.delete(id);\n clearTimeout(pending.timer);\n if (message.error) {\n pending.resolve({ ok: false, error: message.error });\n } else {\n pending.resolve({ ok: true, result: message.result });\n }\n return true;\n }\n\n function sendHostContext() {\n sendToAppFrame({ type: \"agentNative.mcpHostContext\", data: hostState() });\n }\n\n function sendFrameReadyMessages(frame) {\n const originPayload = { type: \"agentNative.frameOrigin\", origin: window.location.origin };\n frameReadyMessageDelays.forEach((delay) => {\n setTimeout(() => {\n try { frame.contentWindow && frame.contentWindow.postMessage(originPayload, \"*\"); } catch {}\n sendHostContext();\n }, delay);\n });\n }\n\n function withChatBridgeParam(value) {\n if (typeof value !== \"string\" || !value) return value;\n try {\n const base = \"http://agent-native.invalid\";\n const url = value.startsWith(\"/\") ? new URL(value, base) : new URL(value);\n url.searchParams.set(chatBridgeParam, \"1\");\n return value.startsWith(\"/\")\n ? url.pathname + url.search + url.hash\n : url.toString();\n } catch {\n return value;\n }\n }\n\n function embedSessionArgsFor(value) {\n const chrome = typeof toolInput.chrome === \"string\" ? toolInput.chrome : \"full\";\n return typeof value === \"string\" && value.startsWith(\"/\")\n ? { path: value, chrome }\n : { url: value, chrome };\n }\n\n function isEmbedStartUrl(value) {\n if (typeof value !== \"string\" || !value) return false;\n try {\n const url = new URL(value, window.location.href);\n return url.pathname.endsWith(\"/_agent-native/embed/start\");\n } catch {\n return false;\n }\n }\n\n function localPathFromUrl(url, includeToken) {\n const next = new URL(url.href);\n if (!includeToken) next.searchParams.delete(\"__an_embed_token\");\n return next.pathname + next.search + next.hash;\n }\n\n function rewriteRootRelativeHtmlUrls(html, appOrigin) {\n return String(html).replace(\n /\\\\b(src|href|poster|action)\\\\s*=\\\\s*([\"'])\\\\/(?!\\\\/)/gi,\n (_match, name, quote) => String(name) + \"=\" + quote + appOrigin + \"/\"\n );\n }\n\n function removeHtmlCspMeta(html) {\n return String(html).replace(\n /<meta\\\\s+[^>]*http-equiv\\\\s*=\\\\s*([\"'])?content-security-policy\\\\1?[^>]*>/gi,\n \"\"\n );\n }\n\n function embedConfigForAppUrl(appUrl) {\n const sanitizedTarget = localPathFromUrl(appUrl, false);\n return {\n origin: appUrl.origin,\n href: appUrl.href,\n baseHref: appUrl.origin + appUrl.pathname,\n target: sanitizedTarget,\n token: appUrl.searchParams.get(\"__an_embed_token\") || \"\",\n chatBridgeActive: appUrl.searchParams.get(chatBridgeParam) === \"1\",\n chatBridgeParam,\n embedTokenParam: \"__an_embed_token\",\n embedTargetHeader: \"x-agent-native-embed-target\"\n };\n }\n\n function installReactRefreshPreambleFallback() {\n window.__vite_plugin_react_preamble_installed__ = true;\n if (typeof window.$RefreshReg$ !== \"function\") {\n window.$RefreshReg$ = function() {};\n }\n if (typeof window.$RefreshSig$ !== \"function\") {\n window.$RefreshSig$ = function() {\n return function(type) {\n return type;\n };\n };\n }\n }\n\n function installExternalEmbedRuntime(config) {\n window.__AGENT_NATIVE_EXTERNAL_EMBED = config;\n installReactRefreshPreambleFallback();\n try {\n if (config.target) {\n window.history.replaceState(window.history.state, \"\", config.target);\n }\n } catch (_err) {}\n try {\n if (config.token) {\n sessionStorage.setItem(\"agent-native:embed-auth-token\", config.token);\n }\n if (config.chatBridgeActive && config.token) {\n sessionStorage.setItem(\"agent-native:mcp-chat-bridge\", config.token);\n }\n } catch (_err) {}\n if (window.__agentNativeExternalEmbedRuntimeInstalled) return;\n window.__agentNativeExternalEmbedRuntimeInstalled = true;\n function appOrigin() {\n try {\n return new URL(config.origin).origin;\n } catch (_err) {\n return \"\";\n }\n }\n function targetPath() {\n return config.target || location.pathname + location.search;\n }\n function rewrittenUrl(value, appendToken) {\n const origin = appOrigin();\n if (!origin) return null;\n let url;\n try {\n url = new URL(value, location.href);\n } catch (_err) {\n return null;\n }\n if (url.origin !== location.origin && url.origin !== origin) return null;\n if (url.origin !== origin) {\n const app = new URL(origin);\n url.protocol = app.protocol;\n url.host = app.host;\n }\n if (appendToken && config.token && url.pathname === \"/_agent-native/events\") {\n url.searchParams.set(config.embedTokenParam, config.token);\n }\n return url.toString();\n }\n function authHeaders(input, init) {\n const headers = new Headers(\n init && init.headers ? init.headers : input instanceof Request ? input.headers : undefined\n );\n if (config.token && !headers.has(\"Authorization\")) {\n headers.set(\"Authorization\", \"Bearer \" + config.token);\n }\n if (!headers.has(config.embedTargetHeader)) {\n headers.set(config.embedTargetHeader, targetPath());\n }\n return headers;\n }\n if (typeof fetch === \"function\") {\n const originalFetch = fetch.bind(window);\n window.fetch = function(input, init) {\n const raw = input instanceof Request ? input.url : String(input);\n const url = rewrittenUrl(raw, false);\n if (!url) return originalFetch(input, init);\n const nextInit = Object.assign({}, init || {}, {\n headers: authHeaders(input, init),\n credentials: \"omit\"\n });\n if (input instanceof Request) {\n return originalFetch(new Request(url, input), nextInit);\n }\n return originalFetch(url, nextInit);\n };\n }\n if (typeof XMLHttpRequest !== \"undefined\") {\n const originalOpen = XMLHttpRequest.prototype.open;\n const originalSend = XMLHttpRequest.prototype.send;\n XMLHttpRequest.prototype.open = function(method, url) {\n const rewritten = rewrittenUrl(url, false);\n this.__agentNativeExternalEmbed = !!rewritten;\n return originalOpen.call(\n this,\n method,\n rewritten || url,\n arguments.length > 2 ? arguments[2] : true,\n arguments[3],\n arguments[4]\n );\n };\n XMLHttpRequest.prototype.send = function(body) {\n if (this.__agentNativeExternalEmbed) {\n try {\n if (config.token) this.setRequestHeader(\"Authorization\", \"Bearer \" + config.token);\n this.setRequestHeader(config.embedTargetHeader, targetPath());\n } catch (_err) {}\n }\n return originalSend.call(this, body);\n };\n }\n if (typeof EventSource !== \"undefined\") {\n const OriginalEventSource = EventSource;\n window.EventSource = function(url, options) {\n return new OriginalEventSource(rewrittenUrl(url, true) || url, options);\n };\n window.EventSource.prototype = OriginalEventSource.prototype;\n }\n }\n\n function copyDocumentElementAttributes(source) {\n const target = document.documentElement;\n for (const attr of Array.from(target.attributes)) {\n target.removeAttribute(attr.name);\n }\n for (const attr of Array.from(source.attributes)) {\n target.setAttribute(attr.name, attr.value);\n }\n }\n\n function importChildren(source, target) {\n target.replaceChildren(\n ...Array.from(source.childNodes).map((node) => document.importNode(node, true))\n );\n }\n\n function isModuleScript(script) {\n return (script.getAttribute(\"type\") || \"\").trim().toLowerCase() === \"module\";\n }\n\n function isRunnableClassicScript(script) {\n const type = (script.getAttribute(\"type\") || \"\").trim().toLowerCase();\n return !type || type === \"text/javascript\" || type === \"application/javascript\";\n }\n\n function runClassicScript(script) {\n const next = document.createElement(\"script\");\n for (const attr of Array.from(script.attributes)) {\n if (attr.name === \"type\") continue;\n next.setAttribute(attr.name, attr.value);\n }\n if (script.src) {\n next.src = script.src;\n } else {\n next.textContent = script.textContent || \"\";\n }\n document.body.appendChild(next);\n next.remove();\n }\n\n function isEmbedRuntimeModulePath(pathname) {\n if (typeof pathname !== \"string\" || !pathname) return false;\n return /(?:^|\\\\/)(?:@(?:id|vite|fs|react-refresh)|app|node_modules|packages|src)(?:\\\\/|$)/.test(pathname) ||\n /(?:^|\\\\/)__x00__virtual:/.test(pathname) ||\n pathname.includes(\"virtual:react-router\");\n }\n\n function appendEmbedParamsToAppUrl(url, config) {\n if (isEmbedRuntimeModulePath(url.pathname)) return url;\n if (config.token) url.searchParams.set(config.embedTokenParam, config.token);\n if (config.chatBridgeActive) url.searchParams.set(config.chatBridgeParam, \"1\");\n return url;\n }\n\n function rootRelativeSpecifierToAppUrl(specifier, config) {\n if (typeof specifier !== \"string\" || !specifier.startsWith(\"/\") || specifier.startsWith(\"//\")) {\n return specifier;\n }\n try {\n const url = new URL(specifier, config.origin);\n return appendEmbedParamsToAppUrl(url, config).toString();\n } catch (_err) {\n return specifier;\n }\n }\n\n function rootRelativeSpecifiersToAbsolute(code, config) {\n return String(code).replace(/([\"'])\\\\/(?!\\\\/)([^\"']*)/g, (_match, quote, rest) => {\n return quote + rootRelativeSpecifierToAppUrl(\"/\" + rest, config);\n });\n }\n\n function relativeSpecifierToAppUrl(specifier, config, baseUrl) {\n if (typeof specifier !== \"string\" || !/^\\\\.\\\\.?\\\\//.test(specifier)) {\n return specifier;\n }\n try {\n const url = new URL(specifier, baseUrl || config.baseHref);\n if (url.origin === config.origin) {\n appendEmbedParamsToAppUrl(url, config);\n }\n return url.toString();\n } catch (_err) {\n return specifier;\n }\n }\n\n function relativeModuleSpecifiersToAbsolute(code, config, baseUrl) {\n return String(code)\n .replace(/(\\\\bimport\\\\s+(?:[^\"']+?\\\\s+from\\\\s+)?)([\"'])(\\\\.\\\\.?\\\\/[^\"']*)\\\\2/g, (_match, prefix, quote, specifier) => {\n return prefix + quote + relativeSpecifierToAppUrl(specifier, config, baseUrl) + quote;\n })\n .replace(/(\\\\bimport\\\\s*\\\\(\\\\s*)([\"'])(\\\\.\\\\.?\\\\/[^\"']*)\\\\2/g, (_match, prefix, quote, specifier) => {\n return prefix + quote + relativeSpecifierToAppUrl(specifier, config, baseUrl) + quote;\n })\n .replace(/(\\\\bexport\\\\s+[^\"']*?\\\\s+from\\\\s+)([\"'])(\\\\.\\\\.?\\\\/[^\"']*)\\\\2/g, (_match, prefix, quote, specifier) => {\n return prefix + quote + relativeSpecifierToAppUrl(specifier, config, baseUrl) + quote;\n });\n }\n\n function stripDevOnlyModuleImports(code) {\n return String(code).replace(\n /\\\\bimport\\\\s+(?:[^\"']+\\\\s+from\\\\s+)?[\"'][^\"']*(?:virtual:react-router\\\\/inject-hmr-runtime|__x00__virtual:react-router\\\\/inject-hmr-runtime)[^\"']*[\"']\\\\s*;?/g,\n \"\"\n );\n }\n\n function namedImportBindings(specifierList) {\n return String(specifierList)\n .split(\",\")\n .map((part) => {\n const trimmed = part.trim();\n if (!trimmed) return \"\";\n return trimmed.replace(\n /^([A-Za-z_$][\\\\w$]*)\\\\s+as\\\\s+([A-Za-z_$][\\\\w$]*)$/,\n \"$1: $2\"\n );\n })\n .filter(Boolean)\n .join(\", \");\n }\n\n function moduleCodeToClassicAsync(code, config, baseUrl) {\n return relativeModuleSpecifiersToAbsolute(\n rootRelativeSpecifiersToAbsolute(stripDevOnlyModuleImports(code), config),\n config,\n baseUrl\n )\n .replace(\n /\\\\bimport\\\\s+([A-Za-z_$][\\\\w$]*)\\\\s*,\\\\s*\\\\*\\\\s+as\\\\s+([A-Za-z_$][\\\\w$]*)\\\\s+from\\\\s+([\"'][^\"']+[\"'])\\\\s*;?/g,\n \"const $2 = await import($3); const $1 = $2.default;\"\n )\n .replace(\n /\\\\bimport\\\\s+([A-Za-z_$][\\\\w$]*)\\\\s*,\\\\s*\\\\{([\\\\s\\\\S]*?)\\\\}\\\\s*from\\\\s+([\"'][^\"']+[\"'])\\\\s*;?/g,\n (_match, defaultName, specifiers, source) =>\n \"const { default: \" +\n defaultName +\n (namedImportBindings(specifiers) ? \", \" + namedImportBindings(specifiers) : \"\") +\n \" } = await import(\" +\n source +\n \");\"\n )\n .replace(\n /\\\\bimport\\\\s+\\\\{([\\\\s\\\\S]*?)\\\\}\\\\s*from\\\\s+([\"'][^\"']+[\"'])\\\\s*;?/g,\n (_match, specifiers, source) =>\n \"const { \" + namedImportBindings(specifiers) + \" } = await import(\" + source + \");\"\n )\n .replace(\n /\\\\bimport\\\\s+\\\\*\\\\s+as\\\\s+([A-Za-z_$][\\\\w$]*)\\\\s+from\\\\s+([\"'][^\"']+[\"'])\\\\s*;?/g,\n \"const $1 = await import($2);\"\n )\n .replace(\n /\\\\bimport\\\\s+([A-Za-z_$][\\\\w$]*)\\\\s+from\\\\s+([\"'][^\"']+[\"'])\\\\s*;?/g,\n \"const { default: $1 } = await import($2);\"\n )\n .replace(/\\\\bimport\\\\s+([\"'][^\"']+[\"'])\\\\s*;?/g, \"await import($1);\")\n .replace(/\\\\bimport\\\\(([\"'][^\"']+[\"'])\\\\)\\\\s*;?/g, \"await import($1);\");\n }\n\n function scriptSourceUrl(script, config) {\n const raw = script.getAttribute(\"src\") || \"\";\n if (!raw) return \"\";\n try {\n const url = new URL(raw, config.baseHref);\n if (url.origin === config.origin) {\n appendEmbedParamsToAppUrl(url, config);\n }\n return url.toString();\n } catch (_err) {\n return raw;\n }\n }\n\n async function moduleScriptCode(script, config) {\n const src = scriptSourceUrl(script, config);\n if (!src) return script.textContent || \"\";\n const response = await fetch(src, {\n credentials: \"omit\",\n headers: { Accept: \"text/javascript, application/javascript, */*\" }\n });\n if (!response.ok) {\n throw new Error(\"Module script returned HTTP \" + response.status + \".\");\n }\n return await response.text();\n }\n\n async function runModuleScriptAsClassic(script, config) {\n const sourceUrl = scriptSourceUrl(script, config) || config.baseHref;\n const code = moduleCodeToClassicAsync(\n await moduleScriptCode(script, config),\n config,\n sourceUrl\n );\n const runner = document.createElement(\"script\");\n runner.textContent =\n \"(async()=>{\" +\n code +\n \"})().catch((err)=>{console.error('[agent-native] transplanted app module failed',err);document.body.setAttribute('data-agent-native-hydration-error',String(err&&err.message||err));});\";\n document.body.appendChild(runner);\n runner.remove();\n }\n\n async function mountTransplantedHtml(html, appUrl) {\n const config = embedConfigForAppUrl(appUrl);\n installExternalEmbedRuntime(config);\n const parsed = new DOMParser().parseFromString(\n rewriteRootRelativeHtmlUrls(removeHtmlCspMeta(html), appUrl.origin),\n \"text/html\"\n );\n const scripts = Array.from(parsed.querySelectorAll(\"script\"));\n copyDocumentElementAttributes(parsed.documentElement);\n importChildren(parsed.head, document.head);\n const base = document.createElement(\"base\");\n base.href = config.baseHref;\n document.head.prepend(base);\n importChildren(parsed.body, document.body);\n for (const script of scripts) {\n if (isRunnableClassicScript(script)) runClassicScript(script);\n }\n for (const script of scripts) {\n if (isModuleScript(script)) await runModuleScriptAsClassic(script, config);\n }\n }\n\n function absoluteUrl(value, base) {\n try {\n return new URL(value, base).toString();\n } catch {\n return \"\";\n }\n }\n\n async function resolveTransplantAppDocumentSource(src) {\n if (!isEmbedStartUrl(src)) {\n return { url: new URL(src), response: null };\n }\n const response = await fetch(src, {\n credentials: \"omit\",\n redirect: \"follow\",\n headers: {\n Accept: \"application/json\",\n \"X-Agent-Native-Embed-Transplant\": \"1\"\n }\n });\n const contentType = response.headers.get(\"content-type\") || \"\";\n if (response.ok && /\\\\bapplication\\\\/json\\\\b/i.test(contentType)) {\n const data = await response.json();\n const location = typeof data.location === \"string\" ? data.location : \"\";\n const url = absoluteUrl(location, src);\n if (url) return { url: new URL(withChatBridgeParam(url)), response: null };\n throw new Error(\"Embedded app did not return a launch URL.\");\n }\n return {\n url: new URL(response.url || src),\n response\n };\n }\n\n async function transplantAppDocument(src) {\n clearFrameReadyTimer();\n clearFrameLoadTimer();\n appFrame = null;\n lastFrameSrc = src;\n setMessage(\"Loading app\");\n const source = await resolveTransplantAppDocumentSource(src);\n const response = source.response || await fetch(source.url.href, {\n credentials: \"omit\",\n redirect: \"follow\",\n headers: { Accept: \"text/html\" }\n });\n if (!response.ok) {\n if (response.status === 401 && isEmbedStartUrl(src)) {\n refreshExpiredEmbedSession();\n return;\n }\n throw new Error(\"Embedded app returned HTTP \" + response.status + \".\");\n }\n const html = await response.text();\n const appUrl = source.url || new URL(response.url || src);\n try {\n window.history.replaceState(window.history.state, \"\", localPathFromUrl(appUrl, false));\n } catch {}\n await mountTransplantedHtml(html, appUrl);\n notifyHostHeightRepeatedly();\n }\n\n function wantsEmbed() {\n if (toolInput.embed === false || toolInput.embed === \"false\") return false;\n if (embedByDefault) return true;\n return toolInput.embed === true || toolInput.embed === \"true\";\n }\n\n function renderModeSource() {\n const input = objectValue(toolInput);\n const result = objectValue(toolResultData);\n return {\n mode: typeof input.embedMode === \"string\"\n ? input.embedMode\n : typeof input.renderMode === \"string\"\n ? input.renderMode\n : typeof result.embedMode === \"string\"\n ? result.embedMode\n : typeof result.renderMode === \"string\"\n ? result.renderMode\n : \"\",\n frame: typeof input.frame === \"string\"\n ? input.frame\n : typeof result.frame === \"string\"\n ? result.frame\n : \"\",\n nested: input.nested === true || result.nested === true\n };\n }\n\n function supportedDisplayMode(mode) {\n if (openAiBridge && typeof openAiBridge.requestDisplayMode === \"function\") {\n return mode === \"inline\" || mode === \"fullscreen\" || mode === \"pip\";\n }\n const modes = hostState().context && hostState().context.availableDisplayModes;\n return Array.isArray(modes) && modes.includes(mode);\n }\n\n async function requestHostDisplayMode(mode) {\n let result;\n if (openAiBridge && typeof openAiBridge.requestDisplayMode === \"function\") {\n result = await openAiBridge.requestDisplayMode({ mode });\n } else {\n if (!app || typeof app.requestDisplayMode !== \"function\") {\n throw new Error(\"Display mode changes are not available in this host.\");\n }\n result = await app.requestDisplayMode({ mode });\n }\n updateDisplayButton();\n sendHostContext();\n return result;\n }\n\n function updateDisplayButton() {\n const context = hostState().context || {};\n const nextMode = context.displayMode === \"fullscreen\" ? \"inline\" : \"fullscreen\";\n const supported = supportedDisplayMode(nextMode);\n displayButton.hidden = !supported;\n displayButton.disabled = !supported;\n displayButton.textContent = nextMode === \"fullscreen\" ? \"Fullscreen\" : \"Inline\";\n displayButton.onclick = () => {\n if (!supportedDisplayMode(nextMode)) return;\n void requestHostDisplayMode(nextMode).catch((err) => {\n console.warn(\"[agent-native] MCP host rejected display mode request\", err);\n });\n };\n }\n\n function setMessage(message) {\n stage.innerHTML = '<div class=\"message\">' + esc(message) + '</div>';\n }\n\n function clearFrameReadyTimer() {\n if (!appFrameReadyTimer) return;\n clearTimeout(appFrameReadyTimer);\n appFrameReadyTimer = null;\n }\n\n function clearFrameLoadTimer() {\n if (!appFrameLoadTimer) return;\n clearTimeout(appFrameLoadTimer);\n appFrameLoadTimer = null;\n }\n\n function startFrameReadyTimer(frame) {\n clearFrameReadyTimer();\n appFrameReadyTimer = setTimeout(() => {\n if (!appFrameReady && appFrame === frame) renderFrameFallback();\n }, frameReadyTimeoutMs);\n }\n\n function renderFrameFallback() {\n clearFrameReadyTimer();\n clearFrameLoadTimer();\n appFrame = null;\n const fallbackCopy = openUrl\n ? \"This chat host did not allow the embedded app frame to load inline. You can still open the same app route through the host or use the URL below.\"\n : \"This chat host did not allow the embedded app frame to load inline.\";\n stage.innerHTML =\n '<div class=\"fallback\">' +\n '<div class=\"fallback-title\">Open this app in its own tab</div>' +\n '<div class=\"fallback-copy\">' + esc(fallbackCopy) + '</div>' +\n '<div class=\"fallback-actions\">' +\n '<button type=\"button\" data-fallback-open>Open app</button>' +\n '<button type=\"button\" data-fallback-retry>Try inline again</button>' +\n '</div>' +\n (openUrl ? '<a class=\"fallback-url\" href=\"' + esc(openUrl) + '\" target=\"_blank\" rel=\"noreferrer\">' + esc(openUrl) + '</a>' : '') +\n '</div>';\n const fallbackOpen = stage.querySelector(\"[data-fallback-open]\");\n const fallbackRetry = stage.querySelector(\"[data-fallback-retry]\");\n if (fallbackOpen) {\n fallbackOpen.disabled = !openUrl;\n fallbackOpen.onclick = () => {\n if (openUrl) void openFallbackExternal();\n };\n }\n if (fallbackRetry) {\n fallbackRetry.disabled = !lastFrameSrc;\n fallbackRetry.onclick = () => {\n if (lastFrameSrc) renderFrame(lastFrameSrc);\n };\n }\n }\n\n async function openFallbackExternal() {\n if (!openUrl) return;\n let url = withChatBridgeParam(openUrl);\n try {\n if (url) {\n const result = await callEmbedSessionTool(embedSessionArgsFor(url));\n const data = parseToolResult(result);\n if (typeof data.startUrl === \"string\" && data.startUrl) {\n url = withChatBridgeParam(data.startUrl);\n }\n }\n } catch (err) {\n console.warn(\"[agent-native] MCP fallback could not mint a fresh app session\", err);\n }\n await openHostLink({ url });\n }\n\n function renderFrame(src) {\n clearFrameReadyTimer();\n clearFrameLoadTimer();\n const frame = document.createElement(\"iframe\");\n frame.title = body.dataset.iframeTitle || \"Agent Native app\";\n frame.src = src;\n frame.allow = \"clipboard-read; clipboard-write\";\n appFrame = frame;\n appFrameReady = false;\n lastFrameSrc = src;\n frame.addEventListener(\"load\", () => {\n if (appFrame !== frame) return;\n clearFrameLoadTimer();\n sendFrameReadyMessages(frame);\n startFrameReadyTimer(frame);\n });\n stage.replaceChildren(frame);\n notifyHostHeight();\n appFrameLoadTimer = setTimeout(() => {\n if (!appFrameReady && appFrame === frame) renderFrameFallback();\n }, frameLoadTimeoutMs);\n }\n\n function refreshExpiredEmbedSession() {\n clearFrameReadyTimer();\n clearFrameLoadTimer();\n appFrameReady = false;\n if (!openUrl) {\n renderFrameFallback();\n return;\n }\n openStartUrl = \"\";\n startedFor = \"\";\n lastFrameSrc = \"\";\n setMessage(\"Refreshing app session\");\n void launchEmbed();\n }\n\n function shouldSelfNavigateToApp() {\n const render = renderModeSource();\n const mode = render.mode;\n if (isClaudeMcpContentHost()) return true;\n if (mode === \"iframe\" || mode === \"nested\") return false;\n if (render.nested || render.frame === \"iframe\") return false;\n return true;\n }\n\n function shouldTransplantAppDocument() {\n const render = renderModeSource();\n const mode = render.mode;\n return (\n isClaudeMcpContentHost() ||\n isChatGptSandboxHost() ||\n mode === \"transplant\" ||\n render.frame === \"transplant\"\n );\n }\n\n function isClaudeMcpContentHost() {\n try {\n return /(^|\\\\.)claudemcpcontent\\\\.com$/i.test(window.location.hostname || \"\");\n } catch {\n return false;\n }\n }\n\n function isChatGptSandboxHost() {\n try {\n const host = window.location.hostname || \"\";\n const appParam = new URL(window.location.href).searchParams.get(\"app\");\n return /^[^.]+\\\\.web-sandbox\\\\.oaiusercontent\\\\.com$/i.test(host) || appParam === \"chatgpt\";\n } catch {\n return false;\n }\n }\n\n function shouldRenderControlledAppFrame() {\n return !!openAiBridge || isChatGptSandboxHost();\n }\n\n function navigateToAppFrame(src) {\n clearFrameReadyTimer();\n clearFrameLoadTimer();\n appFrame = null;\n lastFrameSrc = src;\n setMessage(\"Opening app\");\n try {\n window.location.replace(src);\n } catch (err) {\n console.warn(\"[agent-native] MCP app self-navigation failed\", err);\n renderFrameFallback();\n }\n }\n\n async function updateHostModelContext(data) {\n const params = {};\n if (Array.isArray(data && data.content)) params.content = data.content;\n if (data && data.structuredContent && typeof data.structuredContent === \"object\") {\n params.structuredContent = data.structuredContent;\n }\n if (openAiBridge && typeof openAiBridge.setWidgetState === \"function\") {\n openAiBridge.setWidgetState({\n ...objectValue(openAiBridge.widgetState),\n agentNativeModelContext: params\n });\n return { ok: true };\n }\n if (!app || typeof app.updateModelContext !== \"function\") return { ok: false };\n await app.updateModelContext(params);\n return { ok: true };\n }\n\n async function openHostLink(data) {\n const url = typeof (data && data.url) === \"string\" ? data.url : \"\";\n if (!url) return { isError: true };\n if (openAiBridge && typeof openAiBridge.openExternal === \"function\") {\n return await openAiBridge.openExternal({ href: url, redirectUrl: false });\n }\n if (app && typeof app.openLink === \"function\") {\n return await app.openLink({ url });\n }\n window.open(url, \"_blank\", \"noopener,noreferrer\");\n return { ok: true };\n }\n\n function notifyHostHeight() {\n const height = applyIntrinsicHeight(visibleIntrinsicHeight());\n if (!openAiBridge || typeof openAiBridge.notifyIntrinsicHeight !== \"function\") {\n if (app && typeof app.sendSizeChanged === \"function\") {\n try {\n app.sendSizeChanged({ height });\n } catch (err) {\n console.warn(\"[agent-native] MCP host rejected size update\", err);\n }\n }\n return;\n }\n try {\n openAiBridge.notifyIntrinsicHeight({ height });\n } catch (err) {\n console.warn(\"[agent-native] ChatGPT rejected intrinsic height update\", err);\n }\n }\n\n function respondToAppFrame(requestId, work) {\n if (!requestId) return;\n Promise.resolve(work)\n .then((result) => {\n sendToAppFrame({\n type: \"agentNative.mcpHost.response\",\n data: { requestId, ok: true, result }\n });\n })\n .catch((err) => {\n sendToAppFrame({\n type: \"agentNative.mcpHost.response\",\n data: {\n requestId,\n ok: false,\n error: err && err.message ? err.message : String(err)\n }\n });\n });\n }\n\n async function sendHostChat(chat) {\n const requestId = typeof (chat && chat.requestId) === \"string\" ? chat.requestId : \"\";\n if (!chat || chat.submit === false) return;\n const message = typeof chat.message === \"string\" ? chat.message : \"\";\n if (!message.trim()) return;\n const context = typeof chat.context === \"string\" ? chat.context.trim() : \"\";\n const content = Array.isArray(chat.content) && chat.content.length\n ? chat.content\n : [{ type: \"text\", text: message }];\n try {\n if (openAiBridge && typeof openAiBridge.setWidgetState === \"function\") {\n const contextContent = context\n ? [{ type: \"text\", text: context }, ...content.filter((part) => part && part.type !== \"text\")]\n : content.filter((part) => part && part.type !== \"text\");\n openAiBridge.setWidgetState({\n ...objectValue(openAiBridge.widgetState),\n agentNativeChatContext: context || null,\n agentNativeModelContext: { content: contextContent }\n });\n } else if (app && typeof app.updateModelContext === \"function\") {\n await app.updateModelContext({\n content: context\n ? [{ type: \"text\", text: context }, ...content.filter((part) => part && part.type !== \"text\")]\n : content.filter((part) => part && part.type !== \"text\")\n });\n }\n } catch (err) {\n console.warn(\"[agent-native] MCP host rejected model context update\", err);\n }\n try {\n if (openAiBridge && typeof openAiBridge.sendFollowUpMessage === \"function\") {\n await openAiBridge.sendFollowUpMessage({\n prompt: message,\n scrollToBottom: true\n });\n respondToWrapperRequest(requestId, { ok: true });\n return;\n }\n let result = null;\n if (app && typeof app.sendMessage === \"function\") {\n result = await app.sendMessage({\n role: \"user\",\n content\n });\n } else {\n result = await wrapperRpcRequest(\"ui/message\", {\n role: \"user\",\n content\n });\n }\n if (result && result.isError) {\n console.warn(\"[agent-native] MCP host rejected chat message\", result);\n respondToWrapperRequest(requestId, { ok: false, result });\n return;\n }\n if (result && result.ok === false) {\n console.warn(\"[agent-native] MCP host chat bridge failed\", result);\n respondToWrapperRequest(requestId, { ok: false, result });\n return;\n }\n respondToWrapperRequest(requestId, { ok: true, result });\n } catch (err) {\n console.warn(\"[agent-native] MCP host chat bridge failed\", err);\n respondToWrapperRequest(requestId, { ok: false, error: err && err.message ? err.message : String(err) });\n }\n }\n\n window.addEventListener(\"message\", (event) => {\n if (event.source !== window.parent) return;\n const message = event.data;\n if (!message || message.jsonrpc !== \"2.0\") return;\n settleWrapperRpcResponse(message);\n });\n\n window.addEventListener(\"message\", (event) => {\n if (!appFrame || event.source !== appFrame.contentWindow) return;\n if (!event.data) return;\n const data = event.data.data || {};\n if (event.data.type === \"agentNative.embeddedAppReady\") {\n appFrameReady = true;\n clearFrameLoadTimer();\n clearFrameReadyTimer();\n return;\n }\n if (event.data.type === \"agentNative.embedSessionExpired\") {\n refreshExpiredEmbedSession();\n return;\n }\n if (event.data.type === \"agentNative.submitChat\") {\n void sendHostChat(data);\n return;\n }\n if (event.data.type === \"agentNative.mcpHost.updateModelContext\") {\n respondToAppFrame(data.requestId, updateHostModelContext(data));\n return;\n }\n if (event.data.type === \"agentNative.mcpHost.openLink\") {\n respondToAppFrame(data.requestId, openHostLink(data));\n return;\n }\n if (event.data.type === \"agentNative.mcpHost.requestDisplayMode\") {\n respondToAppFrame(data.requestId, requestHostDisplayMode(data.mode));\n }\n });\n\n function notifyHostHeightSoon() {\n requestAnimationFrame(() => notifyHostHeight());\n }\n\n function notifyHostHeightRepeatedly() {\n notifyHostHeight();\n [0, 250, 1000, 2500].forEach((delay) => {\n setTimeout(() => notifyHostHeight(), delay);\n });\n }\n\n window.addEventListener(\"resize\", notifyHostHeightSoon, { passive: true });\n if (window.visualViewport) {\n window.visualViewport.addEventListener(\"resize\", notifyHostHeightSoon, { passive: true });\n }\n\n async function launchEmbed() {\n const launchUrl = openStartUrl || openUrl;\n if (!launchUrl) {\n setMessage(\"Open link was not available.\");\n return;\n }\n if (!wantsEmbed()) {\n setMessage(\"Ready to open.\");\n return;\n }\n if (startedFor === launchUrl) return;\n startedFor = launchUrl;\n setMessage(\"Loading app\");\n try {\n const selfNavigate = shouldSelfNavigateToApp();\n const embedUrl = withChatBridgeParam(launchUrl);\n if (selfNavigate && isEmbedStartUrl(embedUrl)) {\n if (shouldTransplantAppDocument()) {\n await transplantAppDocument(embedUrl);\n } else if (shouldRenderControlledAppFrame()) {\n renderFrame(embedUrl);\n } else {\n navigateToAppFrame(embedUrl);\n }\n return;\n }\n if (!selfNavigate && isEmbedStartUrl(embedUrl)) {\n renderFrame(embedUrl);\n return;\n }\n const result = await callEmbedSessionTool(embedSessionArgsFor(embedUrl));\n const data = parseToolResult(result);\n if (typeof data.startUrl !== \"string\" || !data.startUrl) {\n startedFor = \"\";\n setMessage(data.error || \"This app can be opened, but not embedded from this MCP server.\");\n return;\n }\n const startUrl = withChatBridgeParam(data.startUrl);\n if (selfNavigate) {\n if (shouldTransplantAppDocument()) {\n await transplantAppDocument(startUrl);\n } else if (shouldRenderControlledAppFrame()) {\n renderFrame(startUrl);\n } else {\n navigateToAppFrame(startUrl);\n }\n } else {\n renderFrame(startUrl);\n }\n } catch (err) {\n startedFor = \"\";\n setMessage(err && err.message ? err.message : \"Could not launch embedded app.\");\n }\n }\n\n async function callEmbedSessionTool(args) {\n if (openAiBridge && typeof openAiBridge.callTool === \"function\") {\n return await openAiBridge.callTool(startTool, args);\n }\n if (!app || typeof app.callServerTool !== \"function\") {\n throw new Error(\"Host tool calls are not available.\");\n }\n return await app.callServerTool({ name: startTool, arguments: args });\n }\n\n function updateHostOpenInAppUrl() {\n if (!openAiBridge || !openUrl || typeof openAiBridge.setOpenInAppUrl !== \"function\") {\n return;\n }\n try {\n openAiBridge.setOpenInAppUrl({ href: openUrl });\n } catch (err) {\n console.warn(\"[agent-native] ChatGPT rejected open-in-app URL\", err);\n }\n }\n\n function updateOpenButton() {\n const buttonUrl = openUrl;\n openButton.disabled = !buttonUrl;\n openButton.onclick = () => {\n if (buttonUrl) void openHostLink({ url: buttonUrl });\n };\n updateHostOpenInAppUrl();\n }\n\n function updateTitle(data) {\n const record = objectValue(data);\n const label = record.label || record.app || record.view || body.dataset.appTitle || \"App\";\n titleEl.textContent = String(label);\n }\n\n function readOpenAiBridge() {\n return window.openai && typeof window.openai === \"object\"\n ? window.openai\n : null;\n }\n\n function isChatGptHostHint() {\n try {\n if (new URLSearchParams(window.location.search).get(\"app\") === \"chatgpt\") return true;\n } catch (_err) {}\n try {\n return /chatgpt/i.test(String(navigator.userAgent || \"\"));\n } catch (_err) {\n return false;\n }\n }\n\n function openAiToolResultParams(bridge) {\n const params = {};\n if (bridge && bridge.toolOutput !== undefined) {\n if (bridge.toolOutput && typeof bridge.toolOutput === \"object\") {\n params.structuredContent = bridge.toolOutput;\n } else {\n params.content = [{ type: \"text\", text: String(bridge.toolOutput) }];\n }\n }\n if (bridge && bridge.toolResponseMetadata && typeof bridge.toolResponseMetadata === \"object\") {\n params._meta = bridge.toolResponseMetadata;\n }\n return params;\n }\n\n function syncOpenAiBridge(bridge) {\n if (!bridge) return false;\n openAiBridge = bridge;\n toolInput = objectValue(bridge.toolInput);\n const params = openAiToolResultParams(bridge);\n const data = parseToolResult(params);\n toolResultData = objectValue(data);\n openUrl = openLinkFrom(params, data);\n openStartUrl = embedStartUrlFrom(params, data);\n updateTitle(data);\n updateOpenButton();\n updateDisplayButton();\n notifyHostHeight();\n sendHostContext();\n if (openUrl || openStartUrl) {\n void launchEmbed();\n } else if (!appFrame) {\n setMessage(\"Waiting for app result\");\n }\n return true;\n }\n\n function waitForOpenAiBridge() {\n const existing = readOpenAiBridge();\n if (existing) return Promise.resolve(existing);\n return new Promise((resolve) => {\n let settled = false;\n let pollTimer = 0;\n const finish = (bridge) => {\n if (settled) return;\n settled = true;\n window.removeEventListener(\"openai:set_globals\", onGlobals);\n clearTimeout(timer);\n clearTimeout(pollTimer);\n resolve(bridge || readOpenAiBridge());\n };\n const poll = () => {\n const bridge = readOpenAiBridge();\n if (bridge) {\n finish(bridge);\n return;\n }\n pollTimer = window.setTimeout(poll, openAiBridgePollMs);\n };\n const onGlobals = () => finish(readOpenAiBridge());\n const timer = window.setTimeout(\n () => finish(null),\n isChatGptHostHint() ? chatGptOpenAiBridgeWaitMs : defaultOpenAiBridgeWaitMs\n );\n window.addEventListener(\"openai:set_globals\", onGlobals, { passive: true });\n pollTimer = window.setTimeout(poll, openAiBridgePollMs);\n });\n }\n\n window.addEventListener(\"openai:set_globals\", () => {\n const bridge = readOpenAiBridge();\n if (bridge && (!appFrame || openAiBridge)) syncOpenAiBridge(bridge);\n }, { passive: true });\n\n function createNativeMcpAppsBridge() {\n let rpcId = 0;\n let connected = false;\n let hostContext = {};\n const pendingRequests = new Map();\n\n function rpcNotify(method, params) {\n window.parent.postMessage({ jsonrpc: \"2.0\", method, params: params || {} }, \"*\");\n }\n\n function rpcRequest(method, params, timeoutMs) {\n return new Promise((resolve, reject) => {\n const id = ++rpcId;\n const timer = window.setTimeout(() => {\n pendingRequests.delete(id);\n reject(new Error(\"MCP Apps bridge request timed out: \" + method));\n }, timeoutMs || nativeBridgeRequestTimeoutMs);\n pendingRequests.set(id, { resolve, reject, timer });\n window.parent.postMessage(\n { jsonrpc: \"2.0\", id, method, params: params || {} },\n \"*\"\n );\n });\n }\n\n function settleRpcResponse(message) {\n const pending = pendingRequests.get(message.id);\n if (!pending) return true;\n pendingRequests.delete(message.id);\n clearTimeout(pending.timer);\n if (message.error) {\n const error = new Error(message.error.message || \"MCP Apps bridge request failed.\");\n error.data = message.error.data;\n pending.reject(error);\n return true;\n }\n pending.resolve(message.result);\n return true;\n }\n\n function notificationParams(message) {\n return message && typeof message.params === \"object\" && message.params\n ? message.params\n : {};\n }\n\n function toolInputNotificationParams(params) {\n if (params && typeof params.arguments === \"object\" && params.arguments) {\n return params;\n }\n if (params && typeof params.input === \"object\" && params.input) {\n return { arguments: params.input };\n }\n return { arguments: objectValue(params) };\n }\n\n const nativeApp = {\n ontoolinput: null,\n ontoolresult: null,\n onhostcontextchanged: null,\n getHostContext() {\n return hostContext.context || hostContext;\n },\n getHostCapabilities() {\n return hostContext.capabilities || { tools: true, messaging: true };\n },\n getHostVersion() {\n return hostContext.protocolVersion || \"mcp-apps-postmessage\";\n },\n async connect() {\n if (connected) return hostContext;\n connected = true;\n window.addEventListener(\"message\", onMessage, { passive: true });\n const result = await rpcRequest(\n \"ui/initialize\",\n {\n appInfo: { name: \"Agent Native Embed\", version: \"1.0.0\" },\n appCapabilities: {},\n protocolVersion: \"2026-01-26\"\n },\n nativeBridgeInitializeTimeoutMs\n );\n hostContext = objectValue(result);\n rpcNotify(\"ui/notifications/initialized\", {});\n if (typeof nativeApp.onhostcontextchanged === \"function\") {\n nativeApp.onhostcontextchanged(hostContext);\n }\n return hostContext;\n },\n async callServerTool(request) {\n const record = objectValue(request);\n return await rpcRequest(\"tools/call\", {\n name: record.name,\n arguments: objectValue(record.arguments)\n });\n },\n async updateModelContext(params) {\n return await rpcRequest(\"ui/update-model-context\", objectValue(params));\n },\n async openLink(params) {\n const url = typeof (params && params.url) === \"string\" ? params.url : \"\";\n if (!url) return { isError: true };\n window.open(url, \"_blank\", \"noopener,noreferrer\");\n return { ok: true };\n },\n async requestDisplayMode(params) {\n return await rpcRequest(\"ui/request-display-mode\", objectValue(params));\n },\n sendSizeChanged(params) {\n rpcNotify(\"ui/notifications/size-changed\", objectValue(params));\n },\n async sendMessage(params) {\n return await rpcRequest(\"ui/message\", objectValue(params));\n }\n };\n\n function onMessage(event) {\n if (event.source !== window.parent) return;\n const message = event.data;\n if (!message || message.jsonrpc !== \"2.0\") return;\n if (typeof message.id === \"number\" || typeof message.id === \"string\") {\n settleRpcResponse(message);\n return;\n }\n if (typeof message.method !== \"string\") return;\n const params = notificationParams(message);\n if (message.method === \"ui/notifications/tool-input\") {\n if (typeof nativeApp.ontoolinput === \"function\") {\n nativeApp.ontoolinput(toolInputNotificationParams(params));\n }\n return;\n }\n if (message.method === \"ui/notifications/tool-result\") {\n if (typeof nativeApp.ontoolresult === \"function\") {\n nativeApp.ontoolresult(params);\n }\n return;\n }\n if (\n message.method === \"ui/notifications/host-context\" ||\n message.method === \"ui/notifications/context\"\n ) {\n hostContext = objectValue(params);\n if (typeof nativeApp.onhostcontextchanged === \"function\") {\n nativeApp.onhostcontextchanged(hostContext);\n }\n }\n }\n\n return nativeApp;\n }\n\n async function startNativeMcpAppsBridge() {\n app = createNativeMcpAppsBridge();\n app.ontoolinput = (params) => {\n toolInput = params.arguments || {};\n };\n app.ontoolresult = (params) => {\n const data = parseToolResult(params);\n toolResultData = objectValue(data);\n openUrl = openLinkFrom(params, data);\n openStartUrl = embedStartUrlFrom(params, data);\n updateTitle(data);\n updateOpenButton();\n void launchEmbed();\n };\n app.onhostcontextchanged = () => {\n updateDisplayButton();\n notifyHostHeight();\n sendHostContext();\n };\n await app.connect();\n updateDisplayButton();\n notifyHostHeight();\n sendHostContext();\n }\n\n async function startMcpAppsBridge() {\n const { App } = await import(\"${MCP_APP_IMPORT}\");\n app = new App(\n { name: \"Agent Native Embed\", version: \"1.0.0\" },\n {},\n { autoResize: false }\n );\n app.ontoolinput = (params) => {\n toolInput = params.arguments || {};\n };\n app.ontoolresult = (params) => {\n const data = parseToolResult(params);\n toolResultData = objectValue(data);\n openUrl = openLinkFrom(params, data);\n openStartUrl = embedStartUrlFrom(params, data);\n updateTitle(data);\n updateOpenButton();\n void launchEmbed();\n };\n app.onhostcontextchanged = () => {\n updateDisplayButton();\n notifyHostHeight();\n sendHostContext();\n };\n await app.connect();\n updateDisplayButton();\n notifyHostHeight();\n sendHostContext();\n }\n\n try {\n const initialOpenAiBridge = await waitForOpenAiBridge();\n if (!syncOpenAiBridge(initialOpenAiBridge)) {\n try {\n await startNativeMcpAppsBridge();\n } catch (nativeErr) {\n console.warn(\"[agent-native] native MCP Apps bridge failed\", nativeErr);\n await startMcpAppsBridge();\n }\n }\n } catch (err) {\n console.error(\"[agent-native] MCP app shell failed\", err);\n setMessage(err && err.message ? err.message : \"Could not initialize app.\");\n }\n })();\n </script>\n</body>\n</html>`,\n csp: {\n connectDomains: [\n \"https://esm.sh\",\n MCP_APP_REQUEST_ORIGIN_CSP_SOURCE,\n ...(options.connectDomains ?? []),\n ...(options.frameDomains ?? []),\n ],\n resourceDomains: [\n \"https://esm.sh\",\n MCP_APP_REQUEST_ORIGIN_CSP_SOURCE,\n ...(options.resourceDomains ?? []),\n ...(options.frameDomains ?? []),\n ],\n baseUriDomains: [\n MCP_APP_REQUEST_ORIGIN_CSP_SOURCE,\n ...(options.baseUriDomains ?? []),\n ],\n frameDomains,\n },\n prefersBorder: false,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"embed-app.js","sourceRoot":"","sources":["../../src/mcp/embed-app.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,+BAA+B,EAAE,MAAM,yBAAyB,CAAC;AAE1E,MAAM,cAAc,GAClB,mEAAmE,CAAC;AAEtE,MAAM,CAAC,MAAM,iCAAiC,GAAG,gBAAgB,CAAC;AAClE,MAAM,6BAA6B,GAAG,EAAE,CAAC;AACzC,MAAM,CAAC,MAAM,4BAA4B,GAAG,GAAG,CAAC;AAChD,MAAM,CAAC,MAAM,+BAA+B,GAC1C,4BAA4B,GAAG,6BAA6B,CAAC;AAgB/D,SAAS,IAAI,CAAC,KAAyB;IACrC,OAAO,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,QAAQ,CACtB,UAA2B,EAAE;IAE7B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,UAAU,CAAC;IAC1C,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,kBAAkB,CAAC;IAC9D,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,aAAa,CAAC;IACrD,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,IAAI,sBAAsB,CAAC;IACtE,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,KAAK,KAAK,CAAC;IACxD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CACrB,GAAG,EACH,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,MAAM,IAAI,4BAA4B,CAAC,CAC9D,CAAC;IACF,MAAM,cAAc,GAAG,MAAM,GAAG,6BAA6B,CAAC;IAC9D,MAAM,YAAY,GAAG;QACnB,iCAAiC;QACjC,GAAG,CAAC,OAAO,CAAC,YAAY,IAAI,EAAE,CAAC;KAChC,CAAC;IAEF,OAAO;QACL,KAAK;QACL,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACpE,IAAI,EAAE,GAAG,EAAE,CAAC;;;;;;8MAM8L,MAAM,uCAAuC,cAAc;;;;;;;;;;;;;;;;;;;;oBAoBrP,IAAI,CAAC,KAAK,CAAC;uBACR,IAAI,CAAC,WAAW,CAAC;qBACnB,IAAI,CAAC,SAAS,CAAC;qBACf,IAAI,CAAC,aAAa,CAAC;wBAChB,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG;;;;4CAIN,IAAI,CAAC,KAAK,CAAC;;;mDAGJ,IAAI,CAAC,SAAS,CAAC;;;;;;;;;;;;;;;;8BAgBpC,IAAI,CAAC,SAAS,CAAC,+BAA+B,CAAC;qCACxC,MAAM;2BAChB,6BAA6B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sCA0gDlB,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QA8C5C;QACJ,GAAG,EAAE;YACH,cAAc,EAAE;gBACd,gBAAgB;gBAChB,iCAAiC;gBACjC,GAAG,CAAC,OAAO,CAAC,cAAc,IAAI,EAAE,CAAC;gBACjC,GAAG,CAAC,OAAO,CAAC,YAAY,IAAI,EAAE,CAAC;aAChC;YACD,eAAe,EAAE;gBACf,gBAAgB;gBAChB,iCAAiC;gBACjC,GAAG,CAAC,OAAO,CAAC,eAAe,IAAI,EAAE,CAAC;gBAClC,GAAG,CAAC,OAAO,CAAC,YAAY,IAAI,EAAE,CAAC;aAChC;YACD,cAAc,EAAE;gBACd,iCAAiC;gBACjC,GAAG,CAAC,OAAO,CAAC,cAAc,IAAI,EAAE,CAAC;aAClC;YACD,YAAY;SACb;QACD,aAAa,EAAE,KAAK;KACrB,CAAC;AACJ,CAAC","sourcesContent":["import type { ActionMcpAppResourceConfig } from \"../action.js\";\nimport { MCP_APP_CHAT_BRIDGE_QUERY_PARAM } from \"../shared/embed-auth.js\";\n\nconst MCP_APP_IMPORT =\n \"https://esm.sh/@modelcontextprotocol/ext-apps@1.7.2/app-with-deps\";\n\nexport const MCP_APP_REQUEST_ORIGIN_CSP_SOURCE = \"$requestOrigin\";\nconst MCP_APP_WRAPPER_CHROME_HEIGHT = 44;\nexport const DEFAULT_MCP_APP_SHELL_HEIGHT = 560;\nexport const DEFAULT_MCP_APP_VIEWPORT_HEIGHT =\n DEFAULT_MCP_APP_SHELL_HEIGHT - MCP_APP_WRAPPER_CHROME_HEIGHT;\n\nexport interface EmbedAppOptions {\n title?: string;\n description?: string;\n iframeTitle?: string;\n openLabel?: string;\n embedByDefault?: boolean;\n startToolName?: string;\n connectDomains?: string[];\n resourceDomains?: string[];\n baseUriDomains?: string[];\n frameDomains?: string[];\n height?: number;\n}\n\nfunction attr(value: string | undefined): string {\n return String(value ?? \"\")\n .replace(/&/g, \"&\")\n .replace(/\"/g, \""\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\");\n}\n\nexport function embedApp(\n options: EmbedAppOptions = {},\n): ActionMcpAppResourceConfig {\n const title = options.title ?? \"Open app\";\n const iframeTitle = options.iframeTitle ?? \"Agent Native app\";\n const openLabel = options.openLabel ?? \"Open in app\";\n const startToolName = options.startToolName ?? \"create_embed_session\";\n const embedByDefault = options.embedByDefault !== false;\n const height = Math.max(\n 320,\n Math.min(900, options.height ?? DEFAULT_MCP_APP_SHELL_HEIGHT),\n );\n const viewportHeight = height - MCP_APP_WRAPPER_CHROME_HEIGHT;\n const frameDomains = [\n MCP_APP_REQUEST_ORIGIN_CSP_SOURCE,\n ...(options.frameDomains ?? []),\n ];\n\n return {\n title,\n ...(options.description ? { description: options.description } : {}),\n html: () => `<!doctype html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <style>\n :root { color-scheme: light dark; font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif; background: Canvas; color: CanvasText; --agent-native-shell-height: ${height}px; --agent-native-viewport-height: ${viewportHeight}px; }\n * { box-sizing: border-box; }\n body { margin: 0; }\n .shell { display: grid; gap: 8px; min-height: var(--agent-native-shell-height); padding: 0; }\n .bar { display: flex; align-items: center; justify-content: space-between; gap: 8px; min-height: 36px; padding: 6px 8px; border-bottom: 1px solid color-mix(in srgb, CanvasText 12%, Canvas); }\n .title { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12px; font-weight: 700; color: color-mix(in srgb, CanvasText 72%, Canvas); }\n .actions { display: flex; align-items: center; gap: 6px; }\n button { min-height: 28px; border: 1px solid color-mix(in srgb, CanvasText 14%, Canvas); border-radius: 7px; background: Canvas; color: CanvasText; cursor: pointer; font: inherit; font-size: 12px; font-weight: 700; padding: 0 9px; }\n button:disabled { opacity: .55; cursor: default; }\n .stage { position: relative; min-height: var(--agent-native-viewport-height); }\n iframe { display: block; width: 100%; height: var(--agent-native-viewport-height); border: 0; background: Canvas; }\n .message { display: grid; place-items: center; min-height: var(--agent-native-viewport-height); padding: 18px; color: color-mix(in srgb, CanvasText 62%, Canvas); font-size: 13px; line-height: 1.45; text-align: center; }\n .fallback { display: grid; align-content: center; justify-items: center; gap: 12px; min-height: var(--agent-native-viewport-height); padding: 24px; background: Canvas; color: CanvasText; text-align: center; }\n .fallback-title { max-width: 440px; font-size: 14px; font-weight: 700; }\n .fallback-copy { max-width: 520px; color: color-mix(in srgb, CanvasText 64%, Canvas); font-size: 13px; line-height: 1.45; }\n .fallback-actions { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 8px; }\n .fallback-url { max-width: min(560px, 100%); overflow-wrap: anywhere; color: color-mix(in srgb, CanvasText 76%, Canvas); font-size: 12px; }\n </style>\n</head>\n<body\n data-app-title=\"${attr(title)}\"\n data-iframe-title=\"${attr(iframeTitle)}\"\n data-open-label=\"${attr(openLabel)}\"\n data-start-tool=\"${attr(startToolName)}\"\n data-embed-default=\"${embedByDefault ? \"1\" : \"0\"}\"\n>\n <main class=\"shell\">\n <div class=\"bar\">\n <div class=\"title\" data-title-label>${attr(title)}</div>\n <div class=\"actions\">\n <button type=\"button\" data-display hidden disabled>Fullscreen</button>\n <button type=\"button\" data-open disabled>${attr(openLabel)}</button>\n </div>\n </div>\n <section class=\"stage\" data-stage>\n <div class=\"message\">Preparing app</div>\n </section>\n </main>\n <script>\n (async () => {\n const body = document.body;\n const stage = document.querySelector(\"[data-stage]\");\n const titleEl = document.querySelector(\"[data-title-label]\");\n const openButton = document.querySelector(\"[data-open]\");\n const displayButton = document.querySelector(\"[data-display]\");\n const startTool = body.dataset.startTool || \"create_embed_session\";\n const embedByDefault = body.dataset.embedDefault !== \"0\";\n const chatBridgeParam = ${JSON.stringify(MCP_APP_CHAT_BRIDGE_QUERY_PARAM)};\n const defaultIntrinsicHeight = ${height};\n const chromeHeight = ${MCP_APP_WRAPPER_CHROME_HEIGHT};\n const frameReadyMessageDelays = [0, 200, 500, 1500, 3000, 7000, 15000, 30000];\n const frameReadyTimeoutMs = 45000;\n const frameLoadTimeoutMs = 45000;\n const defaultOpenAiBridgeWaitMs = 200;\n const chatGptOpenAiBridgeWaitMs = 5000;\n const openAiBridgePollMs = 50;\n const nativeBridgeInitializeTimeoutMs = 5000;\n const nativeBridgeRequestTimeoutMs = 30000;\n const wrapperRequestTimeoutMs = 5000;\n let app = null;\n let openAiBridge = null;\n let wrapperRequestId = 0;\n const wrapperRequests = new Map();\n let toolInput = {};\n let toolResultData = {};\n let openUrl = \"\";\n let openStartUrl = \"\";\n let startedFor = \"\";\n let appFrame = null;\n let appFrameReady = false;\n let appFrameReadyTimer = null;\n let appFrameLoadTimer = null;\n let lastFrameSrc = \"\";\n\n function esc(value) {\n return String(value ?? \"\")\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\");\n }\n\n function parseJson(value, fallback) {\n if (value && typeof value === \"object\") return value;\n if (typeof value !== \"string\" || !value.trim()) return fallback;\n try { return JSON.parse(value); } catch { return fallback; }\n }\n\n function objectValue(value) {\n return value && typeof value === \"object\" && !Array.isArray(value)\n ? value\n : {};\n }\n\n function finiteNumber(value) {\n return typeof value === \"number\" && Number.isFinite(value) && value > 0\n ? value\n : null;\n }\n\n function contextMaxHeight(context) {\n if (!context || typeof context !== \"object\") return null;\n return finiteNumber(context.maxHeight) ||\n finiteNumber(context.containerDimensions && context.containerDimensions.maxHeight);\n }\n\n function visibleIntrinsicHeight() {\n const context = hostState().context || {};\n const hostMaxHeight = contextMaxHeight(context);\n if (hostMaxHeight) return Math.floor(hostMaxHeight);\n const viewportHeight = finiteNumber(window.visualViewport && window.visualViewport.height) ||\n finiteNumber(window.innerHeight);\n return Math.floor(viewportHeight || defaultIntrinsicHeight);\n }\n\n function applyIntrinsicHeight(nextHeight) {\n const boundedHeight = Math.min(\n defaultIntrinsicHeight,\n Math.floor(nextHeight || defaultIntrinsicHeight)\n );\n const height = Math.max(320, boundedHeight);\n const viewportHeight = Math.max(0, height - chromeHeight);\n document.documentElement.style.setProperty(\"--agent-native-shell-height\", height + \"px\");\n document.documentElement.style.setProperty(\"--agent-native-viewport-height\", viewportHeight + \"px\");\n if (appFrame) appFrame.style.height = viewportHeight + \"px\";\n return height;\n }\n\n function parseToolResult(params) {\n if (!params) return {};\n if (params.result && typeof params.result === \"object\") {\n return parseToolResult(params.result);\n }\n if (params.toolResult && typeof params.toolResult === \"object\") {\n return parseToolResult(params.toolResult);\n }\n if (params.structuredContent && typeof params.structuredContent === \"object\") {\n return params.structuredContent;\n }\n const parts = Array.isArray(params.content) ? params.content : [];\n const textPart = parts.find((part) => part && part.type === \"text\" && typeof part.text === \"string\");\n const text = textPart ? textPart.text : \"\";\n if (params.isError && typeof text === \"string\" && text.trim()) {\n return { error: text.trim() };\n }\n return parseJson(text, {});\n }\n\n function metadataRecord(value) {\n const meta = value && typeof value === \"object\" && !Array.isArray(value)\n ? value._meta\n : null;\n return meta && typeof meta === \"object\" && !Array.isArray(meta)\n ? meta\n : null;\n }\n\n function toolResultMeta(params) {\n if (!params || typeof params !== \"object\") return {};\n const direct = metadataRecord(params);\n if (direct) return direct;\n if (params.result && typeof params.result === \"object\") {\n return toolResultMeta(params.result);\n }\n if (params.toolResult && typeof params.toolResult === \"object\") {\n return toolResultMeta(params.toolResult);\n }\n return {};\n }\n\n function openLinkRecordFrom(value) {\n return value && typeof value === \"object\" && !Array.isArray(value)\n ? value\n : {};\n }\n\n function openLinkWebUrlFrom(value) {\n const record = openLinkRecordFrom(value);\n return typeof record.webUrl === \"string\" ? record.webUrl : \"\";\n }\n\n function firstNonEmbedStartUrl(values) {\n for (const value of values) {\n if (typeof value === \"string\" && value && !isEmbedStartUrl(value)) return value;\n }\n return \"\";\n }\n\n function firstEmbedStartUrl(values) {\n for (const value of values) {\n if (typeof value === \"string\" && value && isEmbedStartUrl(value)) {\n return withChatBridgeParam(value);\n }\n }\n return \"\";\n }\n\n function openLinkFrom(params, data) {\n const meta = toolResultMeta(params);\n const openLink = meta[\"agent-native/openLink\"];\n const metaUrl = openLinkWebUrlFrom(openLink);\n const record = data && typeof data === \"object\" ? data : {};\n const structuredOpenLinkUrl = openLinkWebUrlFrom(record.openLink);\n return firstNonEmbedStartUrl([\n record.embedTargetPath,\n record.deepLinkUrl,\n record.deepLink,\n record.openUrl,\n record.url,\n structuredOpenLinkUrl,\n metaUrl\n ]);\n }\n\n function embedStartUrlFrom(params, data) {\n const meta = toolResultMeta(params);\n const embedStart = meta[\"agent-native/embedStart\"];\n const embedStartRecord =\n embedStart && typeof embedStart === \"object\" && !Array.isArray(embedStart)\n ? embedStart\n : {};\n const openLink = meta[\"agent-native/openLink\"];\n const metaUrl = openLinkWebUrlFrom(openLink);\n const record = data && typeof data === \"object\" ? data : {};\n return firstEmbedStartUrl([\n embedStartRecord.startUrl,\n record.embedStartUrl,\n record.startUrl,\n record.url,\n openLinkWebUrlFrom(record.openLink),\n metaUrl\n ]);\n }\n\n function hostState() {\n if (openAiBridge) {\n return {\n context: {\n displayMode: openAiBridge.displayMode,\n availableDisplayModes: typeof openAiBridge.requestDisplayMode === \"function\"\n ? [\"inline\", \"fullscreen\", \"pip\"]\n : [],\n maxHeight: openAiBridge.maxHeight,\n locale: openAiBridge.locale,\n theme: openAiBridge.theme,\n view: openAiBridge.view\n },\n capabilities: { openai: true },\n version: openAiBridge.userAgent\n };\n }\n return {\n context: app && app.getHostContext ? app.getHostContext() : undefined,\n capabilities: app && app.getHostCapabilities ? app.getHostCapabilities() : undefined,\n version: app && app.getHostVersion ? app.getHostVersion() : undefined\n };\n }\n\n function sendToAppFrame(message) {\n if (!appFrame || !appFrame.contentWindow) return;\n try { appFrame.contentWindow.postMessage(message, \"*\"); } catch {}\n }\n\n function nextWrapperRequestId() {\n wrapperRequestId += 1;\n return \"mcp-wrapper-\" + Date.now() + \"-\" + wrapperRequestId;\n }\n\n function respondToWrapperRequest(requestId, result) {\n if (!requestId) return;\n sendToAppFrame({\n type: \"agentNative.mcpHost.response\",\n data: {\n requestId,\n ok: !!(result && result.ok),\n result: result || {}\n }\n });\n }\n\n function wrapperRpcRequest(method, params, timeoutMs) {\n return new Promise((resolve) => {\n const id = nextWrapperRequestId();\n const timer = window.setTimeout(() => {\n wrapperRequests.delete(id);\n resolve({ ok: false, error: \"MCP host bridge request timed out.\" });\n }, timeoutMs || wrapperRequestTimeoutMs);\n wrapperRequests.set(id, { resolve, timer });\n try {\n window.parent.postMessage(\n { jsonrpc: \"2.0\", id, method, params: params || {} },\n \"*\"\n );\n } catch (err) {\n wrapperRequests.delete(id);\n clearTimeout(timer);\n resolve({ ok: false, error: err && err.message ? err.message : String(err) });\n }\n });\n }\n\n function settleWrapperRpcResponse(message) {\n const id = typeof (message && message.id) === \"string\" ? message.id : \"\";\n if (!id) return false;\n const pending = wrapperRequests.get(id);\n if (!pending) return false;\n wrapperRequests.delete(id);\n clearTimeout(pending.timer);\n if (message.error) {\n pending.resolve({ ok: false, error: message.error });\n } else {\n pending.resolve({ ok: true, result: message.result });\n }\n return true;\n }\n\n function sendHostContext() {\n sendToAppFrame({ type: \"agentNative.mcpHostContext\", data: hostState() });\n }\n\n function sendFrameReadyMessages(frame) {\n const originPayload = { type: \"agentNative.frameOrigin\", origin: window.location.origin };\n frameReadyMessageDelays.forEach((delay) => {\n setTimeout(() => {\n try { frame.contentWindow && frame.contentWindow.postMessage(originPayload, \"*\"); } catch {}\n sendHostContext();\n }, delay);\n });\n }\n\n function withChatBridgeParam(value) {\n if (typeof value !== \"string\" || !value) return value;\n try {\n const base = \"http://agent-native.invalid\";\n const url = value.startsWith(\"/\") ? new URL(value, base) : new URL(value);\n url.searchParams.set(chatBridgeParam, \"1\");\n return value.startsWith(\"/\")\n ? url.pathname + url.search + url.hash\n : url.toString();\n } catch {\n return value;\n }\n }\n\n function embedSessionArgsFor(value) {\n const chrome = typeof toolInput.chrome === \"string\" ? toolInput.chrome : \"full\";\n return typeof value === \"string\" && value.startsWith(\"/\")\n ? { path: value, chrome }\n : { url: value, chrome };\n }\n\n function isEmbedStartUrl(value) {\n if (typeof value !== \"string\" || !value) return false;\n try {\n const url = new URL(value, window.location.href);\n return url.pathname.endsWith(\"/_agent-native/embed/start\");\n } catch {\n return false;\n }\n }\n\n function localPathFromUrl(url, includeToken) {\n const next = new URL(url.href);\n if (!includeToken) next.searchParams.delete(\"__an_embed_token\");\n return next.pathname + next.search + next.hash;\n }\n\n function rewriteRootRelativeHtmlUrls(html, appOrigin) {\n return String(html).replace(\n /\\\\b(src|href|poster|action)\\\\s*=\\\\s*([\"'])\\\\/(?!\\\\/)/gi,\n (_match, name, quote) => String(name) + \"=\" + quote + appOrigin + \"/\"\n );\n }\n\n function removeHtmlCspMeta(html) {\n return String(html).replace(\n /<meta\\\\s+[^>]*http-equiv\\\\s*=\\\\s*([\"'])?content-security-policy\\\\1?[^>]*>/gi,\n \"\"\n );\n }\n\n function embedConfigForAppUrl(appUrl) {\n const sanitizedTarget = localPathFromUrl(appUrl, false);\n return {\n origin: appUrl.origin,\n href: appUrl.href,\n baseHref: appUrl.origin + appUrl.pathname,\n target: sanitizedTarget,\n token: appUrl.searchParams.get(\"__an_embed_token\") || \"\",\n chatBridgeActive: appUrl.searchParams.get(chatBridgeParam) === \"1\",\n chatBridgeParam,\n embedTokenParam: \"__an_embed_token\",\n embedTargetHeader: \"x-agent-native-embed-target\"\n };\n }\n\n function installReactRefreshPreambleFallback() {\n window.__vite_plugin_react_preamble_installed__ = true;\n if (typeof window.$RefreshReg$ !== \"function\") {\n window.$RefreshReg$ = function() {};\n }\n if (typeof window.$RefreshSig$ !== \"function\") {\n window.$RefreshSig$ = function() {\n return function(type) {\n return type;\n };\n };\n }\n }\n\n function installExternalEmbedRuntime(config) {\n window.__AGENT_NATIVE_EXTERNAL_EMBED = config;\n installReactRefreshPreambleFallback();\n try {\n if (config.target) {\n window.history.replaceState(window.history.state, \"\", config.target);\n }\n } catch (_err) {}\n try {\n if (config.token) {\n sessionStorage.setItem(\"agent-native:embed-auth-token\", config.token);\n }\n if (config.chatBridgeActive && config.token) {\n sessionStorage.setItem(\"agent-native:mcp-chat-bridge\", config.token);\n }\n } catch (_err) {}\n if (window.__agentNativeExternalEmbedRuntimeInstalled) return;\n window.__agentNativeExternalEmbedRuntimeInstalled = true;\n function appOrigin() {\n try {\n return new URL(config.origin).origin;\n } catch (_err) {\n return \"\";\n }\n }\n function targetPath() {\n return config.target || location.pathname + location.search;\n }\n function rewrittenUrl(value, appendToken) {\n const origin = appOrigin();\n if (!origin) return null;\n let url;\n try {\n url = new URL(value, location.href);\n } catch (_err) {\n return null;\n }\n if (url.origin !== location.origin && url.origin !== origin) return null;\n if (url.origin !== origin) {\n const app = new URL(origin);\n url.protocol = app.protocol;\n url.host = app.host;\n }\n if (appendToken && config.token && url.pathname === \"/_agent-native/events\") {\n url.searchParams.set(config.embedTokenParam, config.token);\n }\n return url.toString();\n }\n function authHeaders(input, init) {\n const headers = new Headers(\n init && init.headers ? init.headers : input instanceof Request ? input.headers : undefined\n );\n if (config.token && !headers.has(\"Authorization\")) {\n headers.set(\"Authorization\", \"Bearer \" + config.token);\n }\n if (!headers.has(config.embedTargetHeader)) {\n headers.set(config.embedTargetHeader, targetPath());\n }\n return headers;\n }\n if (typeof fetch === \"function\") {\n const originalFetch = fetch.bind(window);\n window.fetch = function(input, init) {\n const raw = input instanceof Request ? input.url : String(input);\n const url = rewrittenUrl(raw, false);\n if (!url) return originalFetch(input, init);\n const nextInit = Object.assign({}, init || {}, {\n headers: authHeaders(input, init),\n credentials: \"omit\"\n });\n if (input instanceof Request) {\n return originalFetch(new Request(url, input), nextInit);\n }\n return originalFetch(url, nextInit);\n };\n }\n if (typeof XMLHttpRequest !== \"undefined\") {\n const originalOpen = XMLHttpRequest.prototype.open;\n const originalSend = XMLHttpRequest.prototype.send;\n XMLHttpRequest.prototype.open = function(method, url) {\n const rewritten = rewrittenUrl(url, false);\n this.__agentNativeExternalEmbed = !!rewritten;\n return originalOpen.call(\n this,\n method,\n rewritten || url,\n arguments.length > 2 ? arguments[2] : true,\n arguments[3],\n arguments[4]\n );\n };\n XMLHttpRequest.prototype.send = function(body) {\n if (this.__agentNativeExternalEmbed) {\n try {\n if (config.token) this.setRequestHeader(\"Authorization\", \"Bearer \" + config.token);\n this.setRequestHeader(config.embedTargetHeader, targetPath());\n } catch (_err) {}\n }\n return originalSend.call(this, body);\n };\n }\n if (typeof EventSource !== \"undefined\") {\n const OriginalEventSource = EventSource;\n window.EventSource = function(url, options) {\n return new OriginalEventSource(rewrittenUrl(url, true) || url, options);\n };\n window.EventSource.prototype = OriginalEventSource.prototype;\n }\n }\n\n function copyDocumentElementAttributes(source) {\n const target = document.documentElement;\n for (const attr of Array.from(target.attributes)) {\n target.removeAttribute(attr.name);\n }\n for (const attr of Array.from(source.attributes)) {\n target.setAttribute(attr.name, attr.value);\n }\n }\n\n function importChildren(source, target) {\n target.replaceChildren(\n ...Array.from(source.childNodes).map((node) => document.importNode(node, true))\n );\n }\n\n function isModuleScript(script) {\n return (script.getAttribute(\"type\") || \"\").trim().toLowerCase() === \"module\";\n }\n\n function isRunnableClassicScript(script) {\n const type = (script.getAttribute(\"type\") || \"\").trim().toLowerCase();\n return !type || type === \"text/javascript\" || type === \"application/javascript\";\n }\n\n function runClassicScript(script) {\n const next = document.createElement(\"script\");\n for (const attr of Array.from(script.attributes)) {\n if (attr.name === \"type\") continue;\n next.setAttribute(attr.name, attr.value);\n }\n if (script.src) {\n next.src = script.src;\n } else {\n next.textContent = script.textContent || \"\";\n }\n document.body.appendChild(next);\n next.remove();\n }\n\n function isEmbedRuntimeModulePath(pathname) {\n if (typeof pathname !== \"string\" || !pathname) return false;\n return /(?:^|\\\\/)(?:@(?:id|vite|fs|react-refresh)|app|node_modules|packages|src)(?:\\\\/|$)/.test(pathname) ||\n /(?:^|\\\\/)__x00__virtual:/.test(pathname) ||\n pathname.includes(\"virtual:react-router\");\n }\n\n function appendEmbedParamsToAppUrl(url, config) {\n if (isEmbedRuntimeModulePath(url.pathname)) return url;\n if (config.token) url.searchParams.set(config.embedTokenParam, config.token);\n if (config.chatBridgeActive) url.searchParams.set(config.chatBridgeParam, \"1\");\n return url;\n }\n\n function rootRelativeSpecifierToAppUrl(specifier, config) {\n if (typeof specifier !== \"string\" || !specifier.startsWith(\"/\") || specifier.startsWith(\"//\")) {\n return specifier;\n }\n try {\n const url = new URL(specifier, config.origin);\n return appendEmbedParamsToAppUrl(url, config).toString();\n } catch (_err) {\n return specifier;\n }\n }\n\n function rootRelativeSpecifiersToAbsolute(code, config) {\n return String(code).replace(/([\"'])\\\\/(?!\\\\/)([^\"']*)/g, (_match, quote, rest) => {\n return quote + rootRelativeSpecifierToAppUrl(\"/\" + rest, config);\n });\n }\n\n function relativeSpecifierToAppUrl(specifier, config, baseUrl) {\n if (typeof specifier !== \"string\" || !/^\\\\.\\\\.?\\\\//.test(specifier)) {\n return specifier;\n }\n try {\n const url = new URL(specifier, baseUrl || config.baseHref);\n if (url.origin === config.origin) {\n appendEmbedParamsToAppUrl(url, config);\n }\n return url.toString();\n } catch (_err) {\n return specifier;\n }\n }\n\n function relativeModuleSpecifiersToAbsolute(code, config, baseUrl) {\n return String(code)\n .replace(/(\\\\bimport\\\\s+(?:[^\"']+?\\\\s+from\\\\s+)?)([\"'])(\\\\.\\\\.?\\\\/[^\"']*)\\\\2/g, (_match, prefix, quote, specifier) => {\n return prefix + quote + relativeSpecifierToAppUrl(specifier, config, baseUrl) + quote;\n })\n .replace(/(\\\\bimport\\\\s*\\\\(\\\\s*)([\"'])(\\\\.\\\\.?\\\\/[^\"']*)\\\\2/g, (_match, prefix, quote, specifier) => {\n return prefix + quote + relativeSpecifierToAppUrl(specifier, config, baseUrl) + quote;\n })\n .replace(/(\\\\bexport\\\\s+[^\"']*?\\\\s+from\\\\s+)([\"'])(\\\\.\\\\.?\\\\/[^\"']*)\\\\2/g, (_match, prefix, quote, specifier) => {\n return prefix + quote + relativeSpecifierToAppUrl(specifier, config, baseUrl) + quote;\n });\n }\n\n function stripDevOnlyModuleImports(code) {\n return String(code).replace(\n /\\\\bimport\\\\s+(?:[^\"']+\\\\s+from\\\\s+)?[\"'][^\"']*(?:virtual:react-router\\\\/inject-hmr-runtime|__x00__virtual:react-router\\\\/inject-hmr-runtime)[^\"']*[\"']\\\\s*;?/g,\n \"\"\n );\n }\n\n function namedImportBindings(specifierList) {\n return String(specifierList)\n .split(\",\")\n .map((part) => {\n const trimmed = part.trim();\n if (!trimmed) return \"\";\n return trimmed.replace(\n /^([A-Za-z_$][\\\\w$]*)\\\\s+as\\\\s+([A-Za-z_$][\\\\w$]*)$/,\n \"$1: $2\"\n );\n })\n .filter(Boolean)\n .join(\", \");\n }\n\n function moduleCodeToClassicAsync(code, config, baseUrl) {\n return relativeModuleSpecifiersToAbsolute(\n rootRelativeSpecifiersToAbsolute(stripDevOnlyModuleImports(code), config),\n config,\n baseUrl\n )\n .replace(\n /\\\\bimport\\\\s+([A-Za-z_$][\\\\w$]*)\\\\s*,\\\\s*\\\\*\\\\s+as\\\\s+([A-Za-z_$][\\\\w$]*)\\\\s+from\\\\s+([\"'][^\"']+[\"'])\\\\s*;?/g,\n \"const $2 = await import($3); const $1 = $2.default;\"\n )\n .replace(\n /\\\\bimport\\\\s+([A-Za-z_$][\\\\w$]*)\\\\s*,\\\\s*\\\\{([\\\\s\\\\S]*?)\\\\}\\\\s*from\\\\s+([\"'][^\"']+[\"'])\\\\s*;?/g,\n (_match, defaultName, specifiers, source) =>\n \"const { default: \" +\n defaultName +\n (namedImportBindings(specifiers) ? \", \" + namedImportBindings(specifiers) : \"\") +\n \" } = await import(\" +\n source +\n \");\"\n )\n .replace(\n /\\\\bimport\\\\s+\\\\{([\\\\s\\\\S]*?)\\\\}\\\\s*from\\\\s+([\"'][^\"']+[\"'])\\\\s*;?/g,\n (_match, specifiers, source) =>\n \"const { \" + namedImportBindings(specifiers) + \" } = await import(\" + source + \");\"\n )\n .replace(\n /\\\\bimport\\\\s+\\\\*\\\\s+as\\\\s+([A-Za-z_$][\\\\w$]*)\\\\s+from\\\\s+([\"'][^\"']+[\"'])\\\\s*;?/g,\n \"const $1 = await import($2);\"\n )\n .replace(\n /\\\\bimport\\\\s+([A-Za-z_$][\\\\w$]*)\\\\s+from\\\\s+([\"'][^\"']+[\"'])\\\\s*;?/g,\n \"const { default: $1 } = await import($2);\"\n )\n .replace(/\\\\bimport\\\\s+([\"'][^\"']+[\"'])\\\\s*;?/g, \"await import($1);\")\n .replace(/\\\\bimport\\\\(([\"'][^\"']+[\"'])\\\\)\\\\s*;?/g, \"await import($1);\");\n }\n\n function scriptSourceUrl(script, config) {\n const raw = script.getAttribute(\"src\") || \"\";\n if (!raw) return \"\";\n try {\n const url = new URL(raw, config.baseHref);\n if (url.origin === config.origin) {\n appendEmbedParamsToAppUrl(url, config);\n }\n return url.toString();\n } catch (_err) {\n return raw;\n }\n }\n\n async function moduleScriptCode(script, config) {\n const src = scriptSourceUrl(script, config);\n if (!src) return script.textContent || \"\";\n const response = await fetch(src, {\n credentials: \"omit\",\n headers: { Accept: \"text/javascript, application/javascript, */*\" }\n });\n if (!response.ok) {\n throw new Error(\"Module script returned HTTP \" + response.status + \".\");\n }\n return await response.text();\n }\n\n async function runModuleScriptAsClassic(script, config) {\n const sourceUrl = scriptSourceUrl(script, config) || config.baseHref;\n const code = moduleCodeToClassicAsync(\n await moduleScriptCode(script, config),\n config,\n sourceUrl\n );\n const runner = document.createElement(\"script\");\n runner.textContent =\n \"(async()=>{\" +\n code +\n \"})().catch((err)=>{console.error('[agent-native] transplanted app module failed',err);document.body.setAttribute('data-agent-native-hydration-error',String(err&&err.message||err));});\";\n document.body.appendChild(runner);\n runner.remove();\n }\n\n async function mountTransplantedHtml(html, appUrl) {\n const config = embedConfigForAppUrl(appUrl);\n installExternalEmbedRuntime(config);\n const parsed = new DOMParser().parseFromString(\n rewriteRootRelativeHtmlUrls(removeHtmlCspMeta(html), appUrl.origin),\n \"text/html\"\n );\n const scripts = Array.from(parsed.querySelectorAll(\"script\"));\n copyDocumentElementAttributes(parsed.documentElement);\n importChildren(parsed.head, document.head);\n const base = document.createElement(\"base\");\n base.href = config.baseHref;\n document.head.prepend(base);\n importChildren(parsed.body, document.body);\n for (const script of scripts) {\n if (isRunnableClassicScript(script)) runClassicScript(script);\n }\n for (const script of scripts) {\n if (isModuleScript(script)) await runModuleScriptAsClassic(script, config);\n }\n }\n\n function absoluteUrl(value, base) {\n try {\n return new URL(value, base).toString();\n } catch {\n return \"\";\n }\n }\n\n async function resolveTransplantAppDocumentSource(src) {\n if (!isEmbedStartUrl(src)) {\n return { url: new URL(src), response: null };\n }\n const response = await fetch(src, {\n credentials: \"omit\",\n redirect: \"follow\",\n headers: {\n Accept: \"application/json\",\n \"X-Agent-Native-Embed-Transplant\": \"1\"\n }\n });\n const contentType = response.headers.get(\"content-type\") || \"\";\n if (response.ok && /\\\\bapplication\\\\/json\\\\b/i.test(contentType)) {\n const data = await response.json();\n const location = typeof data.location === \"string\" ? data.location : \"\";\n const url = absoluteUrl(location, src);\n if (url) return { url: new URL(withChatBridgeParam(url)), response: null };\n throw new Error(\"Embedded app did not return a launch URL.\");\n }\n return {\n url: new URL(response.url || src),\n response\n };\n }\n\n async function transplantAppDocument(src) {\n clearFrameReadyTimer();\n clearFrameLoadTimer();\n appFrame = null;\n lastFrameSrc = src;\n setMessage(\"Loading app\");\n const source = await resolveTransplantAppDocumentSource(src);\n const response = source.response || await fetch(source.url.href, {\n credentials: \"omit\",\n redirect: \"follow\",\n headers: { Accept: \"text/html\" }\n });\n if (!response.ok) {\n if (response.status === 401 && isEmbedStartUrl(src)) {\n refreshExpiredEmbedSession();\n return;\n }\n throw new Error(\"Embedded app returned HTTP \" + response.status + \".\");\n }\n const html = await response.text();\n const appUrl = source.url || new URL(response.url || src);\n try {\n window.history.replaceState(window.history.state, \"\", localPathFromUrl(appUrl, false));\n } catch {}\n await mountTransplantedHtml(html, appUrl);\n notifyHostHeightRepeatedly();\n }\n\n function wantsEmbed() {\n if (toolInput.embed === false || toolInput.embed === \"false\") return false;\n if (embedByDefault) return true;\n return toolInput.embed === true || toolInput.embed === \"true\";\n }\n\n function renderModeSource() {\n const input = objectValue(toolInput);\n const result = objectValue(toolResultData);\n return {\n mode: typeof input.embedMode === \"string\"\n ? input.embedMode\n : typeof input.renderMode === \"string\"\n ? input.renderMode\n : typeof result.embedMode === \"string\"\n ? result.embedMode\n : typeof result.renderMode === \"string\"\n ? result.renderMode\n : \"\",\n frame: typeof input.frame === \"string\"\n ? input.frame\n : typeof result.frame === \"string\"\n ? result.frame\n : \"\",\n nested: input.nested === true || result.nested === true\n };\n }\n\n function supportedDisplayMode(mode) {\n if (openAiBridge && typeof openAiBridge.requestDisplayMode === \"function\") {\n return mode === \"inline\" || mode === \"fullscreen\" || mode === \"pip\";\n }\n const modes = hostState().context && hostState().context.availableDisplayModes;\n return Array.isArray(modes) && modes.includes(mode);\n }\n\n async function requestHostDisplayMode(mode) {\n let result;\n if (openAiBridge && typeof openAiBridge.requestDisplayMode === \"function\") {\n result = await openAiBridge.requestDisplayMode({ mode });\n } else {\n if (!app || typeof app.requestDisplayMode !== \"function\") {\n throw new Error(\"Display mode changes are not available in this host.\");\n }\n result = await app.requestDisplayMode({ mode });\n }\n updateDisplayButton();\n sendHostContext();\n return result;\n }\n\n function updateDisplayButton() {\n const context = hostState().context || {};\n const nextMode = context.displayMode === \"fullscreen\" ? \"inline\" : \"fullscreen\";\n const supported = supportedDisplayMode(nextMode);\n displayButton.hidden = !supported;\n displayButton.disabled = !supported;\n displayButton.textContent = nextMode === \"fullscreen\" ? \"Fullscreen\" : \"Inline\";\n displayButton.onclick = () => {\n if (!supportedDisplayMode(nextMode)) return;\n void requestHostDisplayMode(nextMode).catch((err) => {\n console.warn(\"[agent-native] MCP host rejected display mode request\", err);\n });\n };\n }\n\n function setMessage(message) {\n stage.innerHTML = '<div class=\"message\">' + esc(message) + '</div>';\n }\n\n function clearFrameReadyTimer() {\n if (!appFrameReadyTimer) return;\n clearTimeout(appFrameReadyTimer);\n appFrameReadyTimer = null;\n }\n\n function clearFrameLoadTimer() {\n if (!appFrameLoadTimer) return;\n clearTimeout(appFrameLoadTimer);\n appFrameLoadTimer = null;\n }\n\n function startFrameReadyTimer(frame) {\n clearFrameReadyTimer();\n appFrameReadyTimer = setTimeout(() => {\n if (!appFrameReady && appFrame === frame) renderFrameFallback();\n }, frameReadyTimeoutMs);\n }\n\n function renderFrameFallback() {\n clearFrameReadyTimer();\n clearFrameLoadTimer();\n appFrame = null;\n const fallbackCopy = openUrl\n ? \"This chat host did not allow the embedded app frame to load inline. You can still open the same app route through the host or use the URL below.\"\n : \"This chat host did not allow the embedded app frame to load inline.\";\n stage.innerHTML =\n '<div class=\"fallback\">' +\n '<div class=\"fallback-title\">Open this app in its own tab</div>' +\n '<div class=\"fallback-copy\">' + esc(fallbackCopy) + '</div>' +\n '<div class=\"fallback-actions\">' +\n '<button type=\"button\" data-fallback-open>Open app</button>' +\n '<button type=\"button\" data-fallback-retry>Try inline again</button>' +\n '</div>' +\n (openUrl ? '<a class=\"fallback-url\" href=\"' + esc(openUrl) + '\" target=\"_blank\" rel=\"noreferrer\">' + esc(openUrl) + '</a>' : '') +\n '</div>';\n const fallbackOpen = stage.querySelector(\"[data-fallback-open]\");\n const fallbackRetry = stage.querySelector(\"[data-fallback-retry]\");\n if (fallbackOpen) {\n fallbackOpen.disabled = !openUrl;\n fallbackOpen.onclick = () => {\n if (openUrl) void openFallbackExternal();\n };\n }\n if (fallbackRetry) {\n fallbackRetry.disabled = !lastFrameSrc;\n fallbackRetry.onclick = () => {\n if (lastFrameSrc) renderFrame(lastFrameSrc);\n };\n }\n }\n\n async function openFallbackExternal() {\n if (!openUrl) return;\n let url = withChatBridgeParam(openUrl);\n try {\n if (url) {\n const result = await callEmbedSessionTool(embedSessionArgsFor(url));\n const data = parseToolResult(result);\n if (typeof data.startUrl === \"string\" && data.startUrl) {\n url = withChatBridgeParam(data.startUrl);\n }\n }\n } catch (err) {\n console.warn(\"[agent-native] MCP fallback could not mint a fresh app session\", err);\n }\n await openHostLink({ url });\n }\n\n function renderFrame(src) {\n clearFrameReadyTimer();\n clearFrameLoadTimer();\n const frame = document.createElement(\"iframe\");\n frame.title = body.dataset.iframeTitle || \"Agent Native app\";\n frame.src = src;\n frame.allow = \"clipboard-read; clipboard-write\";\n appFrame = frame;\n appFrameReady = false;\n lastFrameSrc = src;\n frame.addEventListener(\"load\", () => {\n if (appFrame !== frame) return;\n clearFrameLoadTimer();\n sendFrameReadyMessages(frame);\n startFrameReadyTimer(frame);\n });\n stage.replaceChildren(frame);\n notifyHostHeight();\n appFrameLoadTimer = setTimeout(() => {\n if (!appFrameReady && appFrame === frame) renderFrameFallback();\n }, frameLoadTimeoutMs);\n }\n\n function refreshExpiredEmbedSession() {\n clearFrameReadyTimer();\n clearFrameLoadTimer();\n appFrameReady = false;\n if (!openUrl) {\n renderFrameFallback();\n return;\n }\n openStartUrl = \"\";\n startedFor = \"\";\n lastFrameSrc = \"\";\n setMessage(\"Refreshing app session\");\n void launchEmbed();\n }\n\n function shouldSelfNavigateToApp() {\n const render = renderModeSource();\n const mode = render.mode;\n if (isClaudeMcpContentHost()) return true;\n if (mode === \"iframe\" || mode === \"nested\") return false;\n if (render.nested || render.frame === \"iframe\") return false;\n return true;\n }\n\n function shouldTransplantAppDocument() {\n const render = renderModeSource();\n const mode = render.mode;\n return (\n isClaudeMcpContentHost() ||\n isChatGptSandboxHost() ||\n mode === \"transplant\" ||\n render.frame === \"transplant\"\n );\n }\n\n function isClaudeMcpContentHost() {\n try {\n return /(^|\\\\.)claudemcpcontent\\\\.com$/i.test(window.location.hostname || \"\");\n } catch {\n return false;\n }\n }\n\n function isChatGptSandboxHost() {\n try {\n const host = window.location.hostname || \"\";\n const appParam = new URL(window.location.href).searchParams.get(\"app\");\n return /^[^.]+\\\\.web-sandbox\\\\.oaiusercontent\\\\.com$/i.test(host) || appParam === \"chatgpt\";\n } catch {\n return false;\n }\n }\n\n function shouldRenderControlledAppFrame() {\n return !!openAiBridge || isChatGptSandboxHost();\n }\n\n function navigateToAppFrame(src) {\n clearFrameReadyTimer();\n clearFrameLoadTimer();\n appFrame = null;\n lastFrameSrc = src;\n setMessage(\"Opening app\");\n try {\n window.location.replace(src);\n } catch (err) {\n console.warn(\"[agent-native] MCP app self-navigation failed\", err);\n renderFrameFallback();\n }\n }\n\n async function updateHostModelContext(data) {\n const params = {};\n if (Array.isArray(data && data.content)) params.content = data.content;\n if (data && data.structuredContent && typeof data.structuredContent === \"object\") {\n params.structuredContent = data.structuredContent;\n }\n if (openAiBridge && typeof openAiBridge.setWidgetState === \"function\") {\n openAiBridge.setWidgetState({\n ...objectValue(openAiBridge.widgetState),\n agentNativeModelContext: params\n });\n return { ok: true };\n }\n if (!app || typeof app.updateModelContext !== \"function\") return { ok: false };\n await app.updateModelContext(params);\n return { ok: true };\n }\n\n async function openHostLink(data) {\n const url = typeof (data && data.url) === \"string\" ? data.url : \"\";\n if (!url) return { isError: true };\n if (openAiBridge && typeof openAiBridge.openExternal === \"function\") {\n return await openAiBridge.openExternal({ href: url, redirectUrl: false });\n }\n if (app && typeof app.openLink === \"function\") {\n return await app.openLink({ url });\n }\n window.open(url, \"_blank\", \"noopener,noreferrer\");\n return { ok: true };\n }\n\n function notifyHostHeight() {\n const height = applyIntrinsicHeight(visibleIntrinsicHeight());\n if (!openAiBridge || typeof openAiBridge.notifyIntrinsicHeight !== \"function\") {\n if (app && typeof app.sendSizeChanged === \"function\") {\n try {\n app.sendSizeChanged({ height });\n } catch (err) {\n console.warn(\"[agent-native] MCP host rejected size update\", err);\n }\n }\n return;\n }\n try {\n openAiBridge.notifyIntrinsicHeight({ height });\n } catch (err) {\n console.warn(\"[agent-native] ChatGPT rejected intrinsic height update\", err);\n }\n }\n\n function respondToAppFrame(requestId, work) {\n if (!requestId) return;\n Promise.resolve(work)\n .then((result) => {\n sendToAppFrame({\n type: \"agentNative.mcpHost.response\",\n data: { requestId, ok: true, result }\n });\n })\n .catch((err) => {\n sendToAppFrame({\n type: \"agentNative.mcpHost.response\",\n data: {\n requestId,\n ok: false,\n error: err && err.message ? err.message : String(err)\n }\n });\n });\n }\n\n async function sendHostChat(chat) {\n const requestId = typeof (chat && chat.requestId) === \"string\" ? chat.requestId : \"\";\n if (!chat || chat.submit === false) return;\n const message = typeof chat.message === \"string\" ? chat.message : \"\";\n if (!message.trim()) return;\n const context = typeof chat.context === \"string\" ? chat.context.trim() : \"\";\n const content = Array.isArray(chat.content) && chat.content.length\n ? chat.content\n : [{ type: \"text\", text: message }];\n const structuredContent =\n chat && chat.structuredContent !== undefined\n ? chat.structuredContent\n : undefined;\n try {\n const contextContent = context\n ? [{ type: \"text\", text: context }, ...content.filter((part) => part && part.type !== \"text\")]\n : content.filter((part) => part && part.type !== \"text\");\n const modelContext = {\n content: contextContent,\n ...(structuredContent !== undefined ? { structuredContent } : {})\n };\n if (openAiBridge && typeof openAiBridge.setWidgetState === \"function\") {\n openAiBridge.setWidgetState({\n ...objectValue(openAiBridge.widgetState),\n agentNativeChatContext: context || null,\n agentNativeModelContext: modelContext\n });\n } else if (app && typeof app.updateModelContext === \"function\") {\n await app.updateModelContext(modelContext);\n }\n } catch (err) {\n console.warn(\"[agent-native] MCP host rejected model context update\", err);\n }\n try {\n if (openAiBridge && typeof openAiBridge.sendFollowUpMessage === \"function\") {\n await openAiBridge.sendFollowUpMessage({\n prompt: message,\n scrollToBottom: true\n });\n respondToWrapperRequest(requestId, { ok: true });\n return;\n }\n let result = null;\n if (app && typeof app.sendMessage === \"function\") {\n result = await app.sendMessage({\n role: \"user\",\n content\n });\n } else {\n result = await wrapperRpcRequest(\"ui/message\", {\n role: \"user\",\n content\n });\n }\n if (result && result.isError) {\n console.warn(\"[agent-native] MCP host rejected chat message\", result);\n respondToWrapperRequest(requestId, { ok: false, result });\n return;\n }\n if (result && result.ok === false) {\n console.warn(\"[agent-native] MCP host chat bridge failed\", result);\n respondToWrapperRequest(requestId, { ok: false, result });\n return;\n }\n respondToWrapperRequest(requestId, { ok: true, result });\n } catch (err) {\n console.warn(\"[agent-native] MCP host chat bridge failed\", err);\n respondToWrapperRequest(requestId, { ok: false, error: err && err.message ? err.message : String(err) });\n }\n }\n\n window.addEventListener(\"message\", (event) => {\n if (event.source !== window.parent) return;\n const message = event.data;\n if (!message || message.jsonrpc !== \"2.0\") return;\n settleWrapperRpcResponse(message);\n });\n\n window.addEventListener(\"message\", (event) => {\n if (!appFrame || event.source !== appFrame.contentWindow) return;\n if (!event.data) return;\n const data = event.data.data || {};\n if (event.data.type === \"agentNative.embeddedAppReady\") {\n appFrameReady = true;\n clearFrameLoadTimer();\n clearFrameReadyTimer();\n return;\n }\n if (event.data.type === \"agentNative.embedSessionExpired\") {\n refreshExpiredEmbedSession();\n return;\n }\n if (event.data.type === \"agentNative.submitChat\") {\n void sendHostChat(data);\n return;\n }\n if (event.data.type === \"agentNative.mcpHost.updateModelContext\") {\n respondToAppFrame(data.requestId, updateHostModelContext(data));\n return;\n }\n if (event.data.type === \"agentNative.mcpHost.openLink\") {\n respondToAppFrame(data.requestId, openHostLink(data));\n return;\n }\n if (event.data.type === \"agentNative.mcpHost.requestDisplayMode\") {\n respondToAppFrame(data.requestId, requestHostDisplayMode(data.mode));\n }\n });\n\n function notifyHostHeightSoon() {\n requestAnimationFrame(() => notifyHostHeight());\n }\n\n function notifyHostHeightRepeatedly() {\n notifyHostHeight();\n [0, 250, 1000, 2500].forEach((delay) => {\n setTimeout(() => notifyHostHeight(), delay);\n });\n }\n\n window.addEventListener(\"resize\", notifyHostHeightSoon, { passive: true });\n if (window.visualViewport) {\n window.visualViewport.addEventListener(\"resize\", notifyHostHeightSoon, { passive: true });\n }\n\n async function launchEmbed() {\n const launchUrl = openStartUrl || openUrl;\n if (!launchUrl) {\n setMessage(\"Open link was not available.\");\n return;\n }\n if (!wantsEmbed()) {\n setMessage(\"Ready to open.\");\n return;\n }\n if (startedFor === launchUrl) return;\n startedFor = launchUrl;\n setMessage(\"Loading app\");\n try {\n const selfNavigate = shouldSelfNavigateToApp();\n const embedUrl = withChatBridgeParam(launchUrl);\n if (selfNavigate && isEmbedStartUrl(embedUrl)) {\n if (shouldTransplantAppDocument()) {\n await transplantAppDocument(embedUrl);\n } else if (shouldRenderControlledAppFrame()) {\n renderFrame(embedUrl);\n } else {\n navigateToAppFrame(embedUrl);\n }\n return;\n }\n if (!selfNavigate && isEmbedStartUrl(embedUrl)) {\n renderFrame(embedUrl);\n return;\n }\n const result = await callEmbedSessionTool(embedSessionArgsFor(embedUrl));\n const data = parseToolResult(result);\n if (typeof data.startUrl !== \"string\" || !data.startUrl) {\n startedFor = \"\";\n setMessage(data.error || \"This app can be opened, but not embedded from this MCP server.\");\n return;\n }\n const startUrl = withChatBridgeParam(data.startUrl);\n if (selfNavigate) {\n if (shouldTransplantAppDocument()) {\n await transplantAppDocument(startUrl);\n } else if (shouldRenderControlledAppFrame()) {\n renderFrame(startUrl);\n } else {\n navigateToAppFrame(startUrl);\n }\n } else {\n renderFrame(startUrl);\n }\n } catch (err) {\n startedFor = \"\";\n setMessage(err && err.message ? err.message : \"Could not launch embedded app.\");\n }\n }\n\n async function callEmbedSessionTool(args) {\n if (openAiBridge && typeof openAiBridge.callTool === \"function\") {\n return await openAiBridge.callTool(startTool, args);\n }\n if (!app || typeof app.callServerTool !== \"function\") {\n throw new Error(\"Host tool calls are not available.\");\n }\n return await app.callServerTool({ name: startTool, arguments: args });\n }\n\n function updateHostOpenInAppUrl() {\n if (!openAiBridge || !openUrl || typeof openAiBridge.setOpenInAppUrl !== \"function\") {\n return;\n }\n try {\n openAiBridge.setOpenInAppUrl({ href: openUrl });\n } catch (err) {\n console.warn(\"[agent-native] ChatGPT rejected open-in-app URL\", err);\n }\n }\n\n function updateOpenButton() {\n const buttonUrl = openUrl;\n openButton.disabled = !buttonUrl;\n openButton.onclick = () => {\n if (buttonUrl) void openHostLink({ url: buttonUrl });\n };\n updateHostOpenInAppUrl();\n }\n\n function updateTitle(data) {\n const record = objectValue(data);\n const label = record.label || record.app || record.view || body.dataset.appTitle || \"App\";\n titleEl.textContent = String(label);\n }\n\n function readOpenAiBridge() {\n return window.openai && typeof window.openai === \"object\"\n ? window.openai\n : null;\n }\n\n function isChatGptHostHint() {\n try {\n if (new URLSearchParams(window.location.search).get(\"app\") === \"chatgpt\") return true;\n } catch (_err) {}\n try {\n return /chatgpt/i.test(String(navigator.userAgent || \"\"));\n } catch (_err) {\n return false;\n }\n }\n\n function openAiToolResultParams(bridge) {\n const params = {};\n if (bridge && bridge.toolOutput !== undefined) {\n if (bridge.toolOutput && typeof bridge.toolOutput === \"object\") {\n params.structuredContent = bridge.toolOutput;\n } else {\n params.content = [{ type: \"text\", text: String(bridge.toolOutput) }];\n }\n }\n if (bridge && bridge.toolResponseMetadata && typeof bridge.toolResponseMetadata === \"object\") {\n params._meta = bridge.toolResponseMetadata;\n }\n return params;\n }\n\n function syncOpenAiBridge(bridge) {\n if (!bridge) return false;\n openAiBridge = bridge;\n toolInput = objectValue(bridge.toolInput);\n const params = openAiToolResultParams(bridge);\n const data = parseToolResult(params);\n toolResultData = objectValue(data);\n openUrl = openLinkFrom(params, data);\n openStartUrl = embedStartUrlFrom(params, data);\n updateTitle(data);\n updateOpenButton();\n updateDisplayButton();\n notifyHostHeight();\n sendHostContext();\n if (openUrl || openStartUrl) {\n void launchEmbed();\n } else if (!appFrame) {\n setMessage(\"Waiting for app result\");\n }\n return true;\n }\n\n function waitForOpenAiBridge() {\n const existing = readOpenAiBridge();\n if (existing) return Promise.resolve(existing);\n return new Promise((resolve) => {\n let settled = false;\n let pollTimer = 0;\n const finish = (bridge) => {\n if (settled) return;\n settled = true;\n window.removeEventListener(\"openai:set_globals\", onGlobals);\n clearTimeout(timer);\n clearTimeout(pollTimer);\n resolve(bridge || readOpenAiBridge());\n };\n const poll = () => {\n const bridge = readOpenAiBridge();\n if (bridge) {\n finish(bridge);\n return;\n }\n pollTimer = window.setTimeout(poll, openAiBridgePollMs);\n };\n const onGlobals = () => finish(readOpenAiBridge());\n const timer = window.setTimeout(\n () => finish(null),\n isChatGptHostHint() ? chatGptOpenAiBridgeWaitMs : defaultOpenAiBridgeWaitMs\n );\n window.addEventListener(\"openai:set_globals\", onGlobals, { passive: true });\n pollTimer = window.setTimeout(poll, openAiBridgePollMs);\n });\n }\n\n window.addEventListener(\"openai:set_globals\", () => {\n const bridge = readOpenAiBridge();\n if (bridge && (!appFrame || openAiBridge)) syncOpenAiBridge(bridge);\n }, { passive: true });\n\n function createNativeMcpAppsBridge() {\n let rpcId = 0;\n let connected = false;\n let hostContext = {};\n const pendingRequests = new Map();\n\n function rpcNotify(method, params) {\n window.parent.postMessage({ jsonrpc: \"2.0\", method, params: params || {} }, \"*\");\n }\n\n function rpcRequest(method, params, timeoutMs) {\n return new Promise((resolve, reject) => {\n const id = ++rpcId;\n const timer = window.setTimeout(() => {\n pendingRequests.delete(id);\n reject(new Error(\"MCP Apps bridge request timed out: \" + method));\n }, timeoutMs || nativeBridgeRequestTimeoutMs);\n pendingRequests.set(id, { resolve, reject, timer });\n window.parent.postMessage(\n { jsonrpc: \"2.0\", id, method, params: params || {} },\n \"*\"\n );\n });\n }\n\n function settleRpcResponse(message) {\n const pending = pendingRequests.get(message.id);\n if (!pending) return true;\n pendingRequests.delete(message.id);\n clearTimeout(pending.timer);\n if (message.error) {\n const error = new Error(message.error.message || \"MCP Apps bridge request failed.\");\n error.data = message.error.data;\n pending.reject(error);\n return true;\n }\n pending.resolve(message.result);\n return true;\n }\n\n function notificationParams(message) {\n return message && typeof message.params === \"object\" && message.params\n ? message.params\n : {};\n }\n\n function toolInputNotificationParams(params) {\n if (params && typeof params.arguments === \"object\" && params.arguments) {\n return params;\n }\n if (params && typeof params.input === \"object\" && params.input) {\n return { arguments: params.input };\n }\n return { arguments: objectValue(params) };\n }\n\n const nativeApp = {\n ontoolinput: null,\n ontoolresult: null,\n onhostcontextchanged: null,\n getHostContext() {\n return hostContext.context || hostContext;\n },\n getHostCapabilities() {\n return hostContext.capabilities || { tools: true, messaging: true };\n },\n getHostVersion() {\n return hostContext.protocolVersion || \"mcp-apps-postmessage\";\n },\n async connect() {\n if (connected) return hostContext;\n connected = true;\n window.addEventListener(\"message\", onMessage, { passive: true });\n const result = await rpcRequest(\n \"ui/initialize\",\n {\n appInfo: { name: \"Agent Native Embed\", version: \"1.0.0\" },\n appCapabilities: {},\n protocolVersion: \"2026-01-26\"\n },\n nativeBridgeInitializeTimeoutMs\n );\n hostContext = objectValue(result);\n rpcNotify(\"ui/notifications/initialized\", {});\n if (typeof nativeApp.onhostcontextchanged === \"function\") {\n nativeApp.onhostcontextchanged(hostContext);\n }\n return hostContext;\n },\n async callServerTool(request) {\n const record = objectValue(request);\n return await rpcRequest(\"tools/call\", {\n name: record.name,\n arguments: objectValue(record.arguments)\n });\n },\n async updateModelContext(params) {\n return await rpcRequest(\"ui/update-model-context\", objectValue(params));\n },\n async openLink(params) {\n const url = typeof (params && params.url) === \"string\" ? params.url : \"\";\n if (!url) return { isError: true };\n window.open(url, \"_blank\", \"noopener,noreferrer\");\n return { ok: true };\n },\n async requestDisplayMode(params) {\n return await rpcRequest(\"ui/request-display-mode\", objectValue(params));\n },\n sendSizeChanged(params) {\n rpcNotify(\"ui/notifications/size-changed\", objectValue(params));\n },\n async sendMessage(params) {\n return await rpcRequest(\"ui/message\", objectValue(params));\n }\n };\n\n function onMessage(event) {\n if (event.source !== window.parent) return;\n const message = event.data;\n if (!message || message.jsonrpc !== \"2.0\") return;\n if (typeof message.id === \"number\" || typeof message.id === \"string\") {\n settleRpcResponse(message);\n return;\n }\n if (typeof message.method !== \"string\") return;\n const params = notificationParams(message);\n if (message.method === \"ui/notifications/tool-input\") {\n if (typeof nativeApp.ontoolinput === \"function\") {\n nativeApp.ontoolinput(toolInputNotificationParams(params));\n }\n return;\n }\n if (message.method === \"ui/notifications/tool-result\") {\n if (typeof nativeApp.ontoolresult === \"function\") {\n nativeApp.ontoolresult(params);\n }\n return;\n }\n if (\n message.method === \"ui/notifications/host-context\" ||\n message.method === \"ui/notifications/context\"\n ) {\n hostContext = objectValue(params);\n if (typeof nativeApp.onhostcontextchanged === \"function\") {\n nativeApp.onhostcontextchanged(hostContext);\n }\n }\n }\n\n return nativeApp;\n }\n\n async function startNativeMcpAppsBridge() {\n app = createNativeMcpAppsBridge();\n app.ontoolinput = (params) => {\n toolInput = params.arguments || {};\n };\n app.ontoolresult = (params) => {\n const data = parseToolResult(params);\n toolResultData = objectValue(data);\n openUrl = openLinkFrom(params, data);\n openStartUrl = embedStartUrlFrom(params, data);\n updateTitle(data);\n updateOpenButton();\n void launchEmbed();\n };\n app.onhostcontextchanged = () => {\n updateDisplayButton();\n notifyHostHeight();\n sendHostContext();\n };\n await app.connect();\n updateDisplayButton();\n notifyHostHeight();\n sendHostContext();\n }\n\n async function startMcpAppsBridge() {\n const { App } = await import(\"${MCP_APP_IMPORT}\");\n app = new App(\n { name: \"Agent Native Embed\", version: \"1.0.0\" },\n {},\n { autoResize: false }\n );\n app.ontoolinput = (params) => {\n toolInput = params.arguments || {};\n };\n app.ontoolresult = (params) => {\n const data = parseToolResult(params);\n toolResultData = objectValue(data);\n openUrl = openLinkFrom(params, data);\n openStartUrl = embedStartUrlFrom(params, data);\n updateTitle(data);\n updateOpenButton();\n void launchEmbed();\n };\n app.onhostcontextchanged = () => {\n updateDisplayButton();\n notifyHostHeight();\n sendHostContext();\n };\n await app.connect();\n updateDisplayButton();\n notifyHostHeight();\n sendHostContext();\n }\n\n try {\n const initialOpenAiBridge = await waitForOpenAiBridge();\n if (!syncOpenAiBridge(initialOpenAiBridge)) {\n try {\n await startNativeMcpAppsBridge();\n } catch (nativeErr) {\n console.warn(\"[agent-native] native MCP Apps bridge failed\", nativeErr);\n await startMcpAppsBridge();\n }\n }\n } catch (err) {\n console.error(\"[agent-native] MCP app shell failed\", err);\n setMessage(err && err.message ? err.message : \"Could not initialize app.\");\n }\n })();\n </script>\n</body>\n</html>`,\n csp: {\n connectDomains: [\n \"https://esm.sh\",\n MCP_APP_REQUEST_ORIGIN_CSP_SOURCE,\n ...(options.connectDomains ?? []),\n ...(options.frameDomains ?? []),\n ],\n resourceDomains: [\n \"https://esm.sh\",\n MCP_APP_REQUEST_ORIGIN_CSP_SOURCE,\n ...(options.resourceDomains ?? []),\n ...(options.frameDomains ?? []),\n ],\n baseUriDomains: [\n MCP_APP_REQUEST_ORIGIN_CSP_SOURCE,\n ...(options.baseUriDomains ?? []),\n ],\n frameDomains,\n },\n prefersBorder: false,\n };\n}\n"]}
|