@tylertech/forge-ai 0.15.2 → 0.15.3-dev.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/custom-elements.json +4501 -1781
  2. package/dist/ai-artifact-card/ai-artifact-card.d.ts +75 -0
  3. package/dist/ai-artifact-card/ai-artifact-card.mjs +142 -0
  4. package/dist/ai-artifact-card/ai-artifact-card.scss.mjs +283 -0
  5. package/dist/ai-artifact-card/index.d.ts +1 -0
  6. package/dist/ai-artifact-card/index.mjs +5 -0
  7. package/dist/ai-artifact-card-group/ai-artifact-card-group.d.ts +57 -0
  8. package/dist/ai-artifact-card-group/ai-artifact-card-group.mjs +137 -0
  9. package/dist/ai-artifact-card-group/ai-artifact-card-group.scss.mjs +173 -0
  10. package/dist/ai-artifact-card-group/index.d.ts +1 -0
  11. package/dist/ai-artifact-card-group/index.mjs +5 -0
  12. package/dist/ai-assistant-response/ai-assistant-response.d.ts +2 -2
  13. package/dist/ai-assistant-response/ai-assistant-response.mjs +26 -2
  14. package/dist/ai-canvas/ai-canvas.d.ts +43 -0
  15. package/dist/ai-canvas/ai-canvas.mjs +95 -0
  16. package/dist/ai-canvas/ai-canvas.scss.mjs +4 -0
  17. package/dist/ai-canvas/index.d.ts +1 -0
  18. package/dist/ai-canvas/index.mjs +5 -0
  19. package/dist/ai-chatbot/ag-ui-adapter.d.ts +2 -2
  20. package/dist/ai-chatbot/ag-ui-adapter.mjs +1 -1
  21. package/dist/ai-chatbot/agent-adapter.d.ts +111 -4
  22. package/dist/ai-chatbot/agent-adapter.mjs +22 -0
  23. package/dist/ai-chatbot/agent-runner.d.ts +2 -2
  24. package/dist/ai-chatbot/ai-chatbot-base.d.ts +29 -2
  25. package/dist/ai-chatbot/ai-chatbot-base.mjs +147 -3
  26. package/dist/ai-chatbot/ai-chatbot-tool-call.d.ts +2 -2
  27. package/dist/ai-chatbot/ai-chatbot-tool-call.mjs +88 -10
  28. package/dist/ai-chatbot/ai-chatbot.d.ts +24 -1
  29. package/dist/ai-chatbot/ai-chatbot.mjs +102 -2
  30. package/dist/ai-chatbot/ai-chatbot.scss.mjs +1 -1
  31. package/dist/ai-chatbot/create-tool-renderer.d.ts +5 -5
  32. package/dist/ai-chatbot/index.d.ts +3 -2
  33. package/dist/ai-chatbot/index.mjs +3 -0
  34. package/dist/ai-chatbot/message-state-controller.d.ts +10 -1
  35. package/dist/ai-chatbot/message-state-controller.mjs +78 -20
  36. package/dist/ai-chatbot/tool-canvas.d.ts +60 -0
  37. package/dist/ai-chatbot/tool-canvas.mjs +128 -0
  38. package/dist/ai-chatbot/types.d.ts +325 -15
  39. package/dist/ai-chatbot/utils.d.ts +8 -3
  40. package/dist/ai-chatbot/utils.mjs +7 -1
  41. package/dist/ai-chatbot-launcher/ai-chatbot-launcher.d.ts +40 -2
  42. package/dist/ai-chatbot-launcher/ai-chatbot-launcher.mjs +224 -7
  43. package/dist/ai-chatbot-launcher/ai-chatbot-launcher.scss.mjs +1 -1
  44. package/dist/ai-embedded-chat/ai-embedded-chat.mjs +1 -0
  45. package/dist/ai-message-thread/ai-message-thread.d.ts +3 -2
  46. package/dist/ai-message-thread/ai-message-thread.mjs +36 -3
  47. package/dist/ai-steps/ai-steps.d.ts +67 -0
  48. package/dist/ai-steps/ai-steps.mjs +163 -0
  49. package/dist/ai-steps/ai-steps.scss.mjs +4 -0
  50. package/dist/ai-steps/index.d.ts +1 -0
  51. package/dist/ai-steps/index.mjs +5 -0
  52. package/dist/ai-tool-call-indicator/ai-tool-call-indicator.d.ts +2 -2
  53. package/dist/ai-tool-call-indicator/ai-tool-call-indicator.mjs +1 -1
  54. package/dist/core/canvas-controller.d.ts +81 -0
  55. package/dist/core/canvas-controller.mjs +221 -0
  56. package/dist/core/chatbot-core-controller.d.ts +4 -2
  57. package/dist/core/chatbot-core-controller.mjs +121 -4
  58. package/dist/core/index.d.ts +2 -1
  59. package/dist/core/index.mjs +2 -0
  60. package/dist/core/resize-controller.d.ts +5 -0
  61. package/dist/core/resize-controller.mjs +7 -5
  62. package/dist/index.d.ts +4 -0
  63. package/dist/index.mjs +15 -0
  64. package/dist/tools/ai-data-table/ai-data-table-definition.mjs +1 -0
  65. package/dist/tools/ai-mcp-app/ai-mcp-app.d.ts +70 -0
  66. package/dist/tools/ai-mcp-app/ai-mcp-app.mjs +589 -0
  67. package/dist/tools/ai-mcp-app/ai-mcp-app.scss.mjs +4 -0
  68. package/dist/tools/ai-mcp-app/index.d.ts +3 -0
  69. package/dist/tools/ai-mcp-app/index.mjs +6 -0
  70. package/dist/tools/ai-mcp-app/mcp-app-bridge-controller.d.ts +60 -0
  71. package/dist/tools/ai-mcp-app/mcp-app-bridge-controller.mjs +147 -0
  72. package/dist/tools/ai-mcp-app/mcp-app-bridge-types.d.ts +124 -0
  73. package/dist/tools/ai-mcp-app/mcp-app-bridge.d.ts +41 -0
  74. package/dist/tools/ai-mcp-app/mcp-app-bridge.mjs +293 -0
  75. package/dist/tools/ai-mcp-app/mcp-app-context.d.ts +46 -0
  76. package/dist/tools/ai-mcp-app/mcp-app-context.mjs +5 -0
  77. package/dist/tools/ai-steps/ai-steps-definition.d.ts +2 -0
  78. package/dist/tools/ai-steps/ai-steps-definition.mjs +51 -0
  79. package/dist/tools/ai-steps/ai-steps.d.ts +28 -0
  80. package/dist/tools/ai-steps/ai-steps.mjs +49 -0
  81. package/dist/tools/ai-steps/ai-steps.scss.mjs +4 -0
  82. package/dist/tools/ai-steps/index.d.ts +2 -0
  83. package/dist/tools/ai-steps/index.mjs +6 -0
  84. package/dist/tools/index.d.ts +1 -0
  85. package/dist/tools/index.mjs +5 -1
  86. package/dist/utils/inert-outside.d.ts +7 -0
  87. package/dist/utils/inert-outside.mjs +28 -0
  88. package/package.json +4 -1
@@ -0,0 +1,4 @@
1
+ const styles = '/* prettier-ignore */\n/**\n * @license\n * Copyright Tyler Technologies, Inc.\n * License: Apache-2.0\n */\n.forge-icon-button {\n --_icon-button-display:var(--forge-icon-button-display, inline-flex);\n --_icon-button-size:var(--forge-icon-button-size, 48px);\n --_icon-button-gap:var(--forge-icon-button-gap, 0);\n --_icon-button-icon-color:var(--forge-icon-button-icon-color, currentColor);\n --_icon-button-background-color:var(--forge-icon-button-background-color, none);\n --_icon-button-icon-size:var(--forge-icon-button-icon-size, calc(var(--forge-typography-font-size, 1rem) * 1.5));\n --_icon-button-cursor:var(--forge-icon-button-cursor, pointer);\n --_icon-button-padding:var(--forge-icon-button-padding, var(--forge-spacing-xxsmall, 4px));\n --_icon-button-border:var(--forge-icon-button-border, none);\n --_icon-button-shadow:var(--forge-icon-button-shadow, none);\n --_icon-button-transition-duration:var(--forge-icon-button-transition-duration, var(--forge-animation-duration-short3, 150ms));\n --_icon-button-transition-timing:var(--forge-icon-button-transition-timing, var(--forge-animation-easing-standard, cubic-bezier(0.2, 0, 0, 1)));\n --_icon-button-shape:var(--forge-icon-button-shape, calc(var(--forge-shape-full, 9999px) * var(--forge-shape-factor, 1)));\n --_icon-button-shape-start-start:var(--forge-icon-button-shape-start-start, var(--_icon-button-shape));\n --_icon-button-shape-start-end:var(--forge-icon-button-shape-start-end, var(--_icon-button-shape));\n --_icon-button-shape-end-start:var(--forge-icon-button-shape-end-start, var(--_icon-button-shape));\n --_icon-button-shape-end-end:var(--forge-icon-button-shape-end-end, var(--_icon-button-shape));\n --_icon-button-shape-squared:var(--forge-icon-button-shape-squared, calc(var(--forge-shape-medium, 4px) * var(--forge-shape-factor, 1)));\n --_icon-button-outlined-border-width:var(--forge-icon-button-outlined-border-width, 1px);\n --_icon-button-outlined-border-style:var(--forge-icon-button-outlined-border-style, solid);\n --_icon-button-outlined-border-color:var(--forge-icon-button-outlined-border-color, var(--_icon-button-icon-color));\n --_icon-button-tonal-icon-color:var(--forge-icon-button-tonal-icon-color, var(--forge-theme-on-primary-container, #222c62));\n --_icon-button-tonal-background-color:var(--forge-icon-button-tonal-background-color, var(--forge-theme-primary-container, #d1d5ed));\n --_icon-button-filled-icon-color:var(--forge-icon-button-filled-icon-color, var(--forge-theme-on-primary, #ffffff));\n --_icon-button-filled-background-color:var(--forge-icon-button-filled-background-color, var(--forge-theme-primary, #3f51b5));\n --_icon-button-raised-shadow:var(--forge-icon-button-raised-shadow, 0px 3px 1px -2px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12));\n --_icon-button-raised-hover-shadow:var(--forge-icon-button-raised-hover-shadow, 0px 2px 4px -1px rgba(0, 0, 0, 0.2), 0px 4px 5px 0px rgba(0, 0, 0, 0.14), 0px 1px 10px 0px rgba(0, 0, 0, 0.12));\n --_icon-button-raised-active-shadow:var(--forge-icon-button-raised-active-shadow, 0px 5px 5px -3px rgba(0, 0, 0, 0.2), 0px 8px 10px 1px rgba(0, 0, 0, 0.14), 0px 3px 14px 2px rgba(0, 0, 0, 0.12));\n --_icon-button-raised-disabled-shadow:var(--forge-icon-button-raised-disabled-shadow, none);\n --_icon-button-density-small-size:var(--forge-icon-button-density-small-size, 24px);\n --_icon-button-density-small-padding:var(--forge-icon-button-density-small-padding, var(--forge-spacing-xxxsmall, 2px));\n --_icon-button-density-small-icon-size:var(--forge-icon-button-density-small-icon-size, calc(var(--forge-typography-font-size, 1rem) * 1.125));\n --_icon-button-density-medium-size:var(--forge-icon-button-density-medium-size, 36px);\n --_icon-button-density-medium-padding:var(--forge-icon-button-density-medium-padding, var(--forge-spacing-xxsmall, 4px));\n --_icon-button-density-large-size:var(--forge-icon-button-density-large-size, var(--_icon-button-size));\n --_icon-button-toggle-on-background-color:var(--forge-icon-button-toggle-on-background-color, var(--forge-theme-primary-container, #d1d5ed));\n --_icon-button-toggle-on-icon-color:var(--forge-icon-button-toggle-on-icon-color, var(--forge-theme-primary, #3f51b5));\n --_icon-button-outlined-toggle-on-background-color:var(--forge-icon-button-outlined-toggle-on-background-color, var(--forge-theme-primary-container, #d1d5ed));\n --_icon-button-outlined-toggle-on-icon-color:var(--forge-icon-button-outlined-toggle-on-icon-color, var(--forge-theme-primary, #3f51b5));\n --_icon-button-tonal-toggle-background-color:var(--forge-icon-button-tonal-toggle-background-color, var(--forge-theme-surface-container-low, #ebebeb));\n --_icon-button-tonal-toggle-on-background-color:var(--forge-icon-button-tonal-toggle-on-background-color, var(--forge-theme-primary-container, #d1d5ed));\n --_icon-button-tonal-toggle-on-icon-color:var(--forge-icon-button-tonal-toggle-on-icon-color, var(--forge-theme-primary, #3f51b5));\n --_icon-button-filled-toggle-background-color:var(--forge-icon-button-filled-toggle-background-color, var(--forge-theme-surface-container-low, #ebebeb));\n --_icon-button-filled-toggle-icon-color:var(--forge-icon-button-filled-toggle-icon-color, var(--forge-theme-primary, #3f51b5));\n --_icon-button-filled-toggle-on-background-color:var(--forge-icon-button-filled-toggle-on-background-color, var(--forge-theme-primary, #3f51b5));\n --_icon-button-filled-toggle-on-icon-color:var(--forge-icon-button-filled-toggle-on-icon-color, var(--forge-theme-on-primary, #ffffff));\n --_icon-button-disabled-cursor:var(--forge-icon-button-disabled-cursor, not-allowed);\n --_icon-button-disabled-opacity:var(--forge-icon-button-disabled-opacity, 0.38);\n --_icon-button-popover-icon-padding:var(--forge-icon-button-popover-icon-padding, var(--forge-spacing-xsmall, 8px));\n --_icon-button-focus-indicator-color:var(--forge-icon-button-focus-indicator-color, var(--forge-theme-primary, #3f51b5));\n}\n\n.forge-icon-button {\n display: var(--_icon-button-display);\n position: relative;\n outline: none;\n -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n position: relative;\n z-index: 0;\n display: var(--_icon-button-display);\n align-items: center;\n justify-content: center;\n gap: var(--_icon-button-gap);\n box-sizing: border-box;\n height: var(--_icon-button-density-large-size);\n min-width: var(--_icon-button-density-large-size);\n border: var(--_icon-button-border);\n border-start-start-radius: var(--_icon-button-shape-start-start);\n border-start-end-radius: var(--_icon-button-shape-start-end);\n border-end-start-radius: var(--_icon-button-shape-end-start);\n border-end-end-radius: var(--_icon-button-shape-end-end);\n padding: var(--_icon-button-padding);\n box-shadow: var(--_icon-button-shadow);\n color: var(--_icon-button-icon-color);\n background: var(--_icon-button-background-color);\n font-size: var(--_icon-button-icon-size);\n cursor: var(--_icon-button-cursor);\n user-select: none;\n transition-property: box-shadow, background;\n transition-duration: var(--_icon-button-transition-duration);\n transition-timing-function: var(--_icon-button-transition-timing);\n}\n\n.forge-icon-button img, .forge-icon-button svg {\n height: var(--_icon-button-icon-size);\n width: var(--_icon-button-icon-size);\n}\n\n.forge-icon-button svg {\n fill: currentColor;\n}\n\n.forge-icon-button:not(:disabled) {\n --_state-layer-display:var(--forge-state-layer-display, flex);\n --_state-layer-color:var(--forge-state-layer-color, var(--forge-theme-on-surface, #000000));\n --_state-layer-hover-color:var(--forge-state-layer-hover-color, var(--_state-layer-color));\n --_state-layer-hover-opacity:var(--forge-state-layer-hover-opacity, 0.08);\n --_state-layer-pressed-color:var(--forge-state-layer-pressed-color, var(--_state-layer-color));\n --_state-layer-pressed-opacity:var(--forge-state-layer-pressed-opacity, 0.12);\n --_state-layer-hover-duration:var(--forge-state-layer-hover-duration, 15ms);\n --_state-layer-pressed-duration:var(--forge-state-layer-pressed-duration, 105ms);\n --_state-layer-animation-duration:var(--forge-state-layer-animation-duration, 375ms);\n}\n\n.forge-icon-button:not(:disabled)::before {\n opacity: 0;\n position: absolute;\n backface-visibility: hidden;\n transform: translateZ(0);\n background-color: var(--_state-layer-hover-color);\n inset: 0;\n transition: opacity var(--_state-layer-hover-duration) linear, background-color var(--_state-layer-hover-duration) linear;\n --_state-layer-hover-duration:var(--forge-state-layer-hover-duration, 100ms);\n content: "";\n opacity: 0;\n border-radius: inherit;\n}\n\n.forge-icon-button:not(:disabled):hover::before {\n background-color: var(--_state-layer-hover-color);\n opacity: var(--_state-layer-hover-opacity);\n}\n\n.forge-icon-button:not(:disabled):active::before {\n opacity: var(--_state-layer-pressed-opacity);\n transition-duration: var(--_state-layer-pressed-duration);\n --_state-layer-pressed-opacity:var(--forge-state-layer-pressed-opacity, 0.18);\n}\n\n.forge-icon-button:not(:disabled) {\n --forge-state-layer-color: var(--_icon-button-icon-color);\n}\n\n@keyframes forge-focus-indicator-outward-grow {\n from {\n outline-width: 0;\n }\n to {\n outline-width: var(--_focus-indicator-active-width);\n }\n}\n@keyframes forge-focus-indicator-outward-shrink {\n from {\n outline-width: var(--_focus-indicator-active-width);\n }\n}\n@keyframes forge-focus-indicator-inward-grow {\n from {\n border-width: 0;\n }\n to {\n border-width: var(--_focus-indicator-active-width);\n }\n}\n@keyframes forge-focus-indicator-inward-shrink {\n from {\n border-width: var(--_focus-indicator-active-width);\n }\n}\n.forge-icon-button:not(:disabled) {\n outline: none;\n}\n\n.forge-icon-button:not(:disabled):focus-visible::after {\n --_focus-indicator-display:var(--forge-focus-indicator-display, flex);\n --_focus-indicator-width:var(--forge-focus-indicator-width, var(--forge-border-medium, 2px));\n --_focus-indicator-active-width:var(--forge-focus-indicator-active-width, 6px);\n --_focus-indicator-color:var(--forge-focus-indicator-color, var(--forge-theme-primary, #3f51b5));\n --_focus-indicator-shape:var(--forge-focus-indicator-shape, calc(var(--forge-shape-extra-small, 1px) * var(--forge-shape-factor, 1)));\n --_focus-indicator-duration:var(--forge-focus-indicator-duration, var(--forge-animation-duration-long4, 600ms));\n --_focus-indicator-easing:var(--forge-focus-indicator-easing, var(--forge-animation-easing-emphasized, cubic-bezier(0.2, 0, 0, 1)));\n --_focus-indicator-shape-start-start:var(--forge-focus-indicator-shape-start-start, var(--_focus-indicator-shape));\n --_focus-indicator-shape-start-end:var(--forge-focus-indicator-shape-start-end, var(--_focus-indicator-shape));\n --_focus-indicator-shape-end-end:var(--forge-focus-indicator-shape-end-end, var(--_focus-indicator-shape));\n --_focus-indicator-shape-end-start:var(--forge-focus-indicator-shape-end-start, var(--_focus-indicator-shape));\n --_focus-indicator-outward-offset:var(--forge-focus-indicator-outward-offset, var(--forge-spacing-xxsmall, 4px));\n --_focus-indicator-inward-offset:var(--forge-focus-indicator-inward-offset, 0px);\n --_focus-indicator-offset-block:var(--forge-focus-indicator-offset-block, 0);\n --_focus-indicator-offset-inline:var(--forge-focus-indicator-offset-inline, 0);\n}\n\n.forge-icon-button:not(:disabled):focus-visible::after {\n animation-delay: 0s, calc(var(--_focus-indicator-duration) * 0.25);\n animation-duration: calc(var(--_focus-indicator-duration) * 0.25), calc(var(--_focus-indicator-duration) * 0.75);\n animation-timing-function: var(--_focus-indicator-easing);\n box-sizing: border-box;\n color: var(--_focus-indicator-color);\n display: none;\n pointer-events: none;\n position: absolute;\n margin-block: var(--_focus-indicator-offset-block);\n margin-inline: var(--_focus-indicator-offset-inline);\n animation-name: forge-focus-indicator-outward-grow, forge-focus-indicator-outward-shrink;\n border-end-end-radius: calc(var(--_focus-indicator-shape-end-end) + var(--_focus-indicator-outward-offset));\n border-end-start-radius: calc(var(--_focus-indicator-shape-end-start) + var(--_focus-indicator-outward-offset));\n border-start-end-radius: calc(var(--_focus-indicator-shape-start-end) + var(--_focus-indicator-outward-offset));\n border-start-start-radius: calc(var(--_focus-indicator-shape-start-start) + var(--_focus-indicator-outward-offset));\n inset: calc(-1 * var(--_focus-indicator-outward-offset));\n outline: var(--_focus-indicator-width) solid currentColor;\n content: "";\n display: block;\n}\n\n.forge-icon-button:not(:disabled) {\n --forge-focus-indicator-color: var(--_icon-button-focus-indicator-color);\n --forge-focus-indicator-shape: var(--_icon-button-shape);\n}\n\n.forge-icon-button:not(:disabled):where(.forge-icon-button--text, :not(:where(.forge-icon-button--outlined, .forge-icon-button--tonal, .forge-icon-button--filled, .forge-icon-button--raised))) {\n --forge-focus-indicator-outward-offset: 0px;\n}\n\n.forge-icon-button--outlined {\n border-width: var(--_icon-button-outlined-border-width);\n border-style: var(--_icon-button-outlined-border-style);\n border-color: var(--_icon-button-outlined-border-color);\n}\n\n.forge-icon-button--tonal {\n --_icon-button-icon-color:var(--_icon-button-tonal-icon-color);\n --_icon-button-background-color:var(--_icon-button-tonal-background-color);\n}\n\n.forge-icon-button--filled, .forge-icon-button--raised {\n --_icon-button-icon-color:var(--_icon-button-filled-icon-color);\n --_icon-button-background-color:var(--_icon-button-filled-background-color);\n}\n\n.forge-icon-button--raised {\n --_icon-button-shadow:var(--_icon-button-raised-shadow);\n}\n\n.forge-icon-button--raised:hover {\n --_icon-button-raised-shadow:var(--_icon-button-raised-hover-shadow);\n}\n\n.forge-icon-button--raised:active {\n --_icon-button-raised-shadow:var(--_icon-button-raised-active-shadow);\n}\n\n.forge-icon-button--squared {\n --_icon-button-shape:var(--_icon-button-shape-squared);\n}\n\n.forge-icon-button--small {\n --_icon-button-size:var(--_icon-button-density-small-size);\n --_icon-button-icon-size:var(--_icon-button-density-small-icon-size);\n --_icon-button-padding:var(--_icon-button-density-small-padding);\n}\n\n.forge-icon-button--small > * {\n font-size: var(--_icon-button-density-small-icon-size);\n}\n\n.forge-icon-button--medium {\n --_icon-button-size:var(--_icon-button-density-medium-size);\n --_icon-button-padding:var(--_icon-button-density-medium-padding);\n}\n\n.forge-icon-button:disabled {\n pointer-events: none;\n opacity: var(--_icon-button-disabled-opacity);\n pointer-events: auto;\n cursor: not-allowed;\n}\n\n.forge-icon-button forge-circular-progress {\n --forge-circular-progress-indicator-color: var(--_icon-button-icon-color);\n --forge-circular-progress-track-color: transparent;\n --forge-circular-progress-size: 1em;\n}\n\n/**\n * @license\n * Copyright Tyler Technologies, Inc.\n * License: Apache-2.0\n */\n@keyframes forge-skeleton-loading {\n 25%, 100% {\n transform: translateX(100%);\n }\n}\n.forge-skeleton {\n --_skeleton-animation-duration:var(--forge-skeleton-animation-duration, 1500ms);\n --_skeleton-width:var(--forge-skeleton-width, auto);\n --_skeleton-height:var(--forge-skeleton-height, 48px);\n --_skeleton-background:var(--forge-skeleton-background, var(--forge-theme-surface-container, #e0e0e0));\n --_skeleton-shape:var(--forge-skeleton-shape, calc(var(--forge-shape-medium, 4px) * var(--forge-shape-factor, 1)));\n --_skeleton-margin:var(--forge-skeleton-margin, var(--forge-spacing-medium, 16px) 0);\n --_skeleton-button-height:var(--forge-skeleton-button-height, var(--forge-button-height, 36px));\n --_skeleton-button-width:var(--forge-skeleton-button-width, 72px);\n --_skeleton-form-field-height:var(--forge-skeleton-form-field-height, 40px);\n --_skeleton-form-field-width:var(--forge-skeleton-form-field-width, 256px);\n --_skeleton-chip-height:var(--forge-skeleton-chip-height, 32px);\n --_skeleton-chip-width:var(--forge-skeleton-chip-width, 72px);\n --_skeleton-chip-shape:var(--forge-skeleton-chip-shape, calc(var(--forge-shape-extra-large, 16px) * var(--forge-shape-factor, 1)));\n --_skeleton-list-item-height:var(--forge-skeleton-list-item-height, 32px);\n --_skeleton-list-item-margin:var(--forge-skeleton-list-item-margin, 12px 8px);\n --_skeleton-text-height:var(--forge-skeleton-text-height, 1rem);\n --_skeleton-gradient-color:var(--forge-skeleton-gradient-color, var(--forge-theme-surface-container-low, #ebebeb));\n --_skeleton-avatar-size:var(--forge-skeleton-avatar-size, var(--forge-avatar-size, 40px));\n --_skeleton-avatar-shape:var(--forge-skeleton-avatar-shape, var(--forge-avatar-shape, calc(var(--forge-shape-round, 50%) * var(--forge-shape-factor, 1))));\n}\n\n.forge-skeleton {\n height: var(--_skeleton-height);\n width: var(--_skeleton-width);\n margin: var(--_skeleton-margin);\n border-radius: var(--_skeleton-shape);\n background-color: var(--_skeleton-background);\n position: relative;\n display: block;\n overflow: hidden;\n box-sizing: border-box;\n display: block;\n}\n\n.forge-skeleton::after {\n position: absolute;\n display: block;\n width: 100%;\n height: 100%;\n transform: translateX(-100%);\n background-repeat: no-repeat;\n background-image: linear-gradient(90deg, transparent, var(--_skeleton-gradient-color), transparent);\n animation: forge-skeleton-loading var(--_skeleton-animation-duration) ease-in infinite;\n content: "";\n}\n\n.forge-skeleton--avatar {\n --_skeleton-height:var(--_skeleton-avatar-size);\n --_skeleton-width:var(--_skeleton-avatar-size);\n --_skeleton-shape:var(--_skeleton-avatar-shape);\n}\n\n.forge-skeleton--list-item {\n --_skeleton-height:var(--_skeleton-list-item-height);\n --_skeleton-margin:var(--_skeleton-list-item-margin);\n}\n\n.forge-skeleton--text {\n --_skeleton-height:var(--_skeleton-text-height);\n}\n\n.forge-skeleton--chip {\n --_skeleton-height:var(--_skeleton-chip-height);\n --_skeleton-width:var(--_skeleton-chip-width);\n --_skeleton-shape:var(--_skeleton-chip-shape);\n}\n\n.forge-skeleton--button {\n --_skeleton-height:var(--_skeleton-button-height);\n --_skeleton-width:var(--_skeleton-button-width);\n}\n\n.forge-skeleton--form-field {\n --_skeleton-height:var(--_skeleton-form-field-height);\n --_skeleton-width:var(--_skeleton-form-field-width);\n}\n\n:host {\n display: block;\n margin-block: var(--forge-spacing-medium, 16px);\n --_mcp-host-color-background-primary: var(--forge-theme-surface, #ffffff);\n --_mcp-host-color-background-secondary: var(--forge-theme-surface-container-minimum, #f5f5f5);\n --_mcp-host-color-background-tertiary: var(--forge-theme-surface-container-low, #ebebeb);\n --_mcp-host-color-background-inverse: var(--forge-theme-surface-inverse, #333333);\n --_mcp-host-color-background-info: var(--forge-theme-info-container-minimum, #f6f9fc);\n --_mcp-host-color-background-danger: var(--forge-theme-error-container-minimum, #fcf5f6);\n --_mcp-host-color-background-success: var(--forge-theme-success-container-minimum, #f7faf7);\n --_mcp-host-color-background-warning: var(--forge-theme-warning-container-minimum, #fdf8f5);\n --_mcp-host-color-text-primary: var(--forge-theme-text-high, rgba(0, 0, 0, 0.87));\n --_mcp-host-color-text-secondary: var(--forge-theme-text-medium, rgba(0, 0, 0, 0.6));\n --_mcp-host-color-text-tertiary: var(--forge-theme-text-low, rgba(0, 0, 0, 0.38));\n --_mcp-host-color-text-inverse: var(--forge-theme-on-surface-inverse, #ffffff);\n --_mcp-host-color-text-info: var(--forge-theme-info, #1565c0);\n --_mcp-host-color-text-danger: var(--forge-theme-error, #b00020);\n --_mcp-host-color-text-success: var(--forge-theme-success, #2e7d32);\n --_mcp-host-color-text-warning: var(--forge-theme-warning, #d14900);\n --_mcp-host-color-text-disabled: var(--forge-theme-text-lowest, rgba(0, 0, 0, 0.12));\n --_mcp-host-color-border-primary: var(--forge-theme-outline, #e0e0e0);\n --_mcp-host-color-border-secondary: var(--forge-theme-outline-low, #9e9e9e);\n --_mcp-host-color-border-info: var(--forge-theme-info, #1565c0);\n --_mcp-host-color-border-danger: var(--forge-theme-error, #b00020);\n --_mcp-host-color-border-success: var(--forge-theme-success, #2e7d32);\n --_mcp-host-color-border-warning: var(--forge-theme-warning, #d14900);\n --_mcp-host-color-ring-primary: var(--forge-theme-primary, #3f51b5);\n --_mcp-host-font-sans: var(--forge-typography-body2-font-family, var(--forge-typography-font-family, "Roboto", sans-serif));\n --_mcp-host-font-weight-normal: 400;\n --_mcp-host-font-weight-medium: 500;\n --_mcp-host-font-weight-bold: 700;\n --_mcp-host-font-text-xs-size: var(--forge-typography-label1-font-size, calc(var(--forge-typography-font-size, 1rem) * var(--forge-typography-label-font-size-scale, 0.75)));\n --_mcp-host-font-text-sm-size: var(--forge-typography-body1-font-size, calc(var(--forge-typography-font-size, 1rem) * var(--forge-typography-body-font-size-scale, 0.875)));\n --_mcp-host-font-text-md-size: var(--forge-typography-body2-font-size, calc(var(--forge-typography-font-size, 1rem) * var(--forge-typography-body-font-size-scale, 1)));\n --_mcp-host-font-text-lg-size: var(--forge-typography-body3-font-size, calc(var(--forge-typography-font-size, 1rem) * var(--forge-typography-body-font-size-scale, 1.125)));\n --_mcp-host-font-text-xs-line-height: var(--forge-typography-label1-line-height, calc(var(--forge-typography-font-size, 1rem) * var(--forge-typography-label-line-height-scale, 1.25)));\n --_mcp-host-font-text-sm-line-height: var(--forge-typography-body1-line-height, calc(var(--forge-typography-font-size, 1rem) * var(--forge-typography-body-line-height-scale, 1.125)));\n --_mcp-host-font-text-md-line-height: var(--forge-typography-body2-line-height, calc(var(--forge-typography-font-size, 1rem) * var(--forge-typography-body-line-height-scale, 1.375)));\n --_mcp-host-font-text-lg-line-height: var(--forge-typography-body3-line-height, calc(var(--forge-typography-font-size, 1rem) * var(--forge-typography-body-line-height-scale, 1.5)));\n --_mcp-host-font-heading-sm-size: var(--forge-typography-heading1-font-size, calc(var(--forge-typography-font-size, 1rem) * var(--forge-typography-heading1-font-size-scale, 0.875)));\n --_mcp-host-font-heading-md-size: var(--forge-typography-heading2-font-size, calc(var(--forge-typography-font-size, 1rem) * var(--forge-typography-heading2-font-size-scale, 1)));\n --_mcp-host-font-heading-lg-size: var(--forge-typography-heading4-font-size, calc(var(--forge-typography-font-size, 1rem) * var(--forge-typography-heading4-font-size-scale, 1.25)));\n --_mcp-host-font-heading-xl-size: var(--forge-typography-heading5-font-size, calc(var(--forge-typography-font-size, 1rem) * var(--forge-typography-heading5-font-size-scale, 1.5)));\n --_mcp-host-font-heading-2xl-size: var(--forge-typography-heading7-font-size, calc(var(--forge-typography-font-size, 1rem) * var(--forge-typography-heading7-font-size-scale, 2)));\n --_mcp-host-font-heading-3xl-size: var(--forge-typography-heading8-font-size, calc(var(--forge-typography-font-size, 1rem) * var(--forge-typography-heading8-font-size-scale, 2.25)));\n --_mcp-host-font-heading-sm-line-height: var(--forge-typography-heading1-line-height, calc(var(--forge-typography-font-size, 1rem) * var(--forge-typography-heading1-line-height-scale, 1.125)));\n --_mcp-host-font-heading-md-line-height: var(--forge-typography-heading2-line-height, calc(var(--forge-typography-font-size, 1rem) * var(--forge-typography-heading2-line-height-scale, 1.25)));\n --_mcp-host-font-heading-lg-line-height: var(--forge-typography-heading4-line-height, calc(var(--forge-typography-font-size, 1rem) * var(--forge-typography-heading4-line-height-scale, 1.5)));\n --_mcp-host-font-heading-xl-line-height: var(--forge-typography-heading5-line-height, calc(var(--forge-typography-font-size, 1rem) * var(--forge-typography-heading5-line-height-scale, 1.75)));\n --_mcp-host-font-heading-2xl-line-height: var(--forge-typography-heading7-line-height, calc(var(--forge-typography-font-size, 1rem) * var(--forge-typography-heading7-line-height-scale, 2.5)));\n --_mcp-host-font-heading-3xl-line-height: var(--forge-typography-heading8-line-height, calc(var(--forge-typography-font-size, 1rem) * var(--forge-typography-heading8-line-height-scale, 2.625)));\n --_mcp-host-border-radius-xs: calc(var(--forge-shape-extra-small, 1px) * var(--forge-shape-factor, 1));\n --_mcp-host-border-radius-sm: calc(var(--forge-shape-small, 2px) * var(--forge-shape-factor, 1));\n --_mcp-host-border-radius-md: calc(var(--forge-shape-medium, 4px) * var(--forge-shape-factor, 1));\n --_mcp-host-border-radius-lg: calc(var(--forge-shape-large, 8px) * var(--forge-shape-factor, 1));\n --_mcp-host-border-radius-xl: calc(var(--forge-shape-extra-large, 16px) * var(--forge-shape-factor, 1));\n --_mcp-host-border-radius-full: calc(var(--forge-shape-full, 9999px) * var(--forge-shape-factor, 1));\n --_mcp-host-border-width-regular: var(--forge-border-thin, 1px);\n --_mcp-host-shadow-sm: 0px 2px 1px -1px rgba(0, 0, 0, 0.2), 0px 1px 1px 0px rgba(0, 0, 0, 0.14), 0px 1px 3px 0px rgba(0, 0, 0, 0.12);\n --_mcp-host-shadow-md: 0px 2px 4px -1px rgba(0, 0, 0, 0.2), 0px 4px 5px 0px rgba(0, 0, 0, 0.14), 0px 1px 10px 0px rgba(0, 0, 0, 0.12);\n --_mcp-host-shadow-lg: 0px 5px 5px -3px rgba(0, 0, 0, 0.2), 0px 8px 10px 1px rgba(0, 0, 0, 0.14), 0px 3px 14px 2px rgba(0, 0, 0, 0.12);\n}\n\n.container {\n position: relative;\n inset: auto;\n margin: 0;\n width: 100%;\n height: 100%;\n display: block;\n padding: 0;\n border: none;\n background: inherit;\n color: inherit;\n}\n.container.bordered {\n border: 1px solid var(--forge-theme-outline, #e0e0e0);\n border-radius: calc(var(--forge-shape-large, 8px) * var(--forge-shape-factor, 1));\n overflow: hidden;\n}\n.container:popover-open {\n position: fixed;\n display: flex;\n flex-direction: column;\n background: var(--forge-theme-surface, #ffffff);\n color: var(--forge-theme-text-high, rgba(0, 0, 0, 0.87));\n}\n.container:popover-open iframe {\n flex: 1;\n min-height: 0;\n}\n.container.fullscreen:popover-open {\n inset: 0;\n width: 100vw;\n height: 100dvh;\n border: none;\n border-radius: 0;\n}\n.container.fullscreen:popover-open::backdrop {\n background: var(--forge-theme-surface, #ffffff);\n}\n.container.pip:popover-open {\n inset: auto;\n inset-block-end: var(--forge-spacing-medium, 16px);\n inset-inline-end: var(--forge-spacing-medium, 16px);\n width: min(360px, 100vw - 2 * var(--forge-spacing-medium, 16px));\n height: 280px;\n border: 1px solid var(--forge-theme-outline, #e0e0e0);\n border-radius: calc(var(--forge-shape-large, 8px) * var(--forge-shape-factor, 1));\n overflow: hidden;\n box-shadow: 0px 2px 4px -1px rgba(0, 0, 0, 0.2), 0px 4px 5px 0px rgba(0, 0, 0, 0.14), 0px 1px 10px 0px rgba(0, 0, 0, 0.12);\n}\n\n.loading .forge-skeleton {\n --forge-skeleton-height: 120px;\n --forge-skeleton-margin: 0;\n --forge-skeleton-shape: calc(var(--forge-shape-large, 8px) * var(--forge-shape-factor, 1));\n}\n\n.promoted-toolbar {\n display: flex;\n justify-content: flex-end;\n flex: none;\n padding: var(--forge-spacing-xxsmall, 4px);\n border-block-end: 1px solid var(--forge-theme-outline, #e0e0e0);\n}\n\n.exit-button,\n.exit-button > svg {\n fill: var(--forge-theme-text-medium, rgba(0, 0, 0, 0.6));\n}\n\niframe {\n display: block;\n border: 0;\n width: 100%;\n height: 100%;\n}\n\n.error-icon {\n width: 48px;\n height: 48px;\n fill: var(--forge-theme-outline, #e0e0e0);\n}';
2
+ export {
3
+ styles as default
4
+ };
@@ -0,0 +1,3 @@
1
+ export * from './ai-mcp-app.js';
2
+ export * from './mcp-app-context.js';
3
+ export * from './mcp-app-bridge-types.js';
@@ -0,0 +1,6 @@
1
+ import { McpAppToolElement } from "./ai-mcp-app.mjs";
2
+ import { mcpAppHostContext } from "./mcp-app-context.mjs";
3
+ export {
4
+ McpAppToolElement,
5
+ mcpAppHostContext
6
+ };
@@ -0,0 +1,60 @@
1
+ import { McpAppHostCapabilities, McpAppHostContext, McpAppResourceCsp, McpAppResourcePermissions, ToolCall } from '../../ai-chatbot';
2
+ import { IMcpAppBridge, McpAppViewToolResult } from './mcp-app-bridge-types.js';
3
+ /**
4
+ * The view→host handler slots the element supplies; registered on the bridge BEFORE
5
+ * `connect()` so they are live for the very first widget request.
6
+ */
7
+ export type McpAppHandlers = Pick<IMcpAppBridge, 'oncalltool' | 'onreadresource' | 'onopenlink' | 'onmessage' | 'onloggingmessage' | 'onsizechange' | 'onrequestdisplaymode' | 'onupdatemodelcontext' | 'onrequestteardown'>;
8
+ export interface McpAppConnectConfig {
9
+ iframe: HTMLIFrameElement;
10
+ sandboxUrl: string;
11
+ html: string;
12
+ hostContext: McpAppHostContext;
13
+ hostCapabilities: McpAppHostCapabilities;
14
+ csp: McpAppResourceCsp;
15
+ permissions: McpAppResourcePermissions;
16
+ sandbox?: string;
17
+ handlers: McpAppHandlers;
18
+ }
19
+ /**
20
+ * Serialize the declared CSP domains for the sandbox `?csp=` param. The sandbox origin
21
+ * builds the actual CSP header from these; empty lists are omitted.
22
+ */
23
+ export declare function buildCspParam(csp: McpAppResourceCsp): string;
24
+ /**
25
+ * The requested permissions the sandbox can enforce, normalized to the spec shape. A key
26
+ * is requested when present (`{ camera: {} }`); `false`/`null` values are ignored.
27
+ */
28
+ export declare function enforcedPermissions(permissions: McpAppResourcePermissions): McpAppResourcePermissions;
29
+ /** Map requested permissions onto the iframe `allow` attribute. */
30
+ export declare function buildAllowAttribute(permissions: McpAppResourcePermissions): string;
31
+ /**
32
+ * Build the View's `CallToolResult` from the raw MCP result + structured content — never
33
+ * from the model-facing `result`. When the backend omitted a field (size caps) the View
34
+ * gets what remains; when both are missing it gets an empty `content` array, flagged
35
+ * `isError` only if the tool call itself errored.
36
+ */
37
+ export declare function buildViewToolResult(toolCall: ToolCall): McpAppViewToolResult;
38
+ /**
39
+ * Drives an {@link IMcpAppBridge} through the sandbox handshake and the streaming
40
+ * tool-call lifecycle. Bridge-agnostic — talks to the interface only.
41
+ *
42
+ * The controller owns the OUTER sandbox iframe DOM (its `src` with the `?csp=` param and
43
+ * its `allow` attribute); the bridge owns the postMessage lifecycle.
44
+ */
45
+ export declare class McpAppBridgeController {
46
+ #private;
47
+ constructor(bridge: IMcpAppBridge);
48
+ connect(config: McpAppConnectConfig): Promise<void>;
49
+ /**
50
+ * Reconcile the widget with the current tool-call state. Streams partial args, sends
51
+ * final args once, then exactly one of `tool-result` (complete/error) or
52
+ * `tool-cancelled` — all gated on the `initialized` handshake. Safe to call on every
53
+ * `toolCall` update.
54
+ */
55
+ syncToolCall(toolCall: ToolCall): void;
56
+ /** Forward a host-context change; the bridge holds it until the View is initialized. */
57
+ sendHostContextChange(hostContext: McpAppHostContext): void;
58
+ /** Send `ui/resource-teardown` and release the bridge; the iframe is removed without waiting for the ack. */
59
+ teardown(): void;
60
+ }
@@ -0,0 +1,147 @@
1
+ const PERMISSION_FEATURES = {
2
+ camera: "camera",
3
+ microphone: "microphone",
4
+ geolocation: "geolocation",
5
+ clipboardWrite: "clipboard-write"
6
+ };
7
+ const UNSAFE_CSP_SOURCE = /[\s;,'"]/;
8
+ const CSP_PARAM_KEYS = ["connectDomains", "resourceDomains", "frameDomains", "baseUriDomains"];
9
+ function buildCspParam(csp) {
10
+ const declared = {};
11
+ for (const key of CSP_PARAM_KEYS) {
12
+ const safe = (csp[key] ?? []).filter((domain) => !!domain && !UNSAFE_CSP_SOURCE.test(domain));
13
+ if (safe.length) {
14
+ declared[key] = safe;
15
+ }
16
+ }
17
+ return JSON.stringify(declared);
18
+ }
19
+ function enforcedPermissions(permissions) {
20
+ const keys = Object.keys(PERMISSION_FEATURES).filter((key) => {
21
+ const value = permissions[key];
22
+ return value !== void 0 && value !== null && value !== false;
23
+ });
24
+ return Object.fromEntries(keys.map((key) => [key, {}]));
25
+ }
26
+ function buildAllowAttribute(permissions) {
27
+ return Object.keys(enforcedPermissions(permissions)).map((key) => PERMISSION_FEATURES[key]).join("; ");
28
+ }
29
+ function buildViewToolResult(toolCall) {
30
+ const mcpResult = toolCall.mcpResultOmitted ? void 0 : toolCall.mcpResult;
31
+ const structuredContent = toolCall.structuredContentOmitted ? void 0 : toolCall.structuredContent;
32
+ const isError = mcpResult?.isError ?? (toolCall.status === "error" || void 0);
33
+ return {
34
+ content: Array.isArray(mcpResult?.content) ? mcpResult.content : [],
35
+ ...structuredContent !== void 0 ? { structuredContent } : {},
36
+ ...isError !== void 0 ? { isError } : {},
37
+ ...mcpResult?._meta !== void 0 ? { _meta: mcpResult._meta } : {}
38
+ };
39
+ }
40
+ class McpAppBridgeController {
41
+ #bridge;
42
+ #connected = null;
43
+ #lastArgsSent = null;
44
+ #inputSent = false;
45
+ #outcome = "pending";
46
+ constructor(bridge) {
47
+ this.#bridge = bridge;
48
+ }
49
+ connect(config) {
50
+ if (this.#connected) {
51
+ return this.#connected;
52
+ }
53
+ Object.assign(this.#bridge, config.handlers);
54
+ const { iframe, sandboxUrl, csp, permissions } = config;
55
+ const outerAllow = buildAllowAttribute(permissions);
56
+ if (outerAllow) {
57
+ iframe.setAttribute("allow", outerAllow);
58
+ } else {
59
+ iframe.removeAttribute("allow");
60
+ }
61
+ const sandboxWindow = iframe.contentWindow;
62
+ if (!sandboxWindow) {
63
+ return Promise.reject(new Error("sandbox iframe has no contentWindow"));
64
+ }
65
+ let sandboxOrigin;
66
+ try {
67
+ sandboxOrigin = new URL(sandboxUrl, window.location.href).origin;
68
+ } catch {
69
+ return Promise.reject(new Error(`invalid sandbox URL: ${sandboxUrl}`));
70
+ }
71
+ if (sandboxOrigin === "null" || sandboxOrigin === window.location.origin) {
72
+ return Promise.reject(new Error("sandbox URL must be on a distinct, non-opaque origin"));
73
+ }
74
+ this.#connected = this.#bridge.connect({
75
+ sandboxWindow,
76
+ sandboxOrigin,
77
+ html: config.html,
78
+ hostContext: config.hostContext,
79
+ hostCapabilities: config.hostCapabilities,
80
+ permissions: enforcedPermissions(permissions),
81
+ sandbox: config.sandbox
82
+ });
83
+ const separator = sandboxUrl.includes("?") ? "&" : "?";
84
+ iframe.src = `${sandboxUrl}${separator}csp=${encodeURIComponent(buildCspParam(csp))}`;
85
+ return this.#connected;
86
+ }
87
+ /**
88
+ * Reconcile the widget with the current tool-call state. Streams partial args, sends
89
+ * final args once, then exactly one of `tool-result` (complete/error) or
90
+ * `tool-cancelled` — all gated on the `initialized` handshake. Safe to call on every
91
+ * `toolCall` update.
92
+ */
93
+ syncToolCall(toolCall) {
94
+ if (!this.#connected || this.#outcome !== "pending") {
95
+ return;
96
+ }
97
+ void this.#connected.then(() => {
98
+ if (this.#outcome !== "pending") {
99
+ return;
100
+ }
101
+ if (toolCall.status === "cancelled") {
102
+ this.#outcome = "cancel-sent";
103
+ this.#bridge.sendToolCancelled();
104
+ return;
105
+ }
106
+ const partialArgs = this.#coerceArgs(toolCall.args);
107
+ const partialString = JSON.stringify(partialArgs);
108
+ if (!this.#inputSent && Object.keys(partialArgs).length && partialString !== this.#lastArgsSent) {
109
+ this.#lastArgsSent = partialString;
110
+ this.#bridge.sendToolInputPartial(partialArgs);
111
+ }
112
+ const isFinished = toolCall.status === "complete" || toolCall.status === "error";
113
+ if ((toolCall.status === "executing" || isFinished) && !this.#inputSent) {
114
+ this.#inputSent = true;
115
+ this.#bridge.sendToolInput(this.#coerceArgs(toolCall.args));
116
+ }
117
+ if (isFinished) {
118
+ this.#outcome = "result-sent";
119
+ this.#bridge.sendToolResult(buildViewToolResult(toolCall));
120
+ }
121
+ });
122
+ }
123
+ /** Forward a host-context change; the bridge holds it until the View is initialized. */
124
+ sendHostContextChange(hostContext) {
125
+ if (this.#connected) {
126
+ this.#bridge.sendHostContextChange(hostContext);
127
+ }
128
+ }
129
+ /** Send `ui/resource-teardown` and release the bridge; the iframe is removed without waiting for the ack. */
130
+ teardown() {
131
+ if (!this.#connected) {
132
+ return;
133
+ }
134
+ this.#outcome = "torn-down";
135
+ this.#bridge.sendTeardown();
136
+ }
137
+ #coerceArgs(args) {
138
+ return args && typeof args === "object" ? args : {};
139
+ }
140
+ }
141
+ export {
142
+ McpAppBridgeController,
143
+ buildAllowAttribute,
144
+ buildCspParam,
145
+ buildViewToolResult,
146
+ enforcedPermissions
147
+ };
@@ -0,0 +1,124 @@
1
+ import { McpAppDisplayMode, McpAppHostCapabilities, McpAppHostContext, McpAppResourcePermissions, McpModelContextUpdateParams, McpResourceReadParams, McpToolCallParams, McpToolResult } from '../../ai-chatbot';
2
+ /**
3
+ * The host-side bridge surface `mcp-app-bridge.ts` (`McpAppBridge`) implements. The
4
+ * element + controller depend on this interface only.
5
+ */
6
+ /**
7
+ * A View's `tools/call` as received by the bridge. The bridge has no widget identity;
8
+ * the element adds its `toolCallId` before forwarding to the host.
9
+ */
10
+ export type McpAppToolCallRequest = Omit<McpToolCallParams, 'toolCallId'>;
11
+ /** A View's `resources/read` as received by the bridge (no widget identity). */
12
+ export type McpAppResourceReadRequest = Omit<McpResourceReadParams, 'toolCallId'>;
13
+ /** The `CallToolResult` delivered to the View via `ui/notifications/tool-result`. */
14
+ export interface McpAppViewToolResult extends McpToolResult {
15
+ structuredContent?: unknown;
16
+ }
17
+ /** Parameters a widget passes to `ui/open-link`. */
18
+ export interface McpAppOpenLinkParams {
19
+ url: string;
20
+ }
21
+ /**
22
+ * Result of a View request the host may decline (`ui/open-link`, `ui/message`): `{}` on
23
+ * success, `{ isError: true }` when the host refused or could not deliver it.
24
+ */
25
+ export interface McpAppRequestResult {
26
+ isError?: boolean;
27
+ }
28
+ /** Parameters a widget passes to `ui/message`. `role` is always `user` (never trusted from the View). */
29
+ export interface McpAppMessageParams {
30
+ /** The View's MCP content blocks, unvalidated. */
31
+ content: unknown[];
32
+ role: 'user';
33
+ }
34
+ /** Parameters a widget passes to `ui/update-model-context` (no widget identity). */
35
+ export type McpAppUpdateModelContextParams = Omit<McpModelContextUpdateParams, 'toolCallId'>;
36
+ /** Parameters a widget passes to `ui/request-display-mode`. */
37
+ export interface McpAppRequestDisplayModeParams {
38
+ mode: McpAppDisplayMode;
39
+ /** Modes the View declared in `ui/initialize` (`appCapabilities.availableDisplayModes`). */
40
+ appDisplayModes: McpAppDisplayMode[];
41
+ }
42
+ /** Result the host returns for a display-mode request — echoes the mode actually set. */
43
+ export interface McpAppRequestDisplayModeResult {
44
+ mode: McpAppDisplayMode;
45
+ }
46
+ /** Payload for a widget `notifications/message` (logging). */
47
+ export interface McpAppLoggingMessage {
48
+ level: string;
49
+ data?: unknown;
50
+ logger?: string;
51
+ }
52
+ /** Payload for a widget `size-changed` notification. */
53
+ export interface McpAppSizeChange {
54
+ width?: number;
55
+ height: number;
56
+ }
57
+ /**
58
+ * Config for the `ui/initialize` handshake and injecting the resource into the sandbox.
59
+ *
60
+ * The controller owns the outer sandbox iframe DOM (setting `src` with the `?csp=` query
61
+ * param, JSON of the declared CSP domain lists that the sandbox origin turns into the CSP
62
+ * header, + the outer `allow` attribute); it hands the bridge the loaded iframe's
63
+ * `contentWindow` so the bridge can scope its transport to that window and drive the
64
+ * `sandbox-proxy-ready` → `sandbox-resource-ready` → `initialized` handshake. All fields
65
+ * are bridge-agnostic (no ext-apps types leak through this surface).
66
+ */
67
+ export interface McpAppBridgeConnectConfig {
68
+ /** The loaded outer sandbox proxy iframe's window; the bridge scopes its transport here. */
69
+ sandboxWindow: Window;
70
+ /** Origin of the sandbox proxy; only messages from it are accepted and all posts target it. */
71
+ sandboxOrigin: string;
72
+ /** The complete standalone app HTML to inject into the inner sandboxed frame. */
73
+ html: string;
74
+ /** Initial host context sent to the widget on `ui/initialize`. */
75
+ hostContext: McpAppHostContext;
76
+ /** Iframe permission policy forwarded to the inner frame via `sandbox-resource-ready`. */
77
+ permissions?: McpAppResourcePermissions;
78
+ /** Optional override for the inner iframe's `sandbox` attribute. */
79
+ sandbox?: string;
80
+ /** Advertised to the View in the `ui/initialize` result. */
81
+ hostCapabilities: McpAppHostCapabilities;
82
+ }
83
+ export interface IMcpAppBridge {
84
+ /**
85
+ * Connect to the loaded sandbox proxy: perform the `ui/initialize` handshake and send
86
+ * the resource in via `sandbox-resource-ready`. Resolves once the widget has sent
87
+ * `initialized`. The host MUST NOT send tool input before this resolves.
88
+ */
89
+ connect(config: McpAppBridgeConnectConfig): Promise<void>;
90
+ /** Streaming partial tool arguments (each args delta). */
91
+ sendToolInputPartial(args: Record<string, unknown>): void;
92
+ /** Final, complete tool arguments (args complete). */
93
+ sendToolInput(args: Record<string, unknown>): void;
94
+ /** The final tool result, built from the raw MCP result + structured content. */
95
+ sendToolResult(result: McpAppViewToolResult): void;
96
+ /** Notify the widget its tool call was cancelled. */
97
+ sendToolCancelled(reason?: string): void;
98
+ /**
99
+ * Push an updated host context (e.g. theme or container-size change). Before the View
100
+ * is initialized the change is held and returned from `ui/initialize` / flushed on
101
+ * `initialized` instead of being sent.
102
+ */
103
+ sendHostContextChange(hostContext: McpAppHostContext): void;
104
+ /** Notify the widget it is being torn down (`ui/resource-teardown`) and release the bridge without waiting for the ack. */
105
+ sendTeardown(): void;
106
+ /** Widget forwarded a `tools/call` to the server. Rejections become JSON-RPC errors. */
107
+ oncalltool?: (params: McpAppToolCallRequest) => Promise<unknown>;
108
+ /** Widget forwarded a `resources/read` to the server. Rejections become JSON-RPC errors. */
109
+ onreadresource?: (params: McpAppResourceReadRequest) => Promise<unknown>;
110
+ /** Widget requested opening an external link. Absent → `{ isError: true }`. */
111
+ onopenlink?: (params: McpAppOpenLinkParams) => Promise<McpAppRequestResult>;
112
+ /** Widget sent a chat message (`ui/message`). Absent → `{ isError: true }`. */
113
+ onmessage?: (params: McpAppMessageParams) => Promise<McpAppRequestResult>;
114
+ /** Widget emitted a logging message (`notifications/message`). */
115
+ onloggingmessage?: (params: McpAppLoggingMessage) => void;
116
+ /** Widget reported a size change. */
117
+ onsizechange?: (params: McpAppSizeChange) => void;
118
+ /** Widget requested a display-mode change; the host echoes the resulting mode. */
119
+ onrequestdisplaymode?: (params: McpAppRequestDisplayModeParams) => Promise<McpAppRequestDisplayModeResult>;
120
+ /** Widget requested a silent model-context update. */
121
+ onupdatemodelcontext?: (params: McpAppUpdateModelContextParams) => Promise<void>;
122
+ /** Widget asked the host to tear it down (`ui/notifications/request-teardown`). */
123
+ onrequestteardown?: () => void;
124
+ }
@@ -0,0 +1,41 @@
1
+ import { McpAppHostContext } from '../../ai-chatbot';
2
+ import { IMcpAppBridge, McpAppBridgeConnectConfig, McpAppViewToolResult } from './mcp-app-bridge-types.js';
3
+ /**
4
+ * Hand-rolled, zero-dependency {@link IMcpAppBridge}. A `postMessage` listener speaking
5
+ * JSON-RPC 2.0 directly: no SDK, no zod, no schema validation. The cross-origin sandbox
6
+ * iframe is the security boundary here, not message-schema checking — every inbound
7
+ * field is narrowed defensively before use.
8
+ *
9
+ * Drives the handshake against the sandbox proxy (`packages/ai/sandbox/sandbox.js`):
10
+ * `sandbox-proxy-ready` -> `sandbox-resource-ready` -> `ui/initialize` ->
11
+ * `ui/notifications/initialized`, then streaming `ui/notifications/*`. Forwards
12
+ * non-`ui/` methods (`tools/call`, `resources/read`) to the same handler slots the
13
+ * interface defines.
14
+ */
15
+ export declare class McpAppBridge implements IMcpAppBridge {
16
+ #private;
17
+ oncalltool?: IMcpAppBridge['oncalltool'];
18
+ onreadresource?: IMcpAppBridge['onreadresource'];
19
+ onopenlink?: IMcpAppBridge['onopenlink'];
20
+ onmessage?: IMcpAppBridge['onmessage'];
21
+ onloggingmessage?: IMcpAppBridge['onloggingmessage'];
22
+ onsizechange?: IMcpAppBridge['onsizechange'];
23
+ onrequestdisplaymode?: IMcpAppBridge['onrequestdisplaymode'];
24
+ onupdatemodelcontext?: IMcpAppBridge['onupdatemodelcontext'];
25
+ onrequestteardown?: IMcpAppBridge['onrequestteardown'];
26
+ constructor(hostInfo: {
27
+ name: string;
28
+ version: string;
29
+ });
30
+ connect(config: McpAppBridgeConnectConfig): Promise<void>;
31
+ sendToolInputPartial(args: Record<string, unknown>): void;
32
+ sendToolInput(args: Record<string, unknown>): void;
33
+ sendToolResult(result: McpAppViewToolResult): void;
34
+ sendToolCancelled(reason?: string): void;
35
+ sendHostContextChange(hostContext: McpAppHostContext): void;
36
+ /**
37
+ * Send `ui/resource-teardown` and dispose immediately; the host doesn't wait for the ack,
38
+ * so the iframe is removed right away. A View that never initialized isn't messaged.
39
+ */
40
+ sendTeardown(): void;
41
+ }