@inkeep/agents-manage-ui 0.12.1 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (221) hide show
  1. package/.next/standalone/agents-manage-ui/.next/BUILD_ID +1 -1
  2. package/.next/standalone/agents-manage-ui/.next/app-build-manifest.json +207 -211
  3. package/.next/standalone/agents-manage-ui/.next/app-path-routes-manifest.json +6 -6
  4. package/.next/standalone/agents-manage-ui/.next/build-manifest.json +5 -5
  5. package/.next/standalone/agents-manage-ui/.next/prerender-manifest.json +13 -13
  6. package/.next/standalone/agents-manage-ui/.next/react-loadable-manifest.json +2 -2
  7. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/page.js +2 -2
  8. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/page.js.nft.json +1 -1
  9. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/page_client-reference-manifest.js +1 -1
  10. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/api-keys/page.js +3 -3
  11. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/api-keys/page.js.nft.json +1 -1
  12. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/api-keys/page_client-reference-manifest.js +1 -1
  13. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/artifacts/[artifactComponentId]/page.js +2 -2
  14. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/artifacts/[artifactComponentId]/page.js.nft.json +1 -1
  15. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/artifacts/[artifactComponentId]/page_client-reference-manifest.js +1 -1
  16. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/artifacts/new/page.js +1 -1
  17. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/artifacts/new/page.js.nft.json +1 -1
  18. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/artifacts/new/page_client-reference-manifest.js +1 -1
  19. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/artifacts/page.js +2 -2
  20. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/artifacts/page.js.nft.json +1 -1
  21. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/artifacts/page_client-reference-manifest.js +1 -1
  22. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/components/[dataComponentId]/page.js +2 -2
  23. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/components/[dataComponentId]/page.js.nft.json +1 -1
  24. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/components/[dataComponentId]/page_client-reference-manifest.js +1 -1
  25. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/components/new/page.js +2 -2
  26. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/components/new/page.js.nft.json +1 -1
  27. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/components/new/page_client-reference-manifest.js +1 -1
  28. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/components/page.js +2 -2
  29. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/components/page.js.nft.json +1 -1
  30. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/components/page_client-reference-manifest.js +1 -1
  31. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/credentials/[credentialId]/page.js +1 -1
  32. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/credentials/[credentialId]/page.js.nft.json +1 -1
  33. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/credentials/[credentialId]/page_client-reference-manifest.js +1 -1
  34. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/credentials/new/bearer/page.js +2 -2
  35. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/credentials/new/bearer/page.js.nft.json +1 -1
  36. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/credentials/new/bearer/page_client-reference-manifest.js +1 -1
  37. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/credentials/new/page.js +1 -1
  38. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/credentials/new/page.js.nft.json +1 -1
  39. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/credentials/new/page_client-reference-manifest.js +1 -1
  40. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/credentials/new/providers/[providerId]/page.js +2 -2
  41. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/credentials/new/providers/[providerId]/page.js.nft.json +1 -1
  42. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/credentials/new/providers/[providerId]/page_client-reference-manifest.js +1 -1
  43. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/credentials/new/providers/page.js +2 -2
  44. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/credentials/new/providers/page.js.nft.json +1 -1
  45. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/credentials/new/providers/page_client-reference-manifest.js +1 -1
  46. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/credentials/page.js +2 -2
  47. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/credentials/page.js.nft.json +1 -1
  48. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/credentials/page_client-reference-manifest.js +1 -1
  49. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/graphs/[graphId]/page.js +2 -2
  50. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/graphs/[graphId]/page.js.nft.json +1 -1
  51. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/graphs/[graphId]/page_client-reference-manifest.js +1 -1
  52. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/graphs/new/page.js +2 -2
  53. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/graphs/new/page.js.nft.json +1 -1
  54. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/graphs/new/page_client-reference-manifest.js +1 -1
  55. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/graphs/page.js +2 -2
  56. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/graphs/page.js.nft.json +1 -1
  57. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/graphs/page_client-reference-manifest.js +1 -1
  58. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/mcp-servers/[mcpServerId]/edit/page.js +2 -2
  59. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/mcp-servers/[mcpServerId]/edit/page.js.nft.json +1 -1
  60. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/mcp-servers/[mcpServerId]/edit/page_client-reference-manifest.js +1 -1
  61. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/mcp-servers/[mcpServerId]/page.js +2 -2
  62. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/mcp-servers/[mcpServerId]/page.js.nft.json +1 -1
  63. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/mcp-servers/[mcpServerId]/page_client-reference-manifest.js +1 -1
  64. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/mcp-servers/new/page.js +2 -2
  65. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/mcp-servers/new/page.js.nft.json +1 -1
  66. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/mcp-servers/new/page_client-reference-manifest.js +1 -1
  67. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/mcp-servers/page.js +2 -2
  68. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/mcp-servers/page.js.nft.json +1 -1
  69. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/mcp-servers/page_client-reference-manifest.js +1 -1
  70. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/page.js +1 -1
  71. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/page.js.nft.json +1 -1
  72. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/page_client-reference-manifest.js +1 -1
  73. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/settings/page.js +1 -1
  74. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/settings/page.js.nft.json +1 -1
  75. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/settings/page_client-reference-manifest.js +1 -1
  76. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/traces/ai-calls/page.js +1 -1
  77. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/traces/ai-calls/page.js.nft.json +1 -1
  78. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/traces/ai-calls/page_client-reference-manifest.js +1 -1
  79. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/traces/conversations/[conversationId]/page.js +3 -3
  80. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/traces/conversations/[conversationId]/page.js.nft.json +1 -1
  81. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/traces/conversations/[conversationId]/page_client-reference-manifest.js +1 -1
  82. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/traces/page.js +3 -3
  83. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/traces/page.js.nft.json +1 -1
  84. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/[projectId]/traces/page_client-reference-manifest.js +1 -1
  85. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/page.js +3 -3
  86. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/page.js.nft.json +1 -1
  87. package/.next/standalone/agents-manage-ui/.next/server/app/[tenantId]/projects/page_client-reference-manifest.js +1 -1
  88. package/.next/standalone/agents-manage-ui/.next/server/app/_not-found/page.js +2 -2
  89. package/.next/standalone/agents-manage-ui/.next/server/app/_not-found/page.js.nft.json +1 -1
  90. package/.next/standalone/agents-manage-ui/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  91. package/.next/standalone/agents-manage-ui/.next/server/app/_not-found.html +1 -1
  92. package/.next/standalone/agents-manage-ui/.next/server/app/_not-found.rsc +9 -9
  93. package/.next/standalone/agents-manage-ui/.next/server/app/api/signoz/conversations/[conversationId]/route_client-reference-manifest.js +1 -1
  94. package/.next/standalone/agents-manage-ui/.next/server/app/api/signoz/route_client-reference-manifest.js +1 -1
  95. package/.next/standalone/agents-manage-ui/.next/server/app/page.js +2 -2
  96. package/.next/standalone/agents-manage-ui/.next/server/app/page.js.nft.json +1 -1
  97. package/.next/standalone/agents-manage-ui/.next/server/app/page_client-reference-manifest.js +1 -1
  98. package/.next/standalone/agents-manage-ui/.next/server/app-paths-manifest.json +6 -6
  99. package/.next/standalone/agents-manage-ui/.next/server/chunks/1167.js +1 -0
  100. package/.next/standalone/agents-manage-ui/.next/server/chunks/2415.js +1 -0
  101. package/.next/standalone/agents-manage-ui/.next/server/chunks/{292.js → 245.js} +11 -11
  102. package/.next/standalone/agents-manage-ui/.next/server/chunks/2539.js +13 -13
  103. package/.next/standalone/agents-manage-ui/.next/server/chunks/3547.js +1 -1
  104. package/.next/standalone/agents-manage-ui/.next/server/chunks/4843.js +1 -0
  105. package/.next/standalone/agents-manage-ui/.next/server/chunks/5495.js +1 -1
  106. package/.next/standalone/agents-manage-ui/.next/server/chunks/6212.js +1 -1
  107. package/.next/standalone/agents-manage-ui/.next/server/chunks/6229.js +1 -0
  108. package/.next/standalone/agents-manage-ui/.next/server/chunks/{8096.js → 6398.js} +1 -1
  109. package/.next/standalone/agents-manage-ui/.next/server/chunks/6525.js +4087 -0
  110. package/.next/standalone/agents-manage-ui/.next/server/chunks/6747.js +4 -4
  111. package/.next/standalone/agents-manage-ui/.next/server/chunks/7090.js +1 -0
  112. package/.next/standalone/agents-manage-ui/.next/server/chunks/7346.js +1 -0
  113. package/.next/standalone/agents-manage-ui/.next/server/chunks/7863.js +1 -0
  114. package/.next/standalone/agents-manage-ui/.next/server/chunks/8100.js +1 -1
  115. package/.next/standalone/agents-manage-ui/.next/server/chunks/8610.js +25 -1
  116. package/.next/standalone/agents-manage-ui/.next/server/chunks/9340.js +1 -0
  117. package/.next/standalone/agents-manage-ui/.next/server/chunks/{5546.js → 9516.js} +1 -1
  118. package/.next/standalone/agents-manage-ui/.next/server/middleware-build-manifest.js +1 -1
  119. package/.next/standalone/agents-manage-ui/.next/server/middleware-react-loadable-manifest.js +1 -1
  120. package/.next/standalone/agents-manage-ui/.next/server/pages/404.html +1 -1
  121. package/.next/standalone/agents-manage-ui/.next/server/pages/500.html +1 -1
  122. package/.next/standalone/agents-manage-ui/.next/server/server-reference-manifest.js +1 -1
  123. package/.next/standalone/agents-manage-ui/.next/server/server-reference-manifest.json +1 -1
  124. package/.next/standalone/agents-manage-ui/.next/static/chunks/{1064-f747155da2f9bf6e.js → 1064-3586ea45cf5c5379.js} +1 -1
  125. package/.next/standalone/agents-manage-ui/.next/static/chunks/1275-a8d88b014d15f391.js +1 -0
  126. package/.next/standalone/agents-manage-ui/.next/static/chunks/1558-20a9339c3529c948.js +1 -0
  127. package/.next/standalone/agents-manage-ui/.next/static/chunks/2063-5b4fb2ded7adef46.js +1 -0
  128. package/.next/standalone/agents-manage-ui/.next/static/chunks/6497-2a72e838c6240f76.js +1 -0
  129. package/.next/standalone/agents-manage-ui/.next/static/chunks/6501-2c90923d1b2f0f3e.js +1 -0
  130. package/.next/standalone/agents-manage-ui/.next/static/chunks/7167-157d248cc421c09a.js +1 -0
  131. package/.next/standalone/agents-manage-ui/.next/static/chunks/7305-4bde6b1356d61f7a.js +1 -0
  132. package/.next/standalone/agents-manage-ui/.next/static/chunks/{7352.9b2a8a672084bdf6.js → 7352.47444c26a143a75f.js} +1 -1
  133. package/.next/standalone/agents-manage-ui/.next/static/chunks/8130-c153c48b1fab6cb4.js +1 -0
  134. package/.next/standalone/agents-manage-ui/.next/static/chunks/{6443-dd27c846ef650d0a.js → 8486-01fbe9371d862c28.js} +6 -6
  135. package/.next/standalone/agents-manage-ui/.next/static/chunks/8831-e31bd19e515f8efd.js +1 -0
  136. package/.next/standalone/agents-manage-ui/.next/static/chunks/app/[tenantId]/projects/[projectId]/api-keys/page-1de478ef776542f5.js +1 -0
  137. package/.next/standalone/agents-manage-ui/.next/static/chunks/app/[tenantId]/projects/[projectId]/artifacts/[artifactComponentId]/{page-61379a8d1c1a9ca1.js → page-005fb6baca480791.js} +1 -1
  138. package/.next/standalone/agents-manage-ui/.next/static/chunks/app/[tenantId]/projects/[projectId]/artifacts/new/{page-61379a8d1c1a9ca1.js → page-005fb6baca480791.js} +1 -1
  139. package/.next/standalone/agents-manage-ui/.next/static/chunks/app/[tenantId]/projects/[projectId]/artifacts/{page-a6cfdce0698bfa2c.js → page-32fcf925e22bffde.js} +1 -1
  140. package/.next/standalone/agents-manage-ui/.next/static/chunks/app/[tenantId]/projects/[projectId]/components/[dataComponentId]/{page-b16426d953306ee7.js → page-3c5b276b763f1361.js} +1 -1
  141. package/.next/standalone/agents-manage-ui/.next/static/chunks/app/[tenantId]/projects/[projectId]/components/new/{page-b16426d953306ee7.js → page-3c5b276b763f1361.js} +1 -1
  142. package/.next/standalone/agents-manage-ui/.next/static/chunks/app/[tenantId]/projects/[projectId]/components/page-681b96a28f27bfad.js +1 -0
  143. package/.next/standalone/agents-manage-ui/.next/static/chunks/app/[tenantId]/projects/[projectId]/credentials/[credentialId]/{page-7cfa34591d1a6acd.js → page-afa97403afe44ea3.js} +1 -1
  144. package/.next/standalone/agents-manage-ui/.next/static/chunks/app/[tenantId]/projects/[projectId]/credentials/new/bearer/page-8e28892ce18b7605.js +1 -0
  145. package/.next/standalone/agents-manage-ui/.next/static/chunks/app/[tenantId]/projects/[projectId]/credentials/new/providers/[providerId]/page-b06c77bd874024bb.js +1 -0
  146. package/.next/standalone/agents-manage-ui/.next/static/chunks/app/[tenantId]/projects/[projectId]/credentials/{page-08fc17f254e5278e.js → page-b1977dfdbd7eaeb3.js} +1 -1
  147. package/.next/standalone/agents-manage-ui/.next/static/chunks/app/[tenantId]/projects/[projectId]/graphs/[graphId]/page-21f1392ae65ea31a.js +1 -0
  148. package/.next/standalone/agents-manage-ui/.next/static/chunks/app/[tenantId]/projects/[projectId]/graphs/new/page-b7ee3944e6a5c03d.js +1 -0
  149. package/.next/standalone/agents-manage-ui/.next/static/chunks/app/[tenantId]/projects/[projectId]/graphs/page-941f95225d71f8b5.js +1 -0
  150. package/.next/standalone/agents-manage-ui/.next/static/chunks/app/[tenantId]/projects/[projectId]/mcp-servers/[mcpServerId]/edit/{page-8ce40458e68f1441.js → page-4498950740edb744.js} +1 -1
  151. package/.next/standalone/agents-manage-ui/.next/static/chunks/app/[tenantId]/projects/[projectId]/mcp-servers/new/page-f34ada0e40bb0f1a.js +1 -0
  152. package/.next/standalone/agents-manage-ui/.next/static/chunks/app/[tenantId]/projects/[projectId]/mcp-servers/page-7f6d40ae3f2fd925.js +1 -0
  153. package/.next/standalone/agents-manage-ui/.next/static/chunks/app/[tenantId]/projects/[projectId]/not-found-f95764dcfe0e1e9d.js +1 -0
  154. package/.next/standalone/agents-manage-ui/.next/static/chunks/app/[tenantId]/projects/[projectId]/settings/{page-5a7b693a09f13234.js → page-373cff59531c6b45.js} +1 -1
  155. package/.next/standalone/agents-manage-ui/.next/static/chunks/app/[tenantId]/projects/[projectId]/traces/page-506bd20e106e26e3.js +1 -0
  156. package/.next/standalone/agents-manage-ui/.next/static/chunks/app/[tenantId]/projects/page-7989cf35493dd2a2.js +1 -0
  157. package/.next/standalone/agents-manage-ui/.next/static/chunks/app/layout-db7d3541e54a712c.js +1 -0
  158. package/.next/standalone/agents-manage-ui/.next/static/chunks/{webpack-b20dc8e12f728891.js → webpack-eada866d0a3f0f14.js} +1 -1
  159. package/.next/standalone/agents-manage-ui/.next/static/css/ff74e9dcb72fa41b.css +1 -0
  160. package/.next/standalone/agents-manage-ui/package.json +4 -1
  161. package/.next/standalone/package.json +1 -0
  162. package/.next/standalone/packages/agents-core/package.json +1 -1
  163. package/package.json +7 -4
  164. package/src/components/form/expandable-field.tsx +17 -11
  165. package/src/components/form/generic-input.tsx +2 -2
  166. package/src/components/form/prompt-editor.tsx +245 -0
  167. package/src/components/graph/graph.tsx +7 -5
  168. package/src/components/graph/nodes/agent-node.tsx +4 -2
  169. package/src/components/graph/nodes/mcp-node.tsx +5 -3
  170. package/src/components/graph/sidepane/edges/edge-editor.tsx +2 -2
  171. package/src/components/graph/sidepane/metadata/metadata-editor.tsx +3 -4
  172. package/src/components/graph/sidepane/nodes/agent-node-editor.tsx +2 -4
  173. package/src/components/graph/sidepane/nodes/expandable-text-area.tsx +54 -14
  174. package/src/components/graph/sidepane/nodes/mcp-node-editor.tsx +6 -4
  175. package/src/components/graph/toolbar/toolbar.tsx +19 -0
  176. package/src/components/projects/form/form-configuration.ts +1 -1
  177. package/src/components/projects/form/project-form.tsx +14 -8
  178. package/src/components/projects/form/project-models-section.tsx +26 -2
  179. package/src/components/projects/form/project-stopwhen-section.tsx +18 -2
  180. package/src/components/projects/form/validation.ts +13 -4
  181. package/src/components/projects/project-item.tsx +2 -1
  182. package/src/components/traces/timeline/timeline-wrapper.tsx +2 -2
  183. package/src/features/graph/commands/commands.ts +24 -24
  184. package/src/features/graph/state/use-graph-store.ts +199 -172
  185. package/src/features/graph/ui/use-graph-shortcuts.ts +2 -2
  186. package/src/hooks/use-graph-errors.ts +7 -9
  187. package/src/hooks/use-node-editor.ts +4 -4
  188. package/src/lib/__tests__/context-suggestions.test.ts +205 -0
  189. package/src/lib/context-suggestions.ts +102 -0
  190. package/src/lib/utils.ts +4 -0
  191. package/.next/standalone/agents-manage-ui/.next/server/chunks/1156.js +0 -1
  192. package/.next/standalone/agents-manage-ui/.next/server/chunks/3859.js +0 -25
  193. package/.next/standalone/agents-manage-ui/.next/server/chunks/5232.js +0 -1
  194. package/.next/standalone/agents-manage-ui/.next/server/chunks/6114.js +0 -4087
  195. package/.next/standalone/agents-manage-ui/.next/server/chunks/6997.js +0 -1
  196. package/.next/standalone/agents-manage-ui/.next/server/chunks/8298.js +0 -1
  197. package/.next/standalone/agents-manage-ui/.next/server/chunks/9812.js +0 -1
  198. package/.next/standalone/agents-manage-ui/.next/static/chunks/1558-cf7aef893a85469e.js +0 -1
  199. package/.next/standalone/agents-manage-ui/.next/static/chunks/2063-00dd6285929e419a.js +0 -1
  200. package/.next/standalone/agents-manage-ui/.next/static/chunks/2616-afea50e929636181.js +0 -1
  201. package/.next/standalone/agents-manage-ui/.next/static/chunks/5635-a3e053f2a2633b0f.js +0 -1
  202. package/.next/standalone/agents-manage-ui/.next/static/chunks/6497-5a3efd5d17896e0b.js +0 -1
  203. package/.next/standalone/agents-manage-ui/.next/static/chunks/7167-d00c25860bc43555.js +0 -1
  204. package/.next/standalone/agents-manage-ui/.next/static/chunks/7305-80fb496a6a7b01cf.js +0 -1
  205. package/.next/standalone/agents-manage-ui/.next/static/chunks/8831-9d23a1d8c9fb3858.js +0 -1
  206. package/.next/standalone/agents-manage-ui/.next/static/chunks/app/[tenantId]/projects/[projectId]/api-keys/page-3e911bcedbdcc8b0.js +0 -1
  207. package/.next/standalone/agents-manage-ui/.next/static/chunks/app/[tenantId]/projects/[projectId]/components/page-53ad78b81054c5f6.js +0 -1
  208. package/.next/standalone/agents-manage-ui/.next/static/chunks/app/[tenantId]/projects/[projectId]/credentials/new/bearer/page-46c8e4772748bf3c.js +0 -1
  209. package/.next/standalone/agents-manage-ui/.next/static/chunks/app/[tenantId]/projects/[projectId]/credentials/new/providers/[providerId]/page-db65b50c3319a62c.js +0 -1
  210. package/.next/standalone/agents-manage-ui/.next/static/chunks/app/[tenantId]/projects/[projectId]/graphs/[graphId]/page-00765523b4cc6114.js +0 -1
  211. package/.next/standalone/agents-manage-ui/.next/static/chunks/app/[tenantId]/projects/[projectId]/graphs/new/page-4791623af5ab27ea.js +0 -1
  212. package/.next/standalone/agents-manage-ui/.next/static/chunks/app/[tenantId]/projects/[projectId]/graphs/page-b645d7373e4b7a62.js +0 -1
  213. package/.next/standalone/agents-manage-ui/.next/static/chunks/app/[tenantId]/projects/[projectId]/mcp-servers/new/page-2543a9b4438b0b03.js +0 -1
  214. package/.next/standalone/agents-manage-ui/.next/static/chunks/app/[tenantId]/projects/[projectId]/mcp-servers/page-15fba6cf333f2f2a.js +0 -1
  215. package/.next/standalone/agents-manage-ui/.next/static/chunks/app/[tenantId]/projects/[projectId]/not-found-abb1f829baf33e89.js +0 -1
  216. package/.next/standalone/agents-manage-ui/.next/static/chunks/app/[tenantId]/projects/[projectId]/traces/page-c5a019309939d912.js +0 -1
  217. package/.next/standalone/agents-manage-ui/.next/static/chunks/app/[tenantId]/projects/page-750a94d65d9266d6.js +0 -1
  218. package/.next/standalone/agents-manage-ui/.next/static/chunks/app/layout-c42ea39210c86d1d.js +0 -1
  219. package/.next/standalone/agents-manage-ui/.next/static/css/02016a706b2fdd40.css +0 -1
  220. /package/.next/standalone/agents-manage-ui/.next/static/{5LuVpO2ZOs-I6neEc3jpn → iLBcTp7vHsMdZImZWajUt}/_buildManifest.js +0 -0
  221. /package/.next/standalone/agents-manage-ui/.next/static/{5LuVpO2ZOs-I6neEc3jpn → iLBcTp7vHsMdZImZWajUt}/_ssgManifest.js +0 -0
@@ -0,0 +1,245 @@
1
+ import { type FC, type RefObject, useEffect, useImperativeHandle, useMemo, useRef } from 'react';
2
+ import { autocompletion, type CompletionSource, startCompletion } from '@codemirror/autocomplete';
3
+ import { Decoration, ViewPlugin, EditorView, type DecorationSet } from '@codemirror/view';
4
+ import { linter, type Diagnostic } from '@codemirror/lint';
5
+ import { duotoneDark, duotoneLight } from '@uiw/codemirror-theme-duotone';
6
+ import CodeMirror, {
7
+ type ReactCodeMirrorProps,
8
+ type Range,
9
+ type ReactCodeMirrorRef,
10
+ } from '@uiw/react-codemirror';
11
+ import { useTheme } from 'next-themes';
12
+ import { cn } from '@/lib/utils';
13
+ import { getContextSuggestions } from '@/lib/context-suggestions';
14
+ import { useGraphStore } from '@/features/graph/state/use-graph-store';
15
+
16
+ // Decoration for template variables
17
+ const templateVariableDecoration = Decoration.mark({
18
+ class: 'cm-template-variable',
19
+ });
20
+
21
+ // Plugin to highlight template variables
22
+ const templateVariablePlugin = ViewPlugin.fromClass(
23
+ class {
24
+ decorations: DecorationSet;
25
+
26
+ constructor(view: EditorView) {
27
+ this.decorations = this.buildDecorations(view);
28
+ }
29
+
30
+ update(update: any) {
31
+ if (update.docChanged) {
32
+ this.decorations = this.buildDecorations(update.view);
33
+ }
34
+ }
35
+
36
+ buildDecorations(view: EditorView): DecorationSet {
37
+ const decorations: Range<Decoration>[] = [];
38
+ const regex = /\{\{([^}]+)}}/g;
39
+
40
+ for (let i = 0; i < view.state.doc.lines; i++) {
41
+ const line = view.state.doc.line(i + 1);
42
+ let match: RegExpExecArray | null;
43
+
44
+ while ((match = regex.exec(line.text)) !== null) {
45
+ const from = line.from + match.index;
46
+ const to = line.from + match.index + match[0].length;
47
+ decorations.push(templateVariableDecoration.range(from, to));
48
+ }
49
+ }
50
+
51
+ return Decoration.set(decorations);
52
+ }
53
+ },
54
+ {
55
+ decorations: (v) => v.decorations,
56
+ }
57
+ );
58
+
59
+ // Theme for template variables
60
+ const templateVariableTheme = EditorView.theme({
61
+ '& .cm-template-variable': {
62
+ color: '#e67e22', // Orange color for variables
63
+ fontWeight: 'bold',
64
+ },
65
+ '&.cm-dark .cm-template-variable': {
66
+ color: '#f39c12', // Lighter orange for dark theme
67
+ },
68
+ });
69
+
70
+ const RESERVED_KEYS = new Set(['$time', '$date', '$timestamp', '$now']);
71
+
72
+ function isJMESPathExpressions(key: string): boolean {
73
+ if (key.startsWith('length(')) {
74
+ return true;
75
+ }
76
+ return key.includes('[?') || key.includes('[*]');
77
+ }
78
+
79
+ // Create linter for template variable validation
80
+ function createTemplateVariableLinter(suggestions: string[]) {
81
+ return linter((view) => {
82
+ const diagnostics: Diagnostic[] = [];
83
+ const validVariables = new Set(suggestions);
84
+ const regex = /\{\{([^}]+)}}/g;
85
+
86
+ for (let i = 0; i < view.state.doc.lines; i++) {
87
+ const line = view.state.doc.line(i + 1);
88
+ let match: RegExpExecArray | null;
89
+
90
+ while ((match = regex.exec(line.text)) !== null) {
91
+ const from = line.from + match.index;
92
+ const to = line.from + match.index + match[0].length;
93
+ const variableName = match[1];
94
+
95
+ // Check if variable is valid (in suggestions) or reserved
96
+ const isValid =
97
+ validVariables.has(variableName) ||
98
+ RESERVED_KEYS.has(variableName) ||
99
+ variableName.startsWith('$env.') ||
100
+ // Exclude arrays from linting, as they are indicated with [*] in the suggestions
101
+ variableName.includes('[') ||
102
+ isJMESPathExpressions(variableName);
103
+
104
+ if (!isValid) {
105
+ diagnostics.push({
106
+ from,
107
+ to,
108
+ severity: 'error',
109
+ message: `Unknown variable: ${variableName}`,
110
+ });
111
+ }
112
+ }
113
+ }
114
+
115
+ return diagnostics;
116
+ });
117
+ }
118
+
119
+ // Create autocomplete source for context variables
120
+ function createContextAutocompleteSource(suggestions: string[]): CompletionSource {
121
+ return (context) => {
122
+ const { state, pos } = context;
123
+ const line = state.doc.lineAt(pos);
124
+ const to = pos - line.from;
125
+ const textBefore = line.text.slice(0, to);
126
+ // Check if we're after a { character
127
+ const match = textBefore.match(/\{([^}]*)$/);
128
+ if (!match) return null;
129
+
130
+ const query = match[1].toLowerCase();
131
+ const filteredSuggestions = suggestions.filter((s) => s.toLowerCase().includes(query));
132
+ const nextChar = line.text[to];
133
+ return {
134
+ from: pos - match[1].length,
135
+ to: pos,
136
+ options: ['$env.', ...RESERVED_KEYS, ...filteredSuggestions].map((suggestion) => ({
137
+ label: suggestion,
138
+ apply: `{${suggestion}${nextChar === '}' ? '}' : '}}'}`, // insert `}}` at the end if next character is not `}`
139
+ })),
140
+ };
141
+ };
142
+ }
143
+
144
+ export interface TextareaWithSuggestionsProps extends Omit<ReactCodeMirrorProps, 'onChange'> {
145
+ onChange: (value: string) => void;
146
+ placeholder?: string;
147
+ disabled?: boolean;
148
+ readOnly?: boolean;
149
+ ref?: RefObject<{ insertTemplateVariable: () => void }>;
150
+ }
151
+
152
+ function tryJsonParse(json: string): object {
153
+ if (!json.trim()) {
154
+ return {};
155
+ }
156
+ try {
157
+ return JSON.parse(json);
158
+ } catch {}
159
+ return {};
160
+ }
161
+
162
+ export const PromptEditor: FC<TextareaWithSuggestionsProps> = ({
163
+ className,
164
+ value,
165
+ onChange,
166
+ placeholder,
167
+ disabled,
168
+ readOnly,
169
+ ref,
170
+ ...rest
171
+ }) => {
172
+ const editorRef = useRef<ReactCodeMirrorRef | null>(null);
173
+ const { resolvedTheme } = useTheme();
174
+ const isDark = resolvedTheme === 'dark';
175
+ useEffect(() => {
176
+ editorRef.current = new EditorView();
177
+ }, []);
178
+
179
+ useImperativeHandle(ref, () => ({
180
+ insertTemplateVariable() {
181
+ const view = editorRef.current?.view;
182
+ if (!view) {
183
+ return;
184
+ }
185
+ const { doc, selection } = view.state;
186
+ // If there's a caret, insert at caret; otherwise, fall back to end of the current line.
187
+ const insertPos = selection.main.empty ? selection.main.head : doc.line(doc.lines).to;
188
+ // Insert "{}" and put the cursor between
189
+ view.dispatch({
190
+ changes: { from: insertPos, to: insertPos, insert: '{}' },
191
+ selection: { anchor: insertPos + 1 },
192
+ scrollIntoView: true,
193
+ });
194
+ startCompletion(view);
195
+ },
196
+ }));
197
+
198
+ const contextConfig = useGraphStore((state) => state.metadata.contextConfig);
199
+
200
+ const extensions = useMemo(() => {
201
+ const contextVariables = tryJsonParse(contextConfig.contextVariables);
202
+ const requestContextSchema = tryJsonParse(contextConfig.requestContextSchema);
203
+ const suggestions = getContextSuggestions({
204
+ requestContextSchema,
205
+ // @ts-expect-error -- todo: improve type
206
+ contextVariables,
207
+ });
208
+ return [
209
+ autocompletion({
210
+ override: [createContextAutocompleteSource(suggestions)],
211
+ compareCompletions(_a, _b) {
212
+ // Disable default localCompare sorting
213
+ return -1;
214
+ },
215
+ }),
216
+ templateVariablePlugin,
217
+ templateVariableTheme,
218
+ createTemplateVariableLinter(suggestions),
219
+ ];
220
+ }, [contextConfig]);
221
+
222
+ return (
223
+ <CodeMirror
224
+ ref={editorRef}
225
+ {...rest}
226
+ value={value || ''}
227
+ onChange={onChange}
228
+ extensions={extensions}
229
+ theme={isDark ? duotoneDark : duotoneLight}
230
+ placeholder={placeholder}
231
+ editable={!disabled && !readOnly}
232
+ basicSetup={{
233
+ lineNumbers: false,
234
+ foldGutter: false,
235
+ highlightActiveLine: false,
236
+ }}
237
+ data-disabled={disabled ? '' : undefined}
238
+ data-read-only={readOnly ? '' : undefined}
239
+ className={cn(
240
+ 'h-full [&>.cm-editor]:max-h-[inherit] [&>.cm-editor]:!bg-transparent dark:[&>.cm-editor]:!bg-input/30 [&>.cm-editor]:!outline-none [&>.cm-editor]:rounded-[7px] [&>.cm-editor]:px-3 [&>.cm-editor]:py-2 leading-2 text-xs font-mono rounded-md border border-input shadow-xs transition-[color,box-shadow] data-disabled:cursor-not-allowed data-disabled:opacity-50 data-disabled:bg-muted data-invalid:border-destructive has-[.cm-focused]:border-ring has-[.cm-focused]:ring-ring/50 has-[.cm-focused]:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive',
241
+ className
242
+ )}
243
+ />
244
+ );
245
+ };
@@ -26,7 +26,7 @@ import {
26
26
  extractGraphMetadata,
27
27
  serializeGraphData,
28
28
  } from '@/features/graph/domain';
29
- import { useGraphStore } from '@/features/graph/state/use-graph-store';
29
+ import { useGraphActions, useGraphStore } from '@/features/graph/state/use-graph-store';
30
30
  import { useGraphShortcuts } from '@/features/graph/ui/use-graph-shortcuts';
31
31
  import { useGraphErrors } from '@/hooks/use-graph-errors';
32
32
  import { useSidePane } from '@/hooks/use-side-pane';
@@ -180,20 +180,22 @@ function Flow({
180
180
  }, [graph?.agents]);
181
181
 
182
182
  const { screenToFlowPosition, updateNodeData, fitView } = useReactFlow();
183
+ const { storeNodes, edges, metadata } = useGraphStore((state) => ({
184
+ storeNodes: state.nodes,
185
+ edges: state.edges,
186
+ metadata: state.metadata,
187
+ }));
183
188
  const {
184
- nodes: storeNodes,
185
- edges,
186
189
  setNodes,
187
190
  setEdges,
188
191
  onNodesChange,
189
192
  onEdgesChange,
190
- metadata,
191
193
  setMetadata,
192
194
  setInitial,
193
195
  markSaved,
194
196
  clearSelection,
195
197
  markUnsaved,
196
- } = useGraphStore();
198
+ } = useGraphActions();
197
199
 
198
200
  // Always use enriched nodes for ReactFlow
199
201
  const nodes = useMemo(() => enrichNodes(storeNodes), [storeNodes, enrichNodes]);
@@ -46,8 +46,10 @@ export function AgentNode(props: NodeProps & { data: AgentNodeData }) {
46
46
  const { name, isDefault, description, models } = data;
47
47
  const modelName = models?.base?.model;
48
48
 
49
- const dataComponentLookup = useGraphStore((state) => state.dataComponentLookup);
50
- const artifactComponentLookup = useGraphStore((state) => state.artifactComponentLookup);
49
+ const { dataComponentLookup, artifactComponentLookup } = useGraphStore((state) => ({
50
+ dataComponentLookup: state.dataComponentLookup,
51
+ artifactComponentLookup: state.artifactComponentLookup,
52
+ }));
51
53
  const { getNodeErrors, hasNodeErrors } = useGraphErrors();
52
54
 
53
55
  // Use the agent ID from node data if available, otherwise fall back to React Flow node ID
@@ -12,9 +12,11 @@ const TOOLS_SHOWN_LIMIT = 4;
12
12
 
13
13
  export function MCPNode(props: NodeProps & { data: MCPNodeData }) {
14
14
  const { data, selected } = props;
15
- const toolLookup = useGraphStore((state) => state.toolLookup);
16
- const agentToolConfigLookup = useGraphStore((state) => state.agentToolConfigLookup);
17
- const edges = useGraphStore((state) => state.edges);
15
+ const { toolLookup, agentToolConfigLookup, edges } = useGraphStore((state) => ({
16
+ toolLookup: state.toolLookup,
17
+ agentToolConfigLookup: state.agentToolConfigLookup,
18
+ edges: state.edges,
19
+ }));
18
20
 
19
21
  const name = data.name || `Tool: ${data.toolId}`;
20
22
  const imageUrl = data.imageUrl;
@@ -3,7 +3,7 @@ import { Spline } from 'lucide-react';
3
3
  import { DashedSplineIcon } from '@/components/icons/dashed-spline';
4
4
  import { Checkbox } from '@/components/ui/checkbox';
5
5
  import { Label } from '@/components/ui/label';
6
- import { useGraphStore } from '@/features/graph/state/use-graph-store';
6
+ import { useGraphActions } from '@/features/graph/state/use-graph-store';
7
7
  import type { A2AEdgeData } from '../../configuration/edge-types';
8
8
 
9
9
  type RelationshipOptionProps = {
@@ -75,7 +75,7 @@ function EdgeEditor({ selectedEdge }: EdgeEditorProps) {
75
75
  const { updateEdgeData, setEdges } = useReactFlow();
76
76
  const sourceNode = useNodesData(selectedEdge.source);
77
77
  const targetNode = useNodesData(selectedEdge.target);
78
- const markUnsaved = useGraphStore((state) => state.markUnsaved);
78
+ const { markUnsaved } = useGraphActions();
79
79
 
80
80
  // Check if this is a self-loop (source and target are the same)
81
81
  const isSelfLoop = selectedEdge.source === selectedEdge.target;
@@ -19,7 +19,7 @@ import { Separator } from '@/components/ui/separator';
19
19
  import { Textarea } from '@/components/ui/textarea';
20
20
  import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
21
21
  import { useRuntimeConfig } from '@/contexts/runtime-config-context';
22
- import { useGraphStore } from '@/features/graph/state/use-graph-store';
22
+ import { useGraphActions, useGraphStore } from '@/features/graph/state/use-graph-store';
23
23
  import { useAutoPrefillIdZustand } from '@/hooks/use-auto-prefill-id-zustand';
24
24
  import { useProjectData } from '@/hooks/use-project-data';
25
25
  import { CollapsibleSettings } from '../collapsible-settings';
@@ -64,7 +64,7 @@ function MetadataEditor() {
64
64
  // Fetch project data for inheritance indicators
65
65
  const { project } = useProjectData();
66
66
 
67
- const { markUnsaved, setMetadata } = useGraphStore();
67
+ const { markUnsaved, setMetadata } = useGraphActions();
68
68
 
69
69
  const updateMetadata: typeof setMetadata = useCallback(
70
70
  (...attrs) => {
@@ -148,10 +148,9 @@ function MetadataEditor() {
148
148
  <div className="space-y-2">
149
149
  <ExpandableTextArea
150
150
  id="graph-prompt"
151
- name="graph-prompt"
152
151
  label="Graph prompt"
153
152
  value={graphPrompt || ''}
154
- onChange={(e) => updateMetadata('graphPrompt', e.target.value)}
153
+ onChange={(value) => updateMetadata('graphPrompt', value)}
155
154
  placeholder="System-level instructions for this graph..."
156
155
  className="max-h-96"
157
156
  />
@@ -135,11 +135,9 @@ export function AgentNodeEditor({
135
135
 
136
136
  <div className="space-y-2">
137
137
  <ExpandableTextArea
138
- ref={(el) => setFieldRef('prompt', el)}
139
138
  id="prompt"
140
- name="prompt"
141
139
  value={selectedNode.data.prompt || ''}
142
- onChange={(e) => updatePath('prompt', e.target.value)}
140
+ onChange={(value) => updatePath('prompt', value)}
143
141
  placeholder="You are a helpful assistant..."
144
142
  data-invalid={errorHelpers?.hasFieldError('prompt') ? '' : undefined}
145
143
  className="w-full max-h-96 data-invalid:border-red-300 data-invalid:focus-visible:border-red-300 data-invalid:focus-visible:ring-red-300"
@@ -159,7 +157,7 @@ export function AgentNodeEditor({
159
157
  />
160
158
  <Separator />
161
159
  {/* Agent Execution Limits */}
162
- <div className="space-y-8 ">
160
+ <div className="space-y-8">
163
161
  <SectionHeader
164
162
  title="Execution limits"
165
163
  description="Configure agent-level execution limits for steps within this agent."
@@ -1,32 +1,72 @@
1
+ import { type FC, type RefObject, useRef, type ComponentProps } from 'react';
1
2
  import { ExpandableField } from '@/components/form/expandable-field';
2
- import { Textarea } from '@/components/ui/textarea';
3
- import { useCursorToEnd } from '@/hooks/use-cursor-to-end';
3
+ import { Button } from '@/components/ui/button';
4
+ import { Braces } from 'lucide-react';
5
+ import { TooltipTrigger, Tooltip, TooltipContent } from '@/components/ui/tooltip';
6
+ import { PromptEditor } from '@/components/form/prompt-editor';
7
+ import { cn } from '@/lib/utils';
4
8
 
5
- function ExpandedTextArea({ ...props }) {
6
- const textareaRef = useCursorToEnd<HTMLTextAreaElement>();
9
+ // Extract inner type from RefObject<T>
10
+ type RefValue<T> = T extends RefObject<infer R> ? R : never;
7
11
 
12
+ const PromptEditorWithAddVariables: FC<
13
+ ComponentProps<typeof PromptEditor> & {
14
+ tooltipClassName: string;
15
+ }
16
+ > = ({ tooltipClassName, ...props }) => {
17
+ const codemirrorRef = useRef<RefValue<typeof props.ref>>(null!);
18
+ const variablesText = 'Add variables';
8
19
  return (
9
- <Textarea
10
- {...props}
11
- ref={textareaRef}
12
- className="w-full max-h-full resize-none h-full"
13
- autoFocus
14
- />
20
+ <div className="h-full relative">
21
+ <PromptEditor ref={codemirrorRef} {...props} />
22
+ <Tooltip>
23
+ <TooltipTrigger asChild>
24
+ <Button
25
+ variant="ghost"
26
+ size="icon"
27
+ className={cn(
28
+ 'absolute bottom-2.5 h-6 w-6 hover:text-foreground transition-all backdrop-blur-sm bg-white/90 hover:bg-white/95 dark:bg-card dark:hover:bg-accent border border-border shadow-md dark:shadow-lg',
29
+ tooltipClassName
30
+ )}
31
+ type="button"
32
+ onClick={() => {
33
+ codemirrorRef.current.insertTemplateVariable();
34
+ }}
35
+ >
36
+ <Braces className="h-4 w-4 text-muted-foreground" />
37
+ <span className="sr-only">{variablesText}</span>
38
+ </Button>
39
+ </TooltipTrigger>
40
+ <TooltipContent>
41
+ {variablesText}
42
+ </TooltipContent>
43
+ </Tooltip>
44
+ </div>
15
45
  );
16
- }
46
+ };
17
47
 
18
48
  export function ExpandableTextArea({
19
49
  label,
20
50
  isRequired = false,
21
51
  ...props
22
- }: { label: string; isRequired?: boolean } & React.ComponentProps<typeof Textarea>) {
52
+ }: {
53
+ label: string;
54
+ isRequired?: boolean;
55
+ } & React.ComponentProps<typeof PromptEditor>) {
23
56
  return (
24
57
  <ExpandableField
25
58
  name={props.id || 'expandable-textarea'}
26
59
  label={label}
27
60
  isRequired={isRequired}
28
- compactView={<Textarea {...props} />}
29
- expandedView={<ExpandedTextArea {...props} />}
61
+ compactView={<PromptEditorWithAddVariables {...props} tooltipClassName="right-10" />}
62
+ expandedView={
63
+ <PromptEditorWithAddVariables
64
+ {...props}
65
+ autoFocus
66
+ className="[&>.cm-editor]:h-full"
67
+ tooltipClassName="right-2.5"
68
+ />
69
+ }
30
70
  />
31
71
  );
32
72
  }
@@ -10,7 +10,7 @@ import { ExternalLink } from '@/components/ui/external-link';
10
10
  import { Input } from '@/components/ui/input';
11
11
  import { Label } from '@/components/ui/label';
12
12
  import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
13
- import { useGraphStore } from '@/features/graph/state/use-graph-store';
13
+ import { useGraphActions, useGraphStore } from '@/features/graph/state/use-graph-store';
14
14
  import { getToolTypeAndName } from '@/lib/utils/mcp-utils';
15
15
  import {
16
16
  getCurrentHeadersForNode,
@@ -33,11 +33,13 @@ export function MCPServerNodeEditor({
33
33
  tenantId: string;
34
34
  projectId: string;
35
35
  }>();
36
- const markUnsaved = useGraphStore((state) => state.markUnsaved);
36
+ const { markUnsaved } = useGraphActions();
37
37
 
38
38
  // Only use toolLookup - single source of truth
39
- const toolLookup = useGraphStore((state) => state.toolLookup);
40
- const edges = useGraphStore((state) => state.edges);
39
+ const { toolLookup, edges } = useGraphStore((state) => ({
40
+ toolLookup: state.toolLookup,
41
+ edges: state.edges,
42
+ }));
41
43
 
42
44
  const getCurrentHeaders = useCallback((): Record<string, string> => {
43
45
  return getCurrentHeadersForNode(selectedNode, agentToolConfigLookup, edges);
@@ -2,6 +2,8 @@ import { Play, Settings } from 'lucide-react';
2
2
  import { Button } from '@/components/ui/button';
3
3
  import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
4
4
  import { useGraphStore } from '@/features/graph/state/use-graph-store';
5
+ import { useEffect, useRef } from 'react';
6
+ import { isMacOs } from '@/lib/utils';
5
7
 
6
8
  interface ToolbarProps {
7
9
  onSubmit: () => void;
@@ -17,6 +19,7 @@ export function Toolbar({
17
19
  setShowPlayground,
18
20
  }: ToolbarProps) {
19
21
  const dirty = useGraphStore((state) => state.dirty);
22
+ const saveButtonRef = useRef<HTMLButtonElement>(null!);
20
23
  const PreviewButton = (
21
24
  <Button
22
25
  disabled={dirty || isPreviewDisabled}
@@ -29,6 +32,21 @@ export function Toolbar({
29
32
  </Button>
30
33
  );
31
34
 
35
+ useEffect(() => {
36
+ function handleSaveShortcut(event: KeyboardEvent) {
37
+ const isShortcutPressed = (isMacOs() ? event.metaKey : event.ctrlKey) && event.key === 's';
38
+ if (!isShortcutPressed) return;
39
+ event.preventDefault();
40
+ // Using button ref instead onSubmit to respect button's disabled state
41
+ saveButtonRef.current.click();
42
+ }
43
+
44
+ window.addEventListener('keydown', handleSaveShortcut);
45
+ return () => {
46
+ window.removeEventListener('keydown', handleSaveShortcut);
47
+ };
48
+ }, []);
49
+
32
50
  return (
33
51
  <div className="flex gap-2">
34
52
  {dirty || isPreviewDisabled ? (
@@ -49,6 +67,7 @@ export function Toolbar({
49
67
  onClick={onSubmit}
50
68
  variant={dirty ? 'default' : 'outline'}
51
69
  disabled={!dirty && !isPreviewDisabled}
70
+ ref={saveButtonRef}
52
71
  >
53
72
  {isPreviewDisabled ? 'Save' : 'Save changes'}
54
73
  </Button>
@@ -12,7 +12,7 @@ export const defaultValues: ProjectFormData = {
12
12
  models: {
13
13
  base: {
14
14
  model: DEFAULT_ANTHROPIC_BASE_MODEL,
15
- providerOptions: {},
15
+ providerOptions: undefined,
16
16
  },
17
17
  structuredOutput: {
18
18
  model: DEFAULT_ANTHROPIC_STRUCTURED_OUTPUT_MODEL,
@@ -34,9 +34,9 @@ const serializeData = (data: ProjectFormData) => {
34
34
  };
35
35
 
36
36
  const cleanStopWhen = (stopWhen: any) => {
37
- // If stopWhen is null, undefined, or empty object, return undefined
37
+ // If stopWhen is null, undefined, or empty object, return empty object (undefined will not update the field)
38
38
  if (!stopWhen || (typeof stopWhen === 'object' && Object.keys(stopWhen).length === 0)) {
39
- return undefined;
39
+ return {};
40
40
  }
41
41
 
42
42
  // Clean the individual properties - remove null/undefined values
@@ -48,9 +48,9 @@ const serializeData = (data: ProjectFormData) => {
48
48
  cleaned.stepCountIs = stopWhen.stepCountIs;
49
49
  }
50
50
 
51
- // If no valid properties, return undefined
51
+ // If no valid properties, return empty object (undefined will not update the field)
52
52
  if (Object.keys(cleaned).length === 0) {
53
- return undefined;
53
+ return {};
54
54
  }
55
55
 
56
56
  return cleaned;
@@ -81,6 +81,15 @@ const serializeData = (data: ProjectFormData) => {
81
81
  };
82
82
  };
83
83
 
84
+ const createDefaultValues = (initialData?: ProjectFormData) => {
85
+ return {
86
+ ...initialData,
87
+ // Handle null values from database - if an object field is null, validation will fail so we need to set it to an empty object
88
+ stopWhen: initialData?.stopWhen || {},
89
+ models: initialData?.models || { base: { model: '', providerOptions: null } },
90
+ };
91
+ };
92
+
84
93
  export function ProjectForm({
85
94
  tenantId,
86
95
  projectId,
@@ -90,10 +99,7 @@ export function ProjectForm({
90
99
  }: ProjectFormProps) {
91
100
  const form = useForm<ProjectFormData>({
92
101
  resolver: zodResolver(projectSchema),
93
- defaultValues: {
94
- ...defaultValues,
95
- ...initialData,
96
- },
102
+ defaultValues: initialData ? createDefaultValues(initialData) : { ...defaultValues },
97
103
  });
98
104
 
99
105
  const { isSubmitting } = form.formState;
@@ -1,7 +1,8 @@
1
1
  'use client';
2
2
 
3
3
  import { ChevronRight, Info } from 'lucide-react';
4
- import { type Control, useController, useWatch } from 'react-hook-form';
4
+ import { useEffect, useState } from 'react';
5
+ import { type Control, useController, useFormState, useWatch } from 'react-hook-form';
5
6
  import { ExpandableJsonEditor } from '@/components/form/expandable-json-editor';
6
7
  import { FormFieldWrapper } from '@/components/form/form-field-wrapper';
7
8
  import { ModelSelector } from '@/components/graph/sidepane/nodes/model-selector';
@@ -179,6 +180,25 @@ function SummarizerModelSection({ control }: { control: Control<ProjectFormData>
179
180
  }
180
181
 
181
182
  export function ProjectModelsSection({ control }: ProjectModelsSectionProps) {
183
+ const [isOpen, setIsOpen] = useState(false);
184
+ const { errors } = useFormState({ control });
185
+
186
+ const hasModelsErrors = !!(
187
+ errors.models?.base?.model ||
188
+ errors.models?.base?.providerOptions ||
189
+ errors.models?.structuredOutput?.model ||
190
+ errors.models?.structuredOutput?.providerOptions ||
191
+ errors.models?.summarizer?.model ||
192
+ errors.models?.summarizer?.providerOptions
193
+ );
194
+
195
+ // Auto-open the collapsible when there are errors in the models section
196
+ useEffect(() => {
197
+ if (hasModelsErrors) {
198
+ setIsOpen(true);
199
+ }
200
+ }, [hasModelsErrors]);
201
+
182
202
  return (
183
203
  <div className="space-y-4">
184
204
  <div>
@@ -188,7 +208,11 @@ export function ProjectModelsSection({ control }: ProjectModelsSectionProps) {
188
208
  </p>
189
209
  </div>
190
210
 
191
- <Collapsible defaultOpen={false} className="border rounded-md bg-background">
211
+ <Collapsible
212
+ open={isOpen}
213
+ onOpenChange={setIsOpen}
214
+ className="border rounded-md bg-background"
215
+ >
192
216
  <CollapsibleTrigger asChild>
193
217
  <Button
194
218
  type="button"