@vertesia/ui 1.5.0-dev.20260725.083715Z → 1.5.0-dev.20260804.124748Z

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 (176) hide show
  1. package/lib/core/hooks/useScrollableSearch.d.ts +1 -1
  2. package/lib/core/hooks/useScrollableSearch.d.ts.map +1 -1
  3. package/lib/core/hooks/useScrollableSearch.js +15 -2
  4. package/lib/core/hooks/useScrollableSearch.js.map +1 -1
  5. package/lib/env/index.d.ts +4 -0
  6. package/lib/env/index.d.ts.map +1 -1
  7. package/lib/env/index.js.map +1 -1
  8. package/lib/features/agent/chat/AgentRequestInputOverlay.d.ts +1 -1
  9. package/lib/features/agent/chat/AgentRequestInputOverlay.d.ts.map +1 -1
  10. package/lib/features/agent/chat/AgentRequestInputOverlay.js +3 -8
  11. package/lib/features/agent/chat/AgentRequestInputOverlay.js.map +1 -1
  12. package/lib/features/agent/chat/ModernAgentConversation.d.ts +8 -1
  13. package/lib/features/agent/chat/ModernAgentConversation.d.ts.map +1 -1
  14. package/lib/features/agent/chat/ModernAgentConversation.js +53 -17
  15. package/lib/features/agent/chat/ModernAgentConversation.js.map +1 -1
  16. package/lib/features/agent/chat/ModernAgentOutput/ActiveWorkstreamsSummary.d.ts +2 -1
  17. package/lib/features/agent/chat/ModernAgentOutput/ActiveWorkstreamsSummary.d.ts.map +1 -1
  18. package/lib/features/agent/chat/ModernAgentOutput/ActiveWorkstreamsSummary.js +25 -10
  19. package/lib/features/agent/chat/ModernAgentOutput/ActiveWorkstreamsSummary.js.map +1 -1
  20. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts.map +1 -1
  21. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js +24 -9
  22. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js.map +1 -1
  23. package/lib/features/agent/chat/ModernAgentOutput/AttachmentPreview.d.ts.map +1 -1
  24. package/lib/features/agent/chat/ModernAgentOutput/AttachmentPreview.js +15 -3
  25. package/lib/features/agent/chat/ModernAgentOutput/AttachmentPreview.js.map +1 -1
  26. package/lib/features/agent/chat/ModernAgentOutput/Header.js +2 -2
  27. package/lib/features/agent/chat/ModernAgentOutput/Header.js.map +1 -1
  28. package/lib/features/agent/chat/ModernAgentOutput/MessageInput.d.ts +2 -1
  29. package/lib/features/agent/chat/ModernAgentOutput/MessageInput.d.ts.map +1 -1
  30. package/lib/features/agent/chat/ModernAgentOutput/MessageInput.js +2 -2
  31. package/lib/features/agent/chat/ModernAgentOutput/MessageInput.js.map +1 -1
  32. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.d.ts.map +1 -1
  33. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js +2 -2
  34. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js.map +1 -1
  35. package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.d.ts +9 -1
  36. package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.d.ts.map +1 -1
  37. package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.js +97 -2
  38. package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.js.map +1 -1
  39. package/lib/features/agent/chat/hooks/useAgentStream.d.ts.map +1 -1
  40. package/lib/features/agent/chat/hooks/useAgentStream.js +12 -3
  41. package/lib/features/agent/chat/hooks/useAgentStream.js.map +1 -1
  42. package/lib/features/agent/chat/index.d.ts +1 -1
  43. package/lib/features/agent/chat/index.d.ts.map +1 -1
  44. package/lib/features/agent/chat/index.js.map +1 -1
  45. package/lib/features/facets/PromptsFacetsNav.d.ts +8 -6
  46. package/lib/features/facets/PromptsFacetsNav.d.ts.map +1 -1
  47. package/lib/features/facets/PromptsFacetsNav.js +8 -3
  48. package/lib/features/facets/PromptsFacetsNav.js.map +1 -1
  49. package/lib/features/store/objects/components/ContentOverview.js +4 -1
  50. package/lib/features/store/objects/components/ContentOverview.js.map +1 -1
  51. package/lib/features/store/objects/components/useContentPanelHooks.d.ts +31 -3
  52. package/lib/features/store/objects/components/useContentPanelHooks.d.ts.map +1 -1
  53. package/lib/features/store/objects/search/DocumentSearchContext.d.ts +128 -6
  54. package/lib/features/store/objects/search/DocumentSearchContext.d.ts.map +1 -1
  55. package/lib/features/store/objects/selection/ObjectsActionContext.d.ts +2 -2
  56. package/lib/features/store/objects/selection/ObjectsActionContext.d.ts.map +1 -1
  57. package/lib/features/store/objects/selection/ObjectsActionSpec.d.ts +2 -2
  58. package/lib/features/store/objects/selection/ObjectsActionSpec.d.ts.map +1 -1
  59. package/lib/features/store/objects/selection/SelectionActions.d.ts +2 -2
  60. package/lib/features/store/objects/selection/SelectionActions.d.ts.map +1 -1
  61. package/lib/features/store/objects/upload/DocumentUploadModal.js.map +1 -1
  62. package/lib/features/store/types/IntakePolicyEditor.d.ts +2 -2
  63. package/lib/features/store/types/IntakePolicyEditor.d.ts.map +1 -1
  64. package/lib/features/store/types/IntakePolicyEditor.js +5 -1
  65. package/lib/features/store/types/IntakePolicyEditor.js.map +1 -1
  66. package/lib/features/store/types/IntakePolicyForm.d.ts.map +1 -1
  67. package/lib/features/store/types/IntakePolicyForm.js +2 -2
  68. package/lib/features/store/types/IntakePolicyForm.js.map +1 -1
  69. package/lib/features/store/types/ObjectSchemaEditor.d.ts +2 -2
  70. package/lib/features/store/types/ObjectSchemaEditor.d.ts.map +1 -1
  71. package/lib/features/store/types/SelectContentType.d.ts +2 -2
  72. package/lib/features/store/types/SelectContentType.d.ts.map +1 -1
  73. package/lib/features/store/types/SelectContentType.js.map +1 -1
  74. package/lib/features/store/types/SelectContentTypeModal.d.ts +2 -2
  75. package/lib/features/store/types/SelectContentTypeModal.d.ts.map +1 -1
  76. package/lib/features/store/types/SelectContentTypeModal.js.map +1 -1
  77. package/lib/features/store/types/TableLayoutEditor.d.ts +2 -2
  78. package/lib/features/store/types/TableLayoutEditor.d.ts.map +1 -1
  79. package/lib/features/store/types/TypeRegistry.d.ts +1267 -6
  80. package/lib/features/store/types/TypeRegistry.d.ts.map +1 -1
  81. package/lib/features/store/types/TypeRegistry.js +5 -0
  82. package/lib/features/store/types/TypeRegistry.js.map +1 -1
  83. package/lib/features/store/types/intake-policy-editor.logic.d.ts +9 -1
  84. package/lib/features/store/types/intake-policy-editor.logic.d.ts.map +1 -1
  85. package/lib/features/store/types/intake-policy-editor.logic.js +9 -1
  86. package/lib/features/store/types/intake-policy-editor.logic.js.map +1 -1
  87. package/lib/features/store/types/search/ObjectTypeSearchContext.d.ts +1251 -1
  88. package/lib/features/store/types/search/ObjectTypeSearchContext.d.ts.map +1 -1
  89. package/lib/features/store/types/typeCatalogCache.d.ts +2 -2
  90. package/lib/features/store/types/typeCatalogCache.d.ts.map +1 -1
  91. package/lib/features/store/types/typeCatalogCache.js +4 -0
  92. package/lib/features/store/types/typeCatalogCache.js.map +1 -1
  93. package/lib/features/user/UserInfo.d.ts +118 -7
  94. package/lib/features/user/UserInfo.d.ts.map +1 -1
  95. package/lib/i18n/locales/ar.json +2 -1
  96. package/lib/i18n/locales/de.json +2 -1
  97. package/lib/i18n/locales/en.json +5 -1
  98. package/lib/i18n/locales/es.json +2 -1
  99. package/lib/i18n/locales/fr.json +2 -1
  100. package/lib/i18n/locales/it.json +2 -1
  101. package/lib/i18n/locales/ja.json +2 -1
  102. package/lib/i18n/locales/ko.json +2 -1
  103. package/lib/i18n/locales/pt.json +2 -1
  104. package/lib/i18n/locales/ru.json +2 -1
  105. package/lib/i18n/locales/tr.json +2 -1
  106. package/lib/i18n/locales/zh-TW.json +2 -1
  107. package/lib/i18n/locales/zh.json +2 -1
  108. package/lib/session/UserSession.d.ts +18 -4
  109. package/lib/session/UserSession.d.ts.map +1 -1
  110. package/lib/shell/apps/AppInstallationProvider.d.ts +222 -2
  111. package/lib/shell/apps/AppInstallationProvider.d.ts.map +1 -1
  112. package/lib/shell/login/InviteAcceptModal.js.map +1 -1
  113. package/lib/vertesia-ui-core.js +1 -1
  114. package/lib/vertesia-ui-core.js.map +1 -1
  115. package/lib/vertesia-ui-features.js +34 -34
  116. package/lib/vertesia-ui-features.js.map +1 -1
  117. package/lib/vertesia-ui-i18n.js +13 -13
  118. package/lib/vertesia-ui-widgets.js +18 -18
  119. package/lib/vertesia-ui-widgets.js.map +1 -1
  120. package/lib/widgets/monacoEditor/MonacoEditor.d.ts +7 -1
  121. package/lib/widgets/monacoEditor/MonacoEditor.d.ts.map +1 -1
  122. package/lib/widgets/monacoEditor/MonacoEditor.js +62 -6
  123. package/lib/widgets/monacoEditor/MonacoEditor.js.map +1 -1
  124. package/package.json +31 -31
  125. package/src/core/hooks/useScrollableSearch.test.tsx +139 -0
  126. package/src/core/hooks/useScrollableSearch.tsx +17 -3
  127. package/src/env/index.ts +2 -0
  128. package/src/features/agent/chat/AgentChatPlaybackControls.test.tsx +2 -0
  129. package/src/features/agent/chat/AgentRequestInputOverlay.test.tsx +51 -6
  130. package/src/features/agent/chat/AgentRequestInputOverlay.tsx +5 -7
  131. package/src/features/agent/chat/ModernAgentConversation.test.tsx +195 -3
  132. package/src/features/agent/chat/ModernAgentConversation.tsx +106 -22
  133. package/src/features/agent/chat/ModernAgentOutput/ActiveWorkstreamsSummary.tsx +75 -20
  134. package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.test.tsx +112 -0
  135. package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.tsx +62 -10
  136. package/src/features/agent/chat/ModernAgentOutput/AttachmentPreview.tsx +36 -4
  137. package/src/features/agent/chat/ModernAgentOutput/Header.tsx +2 -2
  138. package/src/features/agent/chat/ModernAgentOutput/MessageInput.test.tsx +71 -0
  139. package/src/features/agent/chat/ModernAgentOutput/MessageInput.tsx +3 -1
  140. package/src/features/agent/chat/ModernAgentOutput/MessageItem.tsx +18 -4
  141. package/src/features/agent/chat/ModernAgentOutput/requestInputMessages.test.ts +95 -0
  142. package/src/features/agent/chat/ModernAgentOutput/requestInputMessages.ts +111 -1
  143. package/src/features/agent/chat/hooks/useAgentStream.test.tsx +57 -0
  144. package/src/features/agent/chat/hooks/useAgentStream.ts +12 -3
  145. package/src/features/agent/chat/index.ts +1 -0
  146. package/src/features/facets/PromptsFacetsNav.tsx +17 -9
  147. package/src/features/store/objects/components/ContentOverview.tsx +4 -1
  148. package/src/features/store/objects/selection/ObjectsActionContext.tsx +2 -2
  149. package/src/features/store/objects/selection/ObjectsActionSpec.ts +2 -2
  150. package/src/features/store/objects/selection/SelectionActions.tsx +2 -2
  151. package/src/features/store/objects/upload/DocumentUploadModal.tsx +2 -2
  152. package/src/features/store/types/IntakePolicyEditor.tsx +12 -4
  153. package/src/features/store/types/IntakePolicyForm.tsx +25 -0
  154. package/src/features/store/types/ObjectSchemaEditor.tsx +2 -2
  155. package/src/features/store/types/SelectContentType.tsx +9 -9
  156. package/src/features/store/types/SelectContentTypeModal.tsx +5 -5
  157. package/src/features/store/types/TableLayoutEditor.tsx +2 -2
  158. package/src/features/store/types/TypeRegistry.ts +8 -3
  159. package/src/features/store/types/intake-policy-editor.logic.ts +10 -2
  160. package/src/features/store/types/typeCatalogCache.ts +10 -3
  161. package/src/i18n/locales/ar.json +2 -1
  162. package/src/i18n/locales/de.json +2 -1
  163. package/src/i18n/locales/en.json +5 -1
  164. package/src/i18n/locales/es.json +2 -1
  165. package/src/i18n/locales/fr.json +2 -1
  166. package/src/i18n/locales/it.json +2 -1
  167. package/src/i18n/locales/ja.json +2 -1
  168. package/src/i18n/locales/ko.json +2 -1
  169. package/src/i18n/locales/pt.json +2 -1
  170. package/src/i18n/locales/ru.json +2 -1
  171. package/src/i18n/locales/tr.json +2 -1
  172. package/src/i18n/locales/zh-TW.json +2 -1
  173. package/src/i18n/locales/zh.json +2 -1
  174. package/src/shell/login/InviteAcceptModal.tsx +4 -4
  175. package/src/widgets/markdown/ArtifactEditingSurface.test.tsx +13 -9
  176. package/src/widgets/monacoEditor/MonacoEditor.tsx +83 -7
@@ -35,7 +35,13 @@ interface MonacoEditorProps {
35
35
  onMount?: (editor: monaco.editor.IStandaloneCodeEditor, monaco: typeof import('monaco-editor')) => void;
36
36
  defaultValue?: string;
37
37
  useCustomFolding?: boolean;
38
+ /**
39
+ * JSON Schema applied to this editor's content (language must be 'json'). Drives
40
+ * completion, hover documentation, and validation squiggles. Scoped to this editor
41
+ * instance only — other JSON editors keep their own (or no) schema.
42
+ */
43
+ jsonSchema?: object;
38
44
  }
39
- export declare function MonacoEditor({ onChange, value, className, editorRef, language, path, debounceTimeout, options, beforeMount, onMount, defaultValue, useCustomFolding, }: MonacoEditorProps): import("react").JSX.Element;
45
+ export declare function MonacoEditor({ onChange, value, className, editorRef, language, path, debounceTimeout, options, beforeMount, onMount, defaultValue, useCustomFolding, jsonSchema, }: MonacoEditorProps): import("react").JSX.Element;
40
46
  export {};
41
47
  //# sourceMappingURL=MonacoEditor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"MonacoEditor.d.ts","sourceRoot":"","sources":["../../../src/widgets/monacoEditor/MonacoEditor.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,KAAK,MAAM,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,KAAK,SAAS,EAAqD,MAAM,OAAO,CAAC;AAG1F,MAAM,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC;AA6BnC,MAAM,WAAW,UAAU;IACvB,QAAQ,IAAI,MAAM,CAAC;IACnB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAGD,MAAM,WAAW,UAAU;IACvB,UAAU,EAAE,OAAO,CAAC;IACpB,KAAK,EAAE;QACH,GAAG,EAAE;YACD,QAAQ,IAAI,MAAM,CAAC;YACnB,MAAM,EAAE,MAAM,CAAC;SAClB,CAAC;KACL,CAAC;CACL;AAED,qBAAa,UAAW,YAAW,UAAU;IAErC,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,SAAS;gBADT,SAAS,EAAE,MAAM,MAAM,EACvB,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI;IAG9C,QAAQ;IAIR,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM;CAG1B;AAED,UAAU,iBAAiB;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,SAAS,CAAC,UAAU,GAAG,SAAS,CAAC,CAAC;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;IACxC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,oCAAoC,CAAC;IAC7D,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,cAAc,eAAe,CAAC,KAAK,IAAI,CAAC;IAC/D,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,qBAAqB,EAAE,MAAM,EAAE,cAAc,eAAe,CAAC,KAAK,IAAI,CAAC;IACxG,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,wBAAgB,YAAY,CAAC,EACzB,QAAQ,EACR,KAAK,EACL,SAAS,EACT,SAAS,EACT,QAAuB,EACvB,IAAI,EACJ,eAAmB,EACnB,OAAY,EACZ,WAAW,EACX,OAAO,EACP,YAAY,EACZ,gBAAwB,GAC3B,EAAE,iBAAiB,+BAgMnB"}
1
+ {"version":3,"file":"MonacoEditor.d.ts","sourceRoot":"","sources":["../../../src/widgets/monacoEditor/MonacoEditor.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,KAAK,MAAM,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,KAAK,SAAS,EAAqD,MAAM,OAAO,CAAC;AAG1F,MAAM,MAAM,MAAM,GAAG,OAAO,MAAM,CAAC;AA6BnC,MAAM,WAAW,UAAU;IACvB,QAAQ,IAAI,MAAM,CAAC;IACnB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAoCD,MAAM,WAAW,UAAU;IACvB,UAAU,EAAE,OAAO,CAAC;IACpB,KAAK,EAAE;QACH,GAAG,EAAE;YACD,QAAQ,IAAI,MAAM,CAAC;YACnB,MAAM,EAAE,MAAM,CAAC;SAClB,CAAC;KACL,CAAC;CACL;AAED,qBAAa,UAAW,YAAW,UAAU;IAErC,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,SAAS;gBADT,SAAS,EAAE,MAAM,MAAM,EACvB,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI;IAG9C,QAAQ;IAIR,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM;CAG1B;AAED,UAAU,iBAAiB;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,SAAS,CAAC,UAAU,GAAG,SAAS,CAAC,CAAC;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;IACxC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,oCAAoC,CAAC;IAC7D,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,cAAc,eAAe,CAAC,KAAK,IAAI,CAAC;IAC/D,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,qBAAqB,EAAE,MAAM,EAAE,cAAc,eAAe,CAAC,KAAK,IAAI,CAAC;IACxG,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,YAAY,CAAC,EACzB,QAAQ,EACR,KAAK,EACL,SAAS,EACT,SAAS,EACT,QAAuB,EACvB,IAAI,EACJ,eAAmB,EACnB,OAAY,EACZ,WAAW,EACX,OAAO,EACP,YAAY,EACZ,gBAAwB,EACxB,UAAU,GACb,EAAE,iBAAiB,+BAoOnB"}
@@ -32,6 +32,27 @@ function getOverflowWidgetsNode() {
32
32
  }
33
33
  return overflowWidgetsNode;
34
34
  }
35
+ /**
36
+ * Registry of JSON schemas keyed by model path. Monaco's JSON language service is configured
37
+ * globally (per language, not per editor), so every mounted editor's schema must be re-applied
38
+ * together — each entry is scoped to its own model via `fileMatch`, so editors never see each
39
+ * other's schema.
40
+ */
41
+ const jsonSchemaRegistry = new Map();
42
+ let jsonSchemaModelCounter = 0;
43
+ function applyJsonSchemas(monacoInstance) {
44
+ const jsonDefaults = monacoInstance.languages
45
+ .json?.jsonDefaults;
46
+ jsonDefaults?.setDiagnosticsOptions({
47
+ validate: true,
48
+ enableSchemaRequest: false,
49
+ schemas: Array.from(jsonSchemaRegistry.entries()).map(([modelPath, schema]) => ({
50
+ uri: `vertesia://schemas/${encodeURIComponent(modelPath)}`,
51
+ fileMatch: [modelPath],
52
+ schema,
53
+ })),
54
+ });
55
+ }
35
56
  export class VEditorApi {
36
57
  VgetValue;
37
58
  VsetValue;
@@ -46,10 +67,14 @@ export class VEditorApi {
46
67
  this.VsetValue(value || '');
47
68
  }
48
69
  }
49
- export function MonacoEditor({ onChange, value, className, editorRef, language = 'javascript', path, debounceTimeout = 0, options = {}, beforeMount, onMount, defaultValue, useCustomFolding = false, }) {
70
+ export function MonacoEditor({ onChange, value, className, editorRef, language = 'javascript', path, debounceTimeout = 0, options = {}, beforeMount, onMount, defaultValue, useCustomFolding = false, jsonSchema, }) {
50
71
  const [editorValue, setEditorValue] = useState(value || defaultValue || '');
51
72
  const editorInstanceRef = useRef(null);
52
73
  const monacoInstanceRef = useRef(null);
74
+ // Stable per-instance model path: required to scope a jsonSchema to THIS editor's model.
75
+ // Callers may pass an explicit `path`; otherwise one is generated when a schema is set.
76
+ const [generatedPath] = useState(() => jsonSchema ? `inmemory://vertesia/json/${++jsonSchemaModelCounter}.json` : undefined);
77
+ const modelPath = path ?? generatedPath;
53
78
  const { theme } = useTheme();
54
79
  const resolvedTheme = theme === 'system' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme;
55
80
  const effectiveValue = value || defaultValue || '';
@@ -114,6 +139,10 @@ export function MonacoEditor({ onChange, value, className, editorRef, language =
114
139
  const handleEditorDidMount = useCallback((editor, monacoInstance) => {
115
140
  editorInstanceRef.current = editor;
116
141
  monacoInstanceRef.current = monacoInstance;
142
+ if (jsonSchema && modelPath && language === 'json') {
143
+ jsonSchemaRegistry.set(modelPath, jsonSchema);
144
+ applyJsonSchemas(monacoInstance);
145
+ }
117
146
  if (useCustomFolding) {
118
147
  registerCustomFoldingProviders(monacoInstance);
119
148
  }
@@ -138,9 +167,26 @@ export function MonacoEditor({ onChange, value, className, editorRef, language =
138
167
  }
139
168
  // Call custom onMount if provided
140
169
  onMount?.(editor, monacoInstance);
141
- }, [onMount, resolvedTheme, useCustomFolding, foldAllCodeBlocks]);
142
- // Update editor value when prop changes from outside
170
+ }, [onMount, resolvedTheme, useCustomFolding, foldAllCodeBlocks, jsonSchema, modelPath, language]);
171
+ // Unregister this editor's schema on unmount so the global JSON diagnostics config
172
+ // doesn't accumulate schemas for dead models.
173
+ useEffect(() => {
174
+ return () => {
175
+ if (jsonSchema && modelPath && jsonSchemaRegistry.delete(modelPath) && monacoInstanceRef.current) {
176
+ applyJsonSchemas(monacoInstanceRef.current);
177
+ }
178
+ };
179
+ }, [jsonSchema, modelPath]);
180
+ // Apply external `value`/`defaultValue` changes to the model — but NEVER while the user is
181
+ // actively typing. If the editor has focus, an incoming value is almost always a stale echo of
182
+ // this editor's own (possibly debounced or reformatted) onChange output flowing back in through
183
+ // a controlled `value` prop. Re-applying it would jump the caret and drop the characters typed
184
+ // during the round-trip. We skip while focused; genuine external updates land once the editor is
185
+ // blurred. Explicit programmatic updates go through the editor ref (`setValue`) and are exempt.
143
186
  useEffect(() => {
187
+ if (editorInstanceRef.current?.hasTextFocus()) {
188
+ return;
189
+ }
144
190
  setEditorValue((currentValue) => {
145
191
  if (effectiveValue === currentValue) {
146
192
  return currentValue;
@@ -151,10 +197,13 @@ export function MonacoEditor({ onChange, value, className, editorRef, language =
151
197
  return effectiveValue;
152
198
  });
153
199
  }, [effectiveValue]);
154
- // Re-fold code blocks when value prop changes externally
200
+ // Re-fold code blocks when the value changes externally — same focus guard, so folding never
201
+ // moves the selection out from under an actively typing user.
155
202
  useEffect(() => {
156
203
  if (!effectiveValue || !useCustomFolding || !editorInstanceRef.current || !monacoInstanceRef.current)
157
204
  return;
205
+ if (editorInstanceRef.current.hasTextFocus())
206
+ return;
158
207
  const editor = editorInstanceRef.current;
159
208
  const monacoInstance = monacoInstanceRef.current;
160
209
  const timer = setTimeout(() => foldAllCodeBlocks(editor, monacoInstance), 300);
@@ -182,7 +231,7 @@ export function MonacoEditor({ onChange, value, className, editorRef, language =
182
231
  renderValidationDecorations: 'on', // Show error squiggles
183
232
  renderLineHighlight: 'line', // Highlight entire line for errors
184
233
  hover: {
185
- enabled: true,
234
+ enabled: 'on',
186
235
  delay: 100,
187
236
  }, // Enable hover for error messages
188
237
  quickSuggestions: {
@@ -192,6 +241,13 @@ export function MonacoEditor({ onChange, value, className, editorRef, language =
192
241
  }, // Show problems panel information
193
242
  ...options,
194
243
  };
195
- return (_jsx("div", { className: clsx(className, 'w-full h-full!'), children: _jsx(Editor, { className: "h-full w-full", height: "100%", theme: resolvedTheme === 'dark' ? 'vs-dark' : 'light', language: language, path: path, value: editorValue, onChange: handleEditorChange, onMount: handleEditorDidMount, beforeMount: beforeMount, options: defaultOptions, defaultValue: defaultValue || '' }) }));
244
+ return (_jsx("div", { className: clsx(className, 'w-full h-full!'), children: _jsx(Editor, { className: "h-full w-full", height: "100%", theme: resolvedTheme === 'dark' ? 'vs-dark' : 'light', language: language, path: modelPath, onChange: handleEditorChange, onMount: handleEditorDidMount, beforeMount: beforeMount, options: defaultOptions,
245
+ // Uncontrolled: seed the initial content once via `defaultValue` and never bind a
246
+ // reactive `value`. @monaco-editor/react re-applies a changed `value` prop through
247
+ // `executeEdits(..., forceMoveMarkers: true)` whenever it differs from the live
248
+ // model, snapping the caret to the END of the content — the cursor jump we are
249
+ // eliminating whenever a caller feeds its own onChange output back into `value`.
250
+ // All external updates instead flow through the focus-guarded sync effect above.
251
+ defaultValue: effectiveValue }) }));
196
252
  }
197
253
  //# sourceMappingURL=MonacoEditor.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"MonacoEditor.js","sourceRoot":"","sources":["../../../src/widgets/monacoEditor/MonacoEditor.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"MonacoEditor.js","sourceRoot":"","sources":["../../../src/widgets/monacoEditor/MonacoEditor.tsx"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vertesia/ui",
3
- "version": "1.5.0-dev.20260725.083715Z",
3
+ "version": "1.5.0-dev.20260804.124748Z",
4
4
  "description": "Vertesia UI components and and hooks",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -24,24 +24,24 @@
24
24
  "@floating-ui/dom": "^1.8.0",
25
25
  "@floating-ui/react": "^0.27.20",
26
26
  "@monaco-editor/react": "^4.7.0",
27
- "@radix-ui/react-checkbox": "^1.3.7",
28
- "@radix-ui/react-collapsible": "^1.1.16",
29
- "@radix-ui/react-dialog": "^1.1.19",
30
- "@radix-ui/react-direction": "^1.1.2",
31
- "@radix-ui/react-dismissable-layer": "^1.1.15",
32
- "@radix-ui/react-dropdown-menu": "^2.1.20",
33
- "@radix-ui/react-focus-guards": "^1.1.4",
34
- "@radix-ui/react-focus-scope": "^1.1.12",
35
- "@radix-ui/react-label": "^2.1.11",
36
- "@radix-ui/react-popover": "^1.1.19",
37
- "@radix-ui/react-portal": "^1.1.13",
38
- "@radix-ui/react-radio-group": "^1.4.3",
39
- "@radix-ui/react-separator": "^1.1.11",
40
- "@radix-ui/react-slider": "^1.4.3",
41
- "@radix-ui/react-slot": "^1.3.0",
42
- "@radix-ui/react-switch": "^1.3.3",
43
- "@radix-ui/react-tabs": "^1.1.17",
44
- "@radix-ui/react-tooltip": "^1.2.12",
27
+ "@radix-ui/react-checkbox": "^1.3.11",
28
+ "@radix-ui/react-collapsible": "^1.1.20",
29
+ "@radix-ui/react-dialog": "^1.1.23",
30
+ "@radix-ui/react-direction": "^1.1.4",
31
+ "@radix-ui/react-dismissable-layer": "^1.1.19",
32
+ "@radix-ui/react-dropdown-menu": "^2.1.24",
33
+ "@radix-ui/react-focus-guards": "^1.1.6",
34
+ "@radix-ui/react-focus-scope": "^1.1.16",
35
+ "@radix-ui/react-label": "^2.1.15",
36
+ "@radix-ui/react-popover": "^1.1.23",
37
+ "@radix-ui/react-portal": "^1.1.17",
38
+ "@radix-ui/react-radio-group": "^1.4.7",
39
+ "@radix-ui/react-separator": "^1.1.15",
40
+ "@radix-ui/react-slider": "^1.4.7",
41
+ "@radix-ui/react-slot": "^1.3.3",
42
+ "@radix-ui/react-switch": "^1.3.7",
43
+ "@radix-ui/react-tabs": "^1.1.21",
44
+ "@radix-ui/react-tooltip": "^1.2.16",
45
45
  "ajv": "^8.20.0",
46
46
  "ajv-formats": "^3.0.1",
47
47
  "aria-hidden": "^1.2.6",
@@ -56,11 +56,11 @@
56
56
  "framer-motion": "^12.42.2",
57
57
  "i18next": "^26.3.6",
58
58
  "jwt-decode": "^4.0.0",
59
- "katex": "^0.17.0",
59
+ "katex": "^0.18.1",
60
60
  "lodash-es": "^4.18.1",
61
- "lucide-react": "^1.24.0",
61
+ "lucide-react": "^1.27.0",
62
62
  "mermaid": "^11.16.0",
63
- "monaco-editor": "^0.55.1",
63
+ "monaco-editor": "^0.56.0",
64
64
  "motion": "^12.42.2",
65
65
  "papaparse": "^5.5.4",
66
66
  "react": "19.2.7",
@@ -68,7 +68,7 @@
68
68
  "react-date-picker": "^12.0.2",
69
69
  "react-dom": "19.2.7",
70
70
  "react-error-boundary": "^6.1.2",
71
- "react-i18next": "^17.0.9",
71
+ "react-i18next": "^17.0.11",
72
72
  "react-markdown": "^10.1.0",
73
73
  "react-pdf": "^10.4.1",
74
74
  "react-remove-scroll": "^2.7.2",
@@ -86,14 +86,14 @@
86
86
  "tailwind-merge": "^3.6.0",
87
87
  "ts-md5": "^2.0.1",
88
88
  "unist-util-visit": "^5.1.0",
89
- "vega": "^6.2.0",
89
+ "vega": "^6.3.1",
90
90
  "vega-embed": "^7.1.0",
91
91
  "vega-lite": "^6.4.3",
92
- "@vertesia/client": "1.5.0-dev.20260725.083715Z",
93
- "@vertesia/common": "1.5.0-dev.20260725.083715Z",
94
- "@vertesia/fusion-ux": "1.5.0-dev.20260725.083715Z",
95
- "@vertesia/rich-text": "1.5.0-dev.20260725.083715Z",
96
- "@vertesia/json": "1.5.0-dev.20260725.083715Z"
92
+ "@vertesia/client": "1.5.0-dev.20260804.124748Z",
93
+ "@vertesia/common": "1.5.0-dev.20260804.124748Z",
94
+ "@vertesia/fusion-ux": "1.5.0-dev.20260804.124748Z",
95
+ "@vertesia/rich-text": "1.5.0-dev.20260804.124748Z",
96
+ "@vertesia/json": "1.5.0-dev.20260804.124748Z"
97
97
  },
98
98
  "devDependencies": {
99
99
  "@testing-library/react": "^16.3.2",
@@ -106,7 +106,7 @@
106
106
  "@types/react-dom": "19.2.3",
107
107
  "axe-core": "^4.12.1",
108
108
  "culori": "^4.0.2",
109
- "i18next-cli": "^1.66.0",
109
+ "i18next-cli": "^1.66.2",
110
110
  "jsdom": "^29.1.1",
111
111
  "rolldown": "1.2.0",
112
112
  "typescript": "^6.0.3",
@@ -184,7 +184,7 @@
184
184
  "url": "https://github.com/vertesia/composableai.git",
185
185
  "directory": "packages/ui"
186
186
  },
187
- "gitHead": "57bcc2f27dd17b3387f27c18e89329c4c37f98ac",
187
+ "gitHead": "87ac9166db2b38bd1be6e37adf0414ea83e402ee",
188
188
  "scripts": {
189
189
  "clean:lib": "rimraf ./lib ./tsconfig.tsbuildinfo",
190
190
  "clean": "rimraf ./node_modules ./lib ./tsconfig.tsbuildinfo",
@@ -0,0 +1,139 @@
1
+ import { act, render } from '@testing-library/react';
2
+ import { useRef, useState } from 'react';
3
+ import { beforeAll, describe, expect, it, vi } from 'vitest';
4
+ import { type ScrollableSearchResult, useDefaultScrollableSearch } from './useScrollableSearch';
5
+
6
+ beforeAll(() => {
7
+ // jsdom has no IntersectionObserver; the hook only needs it constructible.
8
+ vi.stubGlobal(
9
+ 'IntersectionObserver',
10
+ class {
11
+ observe() {}
12
+ unobserve() {}
13
+ disconnect() {}
14
+ },
15
+ );
16
+ });
17
+
18
+ /**
19
+ * Regression tests for the infinite request loop: callers pass an INLINE search
20
+ * closure (new identity every render). The fetch effect must not depend on that
21
+ * identity, otherwise every completed request re-triggers the effect forever.
22
+ */
23
+
24
+ type Item = { id: number };
25
+
26
+ function flush(): Promise<void> {
27
+ // Drain the microtask queue so pending search promises settle.
28
+ return act(() => Promise.resolve());
29
+ }
30
+
31
+ function Harness({
32
+ searchFn,
33
+ onApi,
34
+ }: {
35
+ searchFn: (payload: unknown, offset: number, limit: number) => Promise<Item[]>;
36
+ onApi: (api: ScrollableSearchResult<Item, unknown, number>) => void;
37
+ }) {
38
+ const loadMoreRef = useRef<HTMLDivElement>(null);
39
+ // Unrelated state to force extra re-renders, as a real page would.
40
+ const [, setTick] = useState(0);
41
+ const api = useDefaultScrollableSearch<Item, unknown>({
42
+ // Inline closure ON PURPOSE — new identity on every render, like real callers.
43
+ async search(payload, offset, limit) {
44
+ return searchFn(payload, offset, limit);
45
+ },
46
+ pageSize: 2,
47
+ nextPageTrigger: loadMoreRef,
48
+ payload: {},
49
+ });
50
+ onApi(api);
51
+ return (
52
+ <div>
53
+ <button type="button" data-testid="rerender" onClick={() => setTick((t) => t + 1)} />
54
+ <div ref={loadMoreRef} />
55
+ </div>
56
+ );
57
+ }
58
+
59
+ function setup(searchFn: (payload: unknown, offset: number, limit: number) => Promise<Item[]>) {
60
+ let api!: ScrollableSearchResult<Item, unknown, number>;
61
+ const utils = render(
62
+ <Harness
63
+ searchFn={searchFn}
64
+ onApi={(a) => {
65
+ api = a;
66
+ }}
67
+ />,
68
+ );
69
+ return { ...utils, getApi: () => api };
70
+ }
71
+
72
+ describe('useDefaultScrollableSearch', () => {
73
+ it('fetches exactly once on mount despite inline search closures and re-renders', async () => {
74
+ const searchFn = vi.fn(async () => [{ id: 1 }, { id: 2 }]);
75
+ const { getApi } = setup(searchFn);
76
+
77
+ await flush();
78
+ expect(searchFn).toHaveBeenCalledTimes(1);
79
+ expect(getApi().result).toEqual([{ id: 1 }, { id: 2 }]);
80
+
81
+ // Extra render cycles (state updates elsewhere on the page) must NOT re-fetch.
82
+ await flush();
83
+ await flush();
84
+ expect(searchFn).toHaveBeenCalledTimes(1);
85
+ });
86
+
87
+ it('searchMore appends the next page (single extra request)', async () => {
88
+ const pages: Item[][] = [[{ id: 1 }, { id: 2 }], [{ id: 3 }]];
89
+ const searchFn = vi.fn(async (_p: unknown, offset: number) => pages[offset / 2] ?? []);
90
+ const { getApi } = setup(searchFn);
91
+ await flush();
92
+
93
+ act(() => getApi().searchMore());
94
+ await flush();
95
+
96
+ expect(searchFn).toHaveBeenCalledTimes(2);
97
+ expect(getApi().result).toEqual([{ id: 1 }, { id: 2 }, { id: 3 }]);
98
+ // Page of 1 < pageSize still probes once more only when triggered — no auto loop.
99
+ await flush();
100
+ expect(searchFn).toHaveBeenCalledTimes(2);
101
+ });
102
+
103
+ it('refresh() re-fetches even on the first page (same payload, same page)', async () => {
104
+ const searchFn = vi.fn(async () => [{ id: 1 }]);
105
+ const { getApi } = setup(searchFn);
106
+ await flush();
107
+ expect(searchFn).toHaveBeenCalledTimes(1);
108
+
109
+ act(() => getApi().refresh());
110
+ await flush();
111
+ expect(searchFn).toHaveBeenCalledTimes(2);
112
+ });
113
+
114
+ it('empty result stops pagination (hasMore=false) and does not re-fetch', async () => {
115
+ const searchFn = vi.fn(async () => []);
116
+ const { getApi } = setup(searchFn);
117
+ await flush();
118
+
119
+ expect(searchFn).toHaveBeenCalledTimes(1);
120
+ expect(getApi().hasMore).toBe(false);
121
+
122
+ act(() => getApi().searchMore());
123
+ await flush();
124
+ // nextPage is null — searchMore is a no-op.
125
+ expect(searchFn).toHaveBeenCalledTimes(1);
126
+ });
127
+
128
+ it('a failing search sets error once and does not retry in a loop', async () => {
129
+ const searchFn = vi.fn(async () => {
130
+ throw new Error('boom');
131
+ });
132
+ const { getApi } = setup(searchFn);
133
+ await flush();
134
+ await flush();
135
+
136
+ expect(getApi().error?.message).toBe('boom');
137
+ expect(searchFn).toHaveBeenCalledTimes(1);
138
+ });
139
+ });
@@ -48,7 +48,7 @@ interface ScrollableSearchOptions<ResultT, PayloadT, PageT = number> {
48
48
  nextPageTrigger: React.RefObject<HTMLElement | null>;
49
49
  }
50
50
 
51
- interface ScrollableSearchResult<ResultT, PayloadT, PageT = number> {
51
+ export interface ScrollableSearchResult<ResultT, PayloadT, PageT = number> {
52
52
  /**
53
53
  * Initiates a new search with the given payload
54
54
  * @param payload The search payload
@@ -105,15 +105,27 @@ export function useScrollableSearch<ResultT, PayloadT, PageT = number>(
105
105
  const [results, setResults] = useState<ResultT[]>([]);
106
106
  const [nextPage, setNextPage] = useState<PageT | null>(null);
107
107
  const [isSearching, setIsSearching] = useState(false);
108
+ // Bumped by search()/refresh() so the fetch effect re-runs even when the
109
+ // payload/page state is unchanged (e.g. refresh on the first page).
110
+ const [refreshTick, setRefreshTick] = useState(0);
108
111
 
109
112
  // Track current request to prevent stale results
110
113
  const requestIdRef = useRef(0);
111
114
 
115
+ // Latest-ref for the search function: callers routinely pass an inline
116
+ // closure, which gets a new identity on every render. Depending on it in
117
+ // the fetch effect made every completed request re-trigger the effect —
118
+ // an infinite request loop. The ref always points at the latest closure
119
+ // without participating in the effect's dependencies.
120
+ const searchFnRef = useRef(opts.search);
121
+ searchFnRef.current = opts.search;
122
+
112
123
  const search = (payload: PayloadT) => {
113
124
  setPage(null);
114
125
  setResults([]); // Clear old results immediately
115
126
  setNextPage(null);
116
127
  setLastPayload(payload);
128
+ setRefreshTick((tick) => tick + 1);
117
129
  };
118
130
 
119
131
  const searchMore = () => {
@@ -122,13 +134,15 @@ export function useScrollableSearch<ResultT, PayloadT, PageT = number>(
122
134
  }
123
135
  };
124
136
 
137
+ // biome-ignore lint/correctness/useExhaustiveDependencies: refreshTick is an intentional external trigger — refresh() bumps it to re-run the fetch when payload/page are unchanged
125
138
  useEffect(() => {
126
139
  // Increment request ID to mark previous requests as stale
127
140
  requestIdRef.current += 1;
128
141
  const currentRequestId = requestIdRef.current;
129
142
 
130
143
  setIsSearching(true);
131
- opts.search(lastPayload, page, pageSize)
144
+ searchFnRef
145
+ .current(lastPayload, page, pageSize)
132
146
  .then((r) => {
133
147
  // Only update state if this is still the current request
134
148
  if (currentRequestId !== requestIdRef.current) {
@@ -158,7 +172,7 @@ export function useScrollableSearch<ResultT, PayloadT, PageT = number>(
158
172
  setIsSearching(false);
159
173
  }
160
174
  });
161
- }, [...dependencies, lastPayload, opts.search, page, pageSize]);
175
+ }, [...dependencies, lastPayload, refreshTick, page, pageSize]);
162
176
 
163
177
  // Intersection observer for infinite scrolling
164
178
  useIntersectionObserver(
package/src/env/index.ts CHANGED
@@ -17,6 +17,8 @@ export interface EnvProps {
17
17
  sts: string; // Security Token Service endpoint
18
18
  git?: string; // Smart HTTP app source git endpoint
19
19
  mcp?: string;
20
+ /** Appgen app-gateway endpoint (serves live development previews and app bundles). */
21
+ gateway?: string;
20
22
  };
21
23
  firebase?: {
22
24
  apiKey: string;
@@ -24,6 +24,8 @@ describe('AgentChatPlaybackControls', () => {
24
24
  <AgentChatPlaybackControls cursor="live" messages={messages} onChangeCursor={onChangeCursor} />,
25
25
  );
26
26
 
27
+ expect(screen.getByText('Debug')).toBeTruthy();
28
+
27
29
  fireEvent.click(screen.getByRole('button', { name: 'Jump to first message' }));
28
30
 
29
31
  expect(onChangeCursor).toHaveBeenCalledWith(0);
@@ -1,22 +1,30 @@
1
- import { fireEvent, screen } from '@testing-library/react';
1
+ import { fireEvent, screen, waitFor } from '@testing-library/react';
2
2
  import { AgentMessageType } from '@vertesia/common';
3
- import { describe, expect, it, vi } from 'vitest';
3
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
4
4
  import { renderWithProviders } from '../../../__tests__/test-utils.js';
5
5
  import { AgentRequestInputOverlay } from './AgentRequestInputOverlay';
6
6
  import type { RequestInputMessageWithUx } from './ModernAgentOutput/requestInputMessages';
7
7
 
8
+ const mocks = vi.hoisted(() => ({
9
+ getCollectionStatus: vi.fn(),
10
+ }));
11
+
8
12
  vi.mock('@vertesia/ui/session', () => ({
9
13
  useUserSession: () => ({
10
14
  client: {
11
15
  remoteMcpConnections: {
12
- getCollectionStatus: vi.fn(),
16
+ getCollectionStatus: mocks.getCollectionStatus,
13
17
  },
14
18
  },
15
19
  }),
16
20
  }));
17
21
 
18
22
  vi.mock('../../oauth/RemoteMcpConnectionButton.js', () => ({
19
- RemoteMcpConnectionButton: () => <button type="button">Connect</button>,
23
+ RemoteMcpConnectionButton: ({ onAuthChange }: { onAuthChange: () => void }) => (
24
+ <button type="button" onClick={onAuthChange}>
25
+ Connect
26
+ </button>
27
+ ),
20
28
  }));
21
29
 
22
30
  function createMcpRequestMessage(): RequestInputMessageWithUx {
@@ -27,6 +35,7 @@ function createMcpRequestMessage(): RequestInputMessageWithUx {
27
35
  workstream_id: 'main',
28
36
  message: 'Connect to Jira to continue.',
29
37
  details: {
38
+ request_id: 'request-mcp-1',
30
39
  ux: {
31
40
  mcp_connect: {
32
41
  app_install_id: 'app1',
@@ -46,6 +55,7 @@ function createToolApprovalRequestMessage(): RequestInputMessageWithUx {
46
55
  workstream_id: 'main',
47
56
  message: 'Approve Write Artifact: quotes.md?',
48
57
  details: {
58
+ request_id: 'write_artifact:name:quotes.md',
49
59
  tool_approval: {
50
60
  tool_name: 'write_artifact',
51
61
  tool_title: 'Write Artifact',
@@ -74,6 +84,11 @@ function createToolApprovalRequestMessage(): RequestInputMessageWithUx {
74
84
  }
75
85
 
76
86
  describe('AgentRequestInputOverlay', () => {
87
+ beforeEach(() => {
88
+ vi.clearAllMocks();
89
+ mocks.getCollectionStatus.mockResolvedValue({ authenticated: true });
90
+ });
91
+
77
92
  it('lets the user decline an MCP connection request', () => {
78
93
  const onSendMessage = vi.fn();
79
94
 
@@ -86,7 +101,29 @@ describe('AgentRequestInputOverlay', () => {
86
101
  fireEvent.click(screen.getByRole('button', { name: /decline/i }));
87
102
 
88
103
  expect(onSendMessage).toHaveBeenCalledTimes(1);
89
- expect(onSendMessage).toHaveBeenCalledWith("I don't want to connect to Jira. Continue without it.");
104
+ expect(onSendMessage).toHaveBeenCalledWith("I don't want to connect to Jira. Continue without it.", {
105
+ request_input_response: { request_id: 'request-mcp-1' },
106
+ });
107
+ });
108
+
109
+ it('correlates a successful MCP connection response', async () => {
110
+ const onMcpConnected = vi.fn();
111
+
112
+ renderWithProviders(
113
+ <AgentRequestInputOverlay
114
+ message={createMcpRequestMessage()}
115
+ onSendMessage={vi.fn()}
116
+ onMcpConnected={onMcpConnected}
117
+ />,
118
+ );
119
+
120
+ fireEvent.click(screen.getByRole('button', { name: 'Connect' }));
121
+
122
+ await waitFor(() => {
123
+ expect(onMcpConnected).toHaveBeenCalledWith(expect.objectContaining({ collection_id: 'jira' }), {
124
+ request_input_response: { request_id: 'request-mcp-1' },
125
+ });
126
+ });
90
127
  });
91
128
 
92
129
  it('sends a commented tool approval denial with structured metadata', () => {
@@ -107,6 +144,9 @@ describe('AgentRequestInputOverlay', () => {
107
144
  decision: 'deny_with_feedback',
108
145
  approval_key: 'write_artifact:name:quotes.md',
109
146
  },
147
+ request_input_response: {
148
+ request_id: 'write_artifact:name:quotes.md',
149
+ },
110
150
  });
111
151
  });
112
152
 
@@ -125,6 +165,9 @@ describe('AgentRequestInputOverlay', () => {
125
165
  decision: 'allow_for_run',
126
166
  approval_key: 'write_artifact:name:quotes.md',
127
167
  },
168
+ request_input_response: {
169
+ request_id: 'write_artifact:name:quotes.md',
170
+ },
128
171
  });
129
172
  });
130
173
 
@@ -138,7 +181,9 @@ describe('AgentRequestInputOverlay', () => {
138
181
  fireEvent.click(screen.getByRole('button', { name: 'Allow once' }));
139
182
 
140
183
  expect(onSendMessage).toHaveBeenCalledTimes(1);
141
- expect(onSendMessage).toHaveBeenCalledWith('allow_once');
184
+ expect(onSendMessage).toHaveBeenCalledWith('allow_once', {
185
+ request_input_response: { request_id: 'write_artifact:name:quotes.md' },
186
+ });
142
187
  });
143
188
 
144
189
  it('renders legacy field-prefixed tool approval prompts with a friendly target', () => {