@tai42/studio-sdk 15.0.0 → 16.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (322) hide show
  1. package/dist/components/explorer-body.d.ts +49 -0
  2. package/dist/components/explorer-body.d.ts.map +1 -0
  3. package/dist/components/explorer-body.js +67 -0
  4. package/dist/components/explorer-body.js.map +1 -0
  5. package/dist/components/explorer-page-size.d.ts +4 -0
  6. package/dist/components/explorer-page-size.d.ts.map +1 -0
  7. package/dist/components/explorer-page-size.js +36 -0
  8. package/dist/components/explorer-page-size.js.map +1 -0
  9. package/dist/components/explorer-tag-filter.d.ts +17 -0
  10. package/dist/components/explorer-tag-filter.d.ts.map +1 -0
  11. package/dist/components/explorer-tag-filter.js +29 -0
  12. package/dist/components/explorer-tag-filter.js.map +1 -0
  13. package/dist/components/explorer-tags.d.ts +22 -0
  14. package/dist/components/explorer-tags.d.ts.map +1 -0
  15. package/dist/components/explorer-tags.js +51 -0
  16. package/dist/components/explorer-tags.js.map +1 -0
  17. package/dist/components/explorer-view.d.ts +3 -17
  18. package/dist/components/explorer-view.d.ts.map +1 -1
  19. package/dist/components/explorer-view.js +53 -170
  20. package/dist/components/explorer-view.js.map +1 -1
  21. package/dist/components/extension-combo-builder.d.ts +0 -5
  22. package/dist/components/extension-combo-builder.d.ts.map +1 -1
  23. package/dist/components/extension-combo-builder.js +4 -42
  24. package/dist/components/extension-combo-builder.js.map +1 -1
  25. package/dist/components/extension-combo-parts.d.ts +44 -0
  26. package/dist/components/extension-combo-parts.d.ts.map +1 -0
  27. package/dist/components/extension-combo-parts.js +57 -0
  28. package/dist/components/extension-combo-parts.js.map +1 -0
  29. package/dist/components/fleet-report.d.ts.map +1 -1
  30. package/dist/components/fleet-report.js +51 -37
  31. package/dist/components/fleet-report.js.map +1 -1
  32. package/dist/components/icons/chrome-marks.d.ts +50 -0
  33. package/dist/components/icons/chrome-marks.d.ts.map +1 -0
  34. package/dist/components/icons/chrome-marks.js +51 -0
  35. package/dist/components/icons/chrome-marks.js.map +1 -0
  36. package/dist/components/icons/icon-frame.d.ts +29 -0
  37. package/dist/components/icons/icon-frame.d.ts.map +1 -0
  38. package/dist/components/icons/icon-frame.js +19 -0
  39. package/dist/components/icons/icon-frame.js.map +1 -0
  40. package/dist/components/icons/index.d.ts +40 -0
  41. package/dist/components/icons/index.d.ts.map +1 -0
  42. package/dist/components/icons/index.js +6 -0
  43. package/dist/components/icons/index.js.map +1 -0
  44. package/dist/components/icons/nav-map.d.ts +14 -0
  45. package/dist/components/icons/nav-map.d.ts.map +1 -0
  46. package/dist/components/icons/nav-map.js +28 -0
  47. package/dist/components/icons/nav-map.js.map +1 -0
  48. package/dist/components/icons/nav-marks.d.ts +44 -0
  49. package/dist/components/icons/nav-marks.d.ts.map +1 -0
  50. package/dist/components/icons/nav-marks.js +45 -0
  51. package/dist/components/icons/nav-marks.js.map +1 -0
  52. package/dist/components/icons/status-marks.d.ts +21 -0
  53. package/dist/components/icons/status-marks.d.ts.map +1 -0
  54. package/dist/components/icons/status-marks.js +22 -0
  55. package/dist/components/icons/status-marks.js.map +1 -0
  56. package/dist/components/icons/theme-marks.d.ts +9 -0
  57. package/dist/components/icons/theme-marks.d.ts.map +1 -0
  58. package/dist/components/icons/theme-marks.js +10 -0
  59. package/dist/components/icons/theme-marks.js.map +1 -0
  60. package/dist/components/json-diff.d.ts.map +1 -1
  61. package/dist/components/json-diff.js +1 -3
  62. package/dist/components/json-diff.js.map +1 -1
  63. package/dist/components/json-tree-context.d.ts +13 -0
  64. package/dist/components/json-tree-context.d.ts.map +1 -0
  65. package/dist/components/json-tree-context.js +15 -0
  66. package/dist/components/json-tree-context.js.map +1 -0
  67. package/dist/components/json-tree-model.d.ts +56 -0
  68. package/dist/components/json-tree-model.d.ts.map +1 -0
  69. package/dist/components/json-tree-model.js +125 -0
  70. package/dist/components/json-tree-model.js.map +1 -0
  71. package/dist/components/json-tree-nodes.d.ts +30 -0
  72. package/dist/components/json-tree-nodes.d.ts.map +1 -0
  73. package/dist/components/json-tree-nodes.js +118 -0
  74. package/dist/components/json-tree-nodes.js.map +1 -0
  75. package/dist/components/json-tree.d.ts.map +1 -1
  76. package/dist/components/json-tree.js +7 -295
  77. package/dist/components/json-tree.js.map +1 -1
  78. package/dist/components/json-value-format.d.ts +20 -0
  79. package/dist/components/json-value-format.d.ts.map +1 -0
  80. package/dist/components/json-value-format.js +63 -0
  81. package/dist/components/json-value-format.js.map +1 -0
  82. package/dist/components/markdown-blocks.d.ts +38 -0
  83. package/dist/components/markdown-blocks.d.ts.map +1 -0
  84. package/dist/components/markdown-blocks.js +168 -0
  85. package/dist/components/markdown-blocks.js.map +1 -0
  86. package/dist/components/markdown-inline.d.ts +24 -0
  87. package/dist/components/markdown-inline.d.ts.map +1 -0
  88. package/dist/components/markdown-inline.js +257 -0
  89. package/dist/components/markdown-inline.js.map +1 -0
  90. package/dist/components/markdown.d.ts +3 -52
  91. package/dist/components/markdown.d.ts.map +1 -1
  92. package/dist/components/markdown.js +4 -376
  93. package/dist/components/markdown.js.map +1 -1
  94. package/dist/components/observer-registry.d.ts +38 -0
  95. package/dist/components/observer-registry.d.ts.map +1 -0
  96. package/dist/components/observer-registry.js +131 -0
  97. package/dist/components/observer-registry.js.map +1 -0
  98. package/dist/components/overflow-measure.d.ts +38 -0
  99. package/dist/components/overflow-measure.d.ts.map +1 -0
  100. package/dist/components/overflow-measure.js +54 -0
  101. package/dist/components/overflow-measure.js.map +1 -0
  102. package/dist/components/prose-regions.d.ts +81 -0
  103. package/dist/components/prose-regions.d.ts.map +1 -0
  104. package/dist/components/prose-regions.js +128 -0
  105. package/dist/components/prose-regions.js.map +1 -0
  106. package/dist/components/scroll-region.d.ts.map +1 -1
  107. package/dist/components/scroll-region.js +3 -298
  108. package/dist/components/scroll-region.js.map +1 -1
  109. package/dist/components/tab-stop-parse.d.ts +53 -0
  110. package/dist/components/tab-stop-parse.d.ts.map +1 -0
  111. package/dist/components/tab-stop-parse.js +202 -0
  112. package/dist/components/tab-stop-parse.js.map +1 -0
  113. package/dist/components/templated-text-field.d.ts.map +1 -1
  114. package/dist/components/templated-text-field.js +10 -148
  115. package/dist/components/templated-text-field.js.map +1 -1
  116. package/dist/components/templated-text-kwargs-editor.d.ts +24 -0
  117. package/dist/components/templated-text-kwargs-editor.d.ts.map +1 -0
  118. package/dist/components/templated-text-kwargs-editor.js +48 -0
  119. package/dist/components/templated-text-kwargs-editor.js.map +1 -0
  120. package/dist/components/templated-text-kwargs.d.ts +37 -0
  121. package/dist/components/templated-text-kwargs.d.ts.map +1 -0
  122. package/dist/components/templated-text-kwargs.js +66 -0
  123. package/dist/components/templated-text-kwargs.js.map +1 -0
  124. package/dist/components/templated-text-source.d.ts +33 -0
  125. package/dist/components/templated-text-source.d.ts.map +1 -0
  126. package/dist/components/templated-text-source.js +53 -0
  127. package/dist/components/templated-text-source.js.map +1 -0
  128. package/dist/components/tool-picker-parts.d.ts +39 -0
  129. package/dist/components/tool-picker-parts.d.ts.map +1 -0
  130. package/dist/components/tool-picker-parts.js +87 -0
  131. package/dist/components/tool-picker-parts.js.map +1 -0
  132. package/dist/components/tool-picker.d.ts +1 -2
  133. package/dist/components/tool-picker.d.ts.map +1 -1
  134. package/dist/components/tool-picker.js +4 -66
  135. package/dist/components/tool-picker.js.map +1 -1
  136. package/dist/components/version-history-panel.d.ts.map +1 -1
  137. package/dist/components/version-history-panel.js +7 -34
  138. package/dist/components/version-history-panel.js.map +1 -1
  139. package/dist/components/version-history-rows.d.ts +48 -0
  140. package/dist/components/version-history-rows.d.ts.map +1 -0
  141. package/dist/components/version-history-rows.js +51 -0
  142. package/dist/components/version-history-rows.js.map +1 -0
  143. package/dist/guards.d.ts +6 -0
  144. package/dist/guards.d.ts.map +1 -0
  145. package/dist/guards.js +8 -0
  146. package/dist/guards.js.map +1 -0
  147. package/dist/hooks/interactions-connection.d.ts +43 -0
  148. package/dist/hooks/interactions-connection.d.ts.map +1 -0
  149. package/dist/hooks/interactions-connection.js +171 -0
  150. package/dist/hooks/interactions-connection.js.map +1 -0
  151. package/dist/hooks/interactions-stream.d.ts +80 -0
  152. package/dist/hooks/interactions-stream.d.ts.map +1 -0
  153. package/dist/hooks/interactions-stream.js +233 -0
  154. package/dist/hooks/interactions-stream.js.map +1 -0
  155. package/dist/hooks/useApi.d.ts +2409 -2293
  156. package/dist/hooks/useApi.d.ts.map +1 -1
  157. package/dist/hooks/useSse.d.ts +3 -6
  158. package/dist/hooks/useSse.d.ts.map +1 -1
  159. package/dist/hooks/useSse.js +38 -451
  160. package/dist/hooks/useSse.js.map +1 -1
  161. package/dist/navigation/app-link.d.ts +25 -0
  162. package/dist/navigation/app-link.d.ts.map +1 -0
  163. package/dist/navigation/app-link.js +33 -0
  164. package/dist/navigation/app-link.js.map +1 -0
  165. package/dist/navigation/context.d.ts +3 -20
  166. package/dist/navigation/context.d.ts.map +1 -1
  167. package/dist/navigation/context.js +7 -267
  168. package/dist/navigation/context.js.map +1 -1
  169. package/dist/navigation/entry-state.d.ts +23 -0
  170. package/dist/navigation/entry-state.d.ts.map +1 -0
  171. package/dist/navigation/entry-state.js +39 -0
  172. package/dist/navigation/entry-state.js.map +1 -0
  173. package/dist/navigation/guard-registry.d.ts +30 -0
  174. package/dist/navigation/guard-registry.d.ts.map +1 -0
  175. package/dist/navigation/guard-registry.js +46 -0
  176. package/dist/navigation/guard-registry.js.map +1 -0
  177. package/dist/navigation/guarded-navigation.d.ts +24 -0
  178. package/dist/navigation/guarded-navigation.d.ts.map +1 -0
  179. package/dist/navigation/guarded-navigation.js +102 -0
  180. package/dist/navigation/guarded-navigation.js.map +1 -0
  181. package/dist/navigation/index.d.ts +3 -2
  182. package/dist/navigation/index.d.ts.map +1 -1
  183. package/dist/navigation/index.js +2 -1
  184. package/dist/navigation/index.js.map +1 -1
  185. package/dist/navigation/types.d.ts +8 -11
  186. package/dist/navigation/types.d.ts.map +1 -1
  187. package/dist/navigation/use-back-forward-guard.d.ts +5 -0
  188. package/dist/navigation/use-back-forward-guard.d.ts.map +1 -0
  189. package/dist/navigation/use-back-forward-guard.js +82 -0
  190. package/dist/navigation/use-back-forward-guard.js.map +1 -0
  191. package/dist/plugin/registry.d.ts +6 -15
  192. package/dist/plugin/registry.d.ts.map +1 -1
  193. package/dist/plugin/registry.js +83 -75
  194. package/dist/plugin/registry.js.map +1 -1
  195. package/dist/schema-editor/SchemaEditor.d.ts +8 -1
  196. package/dist/schema-editor/SchemaEditor.d.ts.map +1 -1
  197. package/dist/schema-editor/SchemaEditor.js +2 -2
  198. package/dist/schema-editor/SchemaEditor.js.map +1 -1
  199. package/dist/schema-form/SecretRefField.d.ts +2 -3
  200. package/dist/schema-form/SecretRefField.d.ts.map +1 -1
  201. package/dist/schema-form/SecretRefField.js +23 -12
  202. package/dist/schema-form/SecretRefField.js.map +1 -1
  203. package/dist/schema-form/classify.d.ts +1 -122
  204. package/dist/schema-form/classify.d.ts.map +1 -1
  205. package/dist/schema-form/classify.js +174 -237
  206. package/dist/schema-form/classify.js.map +1 -1
  207. package/dist/schema-form/default-value.d.ts.map +1 -1
  208. package/dist/schema-form/default-value.js +42 -19
  209. package/dist/schema-form/default-value.js.map +1 -1
  210. package/dist/schema-form/enum-field.d.ts +1 -1
  211. package/dist/schema-form/enum-field.d.ts.map +1 -1
  212. package/dist/schema-form/field-model.d.ts +121 -0
  213. package/dist/schema-form/field-model.d.ts.map +1 -0
  214. package/dist/schema-form/field-model.js +2 -0
  215. package/dist/schema-form/field-model.js.map +1 -0
  216. package/dist/schema-form/field-node.d.ts.map +1 -1
  217. package/dist/schema-form/field-node.js +25 -14
  218. package/dist/schema-form/field-node.js.map +1 -1
  219. package/dist/schema-form/media-field.d.ts +1 -1
  220. package/dist/schema-form/media-field.d.ts.map +1 -1
  221. package/dist/schema-form/media-field.js +47 -28
  222. package/dist/schema-form/media-field.js.map +1 -1
  223. package/dist/schema-form/string-annotations.d.ts +20 -0
  224. package/dist/schema-form/string-annotations.d.ts.map +1 -0
  225. package/dist/schema-form/string-annotations.js +105 -0
  226. package/dist/schema-form/string-annotations.js.map +1 -0
  227. package/dist/schema-form/string-field.d.ts +1 -1
  228. package/dist/schema-form/string-field.d.ts.map +1 -1
  229. package/dist/schema-form/union-field.d.ts +1 -1
  230. package/dist/schema-form/union-field.d.ts.map +1 -1
  231. package/dist/schema-form/union-field.js.map +1 -1
  232. package/dist/schema-form/union.d.ts +1 -1
  233. package/dist/schema-form/union.d.ts.map +1 -1
  234. package/dist/schema-form/validate.d.ts.map +1 -1
  235. package/dist/schema-form/validate.js +126 -105
  236. package/dist/schema-form/validate.js.map +1 -1
  237. package/dist/state-binding/AdapterMapping.d.ts.map +1 -1
  238. package/dist/state-binding/AdapterMapping.js +0 -0
  239. package/dist/state-binding/AdapterMapping.js.map +1 -1
  240. package/dist/state-binding/StateAttachRow.d.ts.map +1 -1
  241. package/dist/state-binding/StateAttachRow.js +52 -36
  242. package/dist/state-binding/StateAttachRow.js.map +1 -1
  243. package/dist/state-binding/adapter-mapping-row.d.ts +17 -0
  244. package/dist/state-binding/adapter-mapping-row.d.ts.map +1 -0
  245. package/dist/state-binding/adapter-mapping-row.js +87 -0
  246. package/dist/state-binding/adapter-mapping-row.js.map +1 -0
  247. package/dist/structured-output/StructuredOutput.d.ts.map +1 -1
  248. package/dist/structured-output/StructuredOutput.js +1 -3
  249. package/dist/structured-output/StructuredOutput.js.map +1 -1
  250. package/package.json +2 -2
  251. package/src/components/explorer-body.tsx +239 -0
  252. package/src/components/explorer-page-size.ts +39 -0
  253. package/src/components/explorer-tag-filter.tsx +80 -0
  254. package/src/components/explorer-tags.ts +64 -0
  255. package/src/components/explorer-view.tsx +114 -366
  256. package/src/components/extension-combo-builder.tsx +35 -152
  257. package/src/components/extension-combo-parts.tsx +237 -0
  258. package/src/components/fleet-report.tsx +97 -54
  259. package/src/components/icons/chrome-marks.tsx +195 -0
  260. package/src/components/icons/icon-frame.tsx +50 -0
  261. package/src/components/icons/index.ts +84 -0
  262. package/src/components/icons/nav-map.ts +55 -0
  263. package/src/components/icons/nav-marks.tsx +205 -0
  264. package/src/components/icons/status-marks.tsx +46 -0
  265. package/src/components/icons/theme-marks.tsx +33 -0
  266. package/src/components/json-diff.tsx +1 -4
  267. package/src/components/json-tree-context.ts +26 -0
  268. package/src/components/json-tree-model.ts +139 -0
  269. package/src/components/json-tree-nodes.tsx +224 -0
  270. package/src/components/json-tree.tsx +15 -434
  271. package/src/components/json-value-format.ts +64 -0
  272. package/src/components/markdown-blocks.ts +198 -0
  273. package/src/components/markdown-inline.tsx +365 -0
  274. package/src/components/markdown.tsx +5 -471
  275. package/src/components/observer-registry.ts +139 -0
  276. package/src/components/overflow-measure.ts +69 -0
  277. package/src/components/prose-regions.ts +153 -0
  278. package/src/components/scroll-region.tsx +20 -360
  279. package/src/components/tab-stop-parse.ts +217 -0
  280. package/src/components/templated-text-field.tsx +38 -330
  281. package/src/components/templated-text-kwargs-editor.tsx +147 -0
  282. package/src/components/templated-text-kwargs.ts +92 -0
  283. package/src/components/templated-text-source.tsx +226 -0
  284. package/src/components/tool-picker-parts.tsx +184 -0
  285. package/src/components/tool-picker.tsx +22 -114
  286. package/src/components/version-history-panel.tsx +38 -142
  287. package/src/components/version-history-rows.tsx +220 -0
  288. package/src/guards.ts +7 -0
  289. package/src/hooks/interactions-connection.ts +227 -0
  290. package/src/hooks/interactions-stream.ts +274 -0
  291. package/src/hooks/useSse.ts +50 -477
  292. package/src/navigation/app-link.tsx +70 -0
  293. package/src/navigation/context.tsx +11 -330
  294. package/src/navigation/entry-state.ts +42 -0
  295. package/src/navigation/guard-registry.ts +65 -0
  296. package/src/navigation/guarded-navigation.ts +147 -0
  297. package/src/navigation/index.ts +2 -2
  298. package/src/navigation/types.ts +8 -11
  299. package/src/navigation/use-back-forward-guard.ts +90 -0
  300. package/src/plugin/registry.ts +111 -90
  301. package/src/schema-editor/SchemaEditor.tsx +9 -1
  302. package/src/schema-form/SecretRefField.tsx +121 -71
  303. package/src/schema-form/classify.ts +244 -395
  304. package/src/schema-form/default-value.ts +48 -17
  305. package/src/schema-form/enum-field.tsx +1 -1
  306. package/src/schema-form/field-model.ts +133 -0
  307. package/src/schema-form/field-node.tsx +94 -38
  308. package/src/schema-form/media-field.tsx +134 -65
  309. package/src/schema-form/string-annotations.ts +111 -0
  310. package/src/schema-form/string-field.tsx +1 -1
  311. package/src/schema-form/union-field.tsx +2 -1
  312. package/src/schema-form/union.ts +1 -1
  313. package/src/schema-form/validate.ts +184 -103
  314. package/src/state-binding/AdapterMapping.tsx +0 -0
  315. package/src/state-binding/StateAttachRow.tsx +222 -147
  316. package/src/state-binding/adapter-mapping-row.tsx +232 -0
  317. package/src/structured-output/StructuredOutput.tsx +1 -4
  318. package/dist/components/icons.d.ts +0 -160
  319. package/dist/components/icons.d.ts.map +0 -1
  320. package/dist/components/icons.js +0 -160
  321. package/dist/components/icons.js.map +0 -1
  322. package/src/components/icons.tsx +0 -586
@@ -127,163 +127,238 @@ export function StateAttachRow({
127
127
  borderRadius: 'var(--tai-radius-md)',
128
128
  }}
129
129
  >
130
- <div
131
- style={{
132
- display: 'flex',
133
- gap: 'var(--tai-space-2)',
134
- alignItems: 'flex-end',
135
- flexWrap: 'wrap',
130
+ <AttachStateHeader
131
+ state={attach.state}
132
+ statesCatalog={statesCatalog}
133
+ onSelectState={(next) => {
134
+ // A new state resets the template picks (its attachments differ).
135
+ onChange({ ...attach, state: next, templates: [] });
136
136
  }}
137
- >
138
- <Field label="State">
139
- <Select
140
- aria-label="State"
141
- placeholder="Choose a state"
142
- value={attach.state}
143
- onValueChange={(next) => {
144
- // A new state resets the template picks (its attachments differ).
145
- onChange({ ...attach, state: next, templates: [] });
146
- }}
147
- options={statesCatalog.map((option) => ({ value: option.name, label: option.name }))}
148
- />
149
- </Field>
150
- <Button
151
- type="button"
152
- variant="ghost"
153
- aria-label={`Remove state ${attach.state === '' ? '(unset)' : attach.state}`}
154
- onClick={onRemove}
155
- >
156
- <CloseIcon aria-hidden="true" />
157
- </Button>
158
- </div>
137
+ onRemove={onRemove}
138
+ />
159
139
 
160
140
  {inherited !== undefined && attach.state !== '' ? (
161
- <div
162
- role="status"
163
- style={{
164
- display: 'flex',
165
- gap: 'var(--tai-space-2)',
166
- alignItems: 'flex-start',
167
- padding: 'var(--tai-space-2)',
168
- borderRadius: 'var(--tai-radius-md)',
169
- background: 'var(--tai-color-warn-tint)',
170
- color: 'var(--tai-color-warn-text)',
171
- }}
172
- >
173
- <AlertTriangleIcon aria-hidden="true" />
174
- <div>
175
- <strong>Overrides the preset&rsquo;s subject</strong>
176
- <div style={{ display: 'flex', gap: 'var(--tai-space-2)', flexWrap: 'wrap' }}>
177
- <span
178
- style={{ color: 'var(--tai-color-text-muted)', fontSize: 'var(--tai-text-sm)' }}
179
- >
180
- Preset default:
181
- </span>
182
- <span style={{ fontFamily: 'var(--tai-font-mono)', fontSize: 'var(--tai-text-sm)' }}>
183
- {`subject: ${templatedTextSummary(inherited.subject_expr)}`}
184
- {inherited.scope_expr !== null
185
- ? `, scope: ${templatedTextSummary(inherited.scope_expr)}`
186
- : ''}
187
- </span>
188
- </div>
189
- </div>
190
- </div>
141
+ <InheritedSubjectNote inherited={inherited} />
191
142
  ) : null}
192
143
 
193
- {attach.state !== '' && unresolved ? (
194
- <div style={{ display: 'flex', flexDirection: 'column', gap: 'var(--tai-space-2)' }}>
195
- <p role="alert" style={{ margin: 0, color: 'var(--tai-color-err-text)' }}>
196
- Template not attached.
197
- </p>
198
- <CodeBlock code={rawBindingLines(attach)} language="text" />
199
- </div>
200
- ) : null}
144
+ {attach.state !== '' && unresolved ? <UnresolvedBinding attach={attach} /> : null}
201
145
 
202
146
  {attach.state !== '' && !unresolved ? (
203
- <>
204
- <Field
205
- label="Templates"
206
- group
207
- description="One or more templates this binding attaches to the state."
208
- >
209
- <div style={{ display: 'flex', flexDirection: 'column', gap: 'var(--tai-space-1)' }}>
210
- {templatesCatalog.length === 0 ? (
211
- <p style={{ margin: 0, color: 'var(--tai-color-text-muted)' }}>
212
- No templates available.
213
- </p>
214
- ) : (
215
- templatesCatalog.map((template) => {
216
- const checked = attach.templates.includes(template.name);
217
- const willAttach = checked && !attachedTemplates.includes(template.name);
218
- return (
219
- <div
220
- key={template.name}
221
- style={{ display: 'flex', flexDirection: 'column', gap: '2px' }}
222
- >
223
- <Checkbox
224
- checked={checked}
225
- label={template.name}
226
- onCheckedChange={(next) => {
227
- toggleTemplate(template.name, next);
228
- }}
229
- />
230
- {willAttach ? (
231
- <span
232
- style={{
233
- color: 'var(--tai-color-text-muted)',
234
- fontSize: 'var(--tai-text-sm)',
235
- }}
236
- >
237
- {ATTACH_ON_USE_HINT}
238
- </span>
239
- ) : null}
240
- </div>
241
- );
242
- })
243
- )}
244
- </div>
245
- </Field>
147
+ <ResolvedAttachBody
148
+ attach={attach}
149
+ templatesCatalog={templatesCatalog}
150
+ attachedTemplates={attachedTemplates}
151
+ subjectError={subjectError}
152
+ suggestions={suggestions}
153
+ templates={templates}
154
+ sources={sources}
155
+ inputJq={inputJq}
156
+ updateJq={updateJq}
157
+ onChange={onChange}
158
+ onToggleTemplate={toggleTemplate}
159
+ />
160
+ ) : null}
161
+ </div>
162
+ );
163
+ }
246
164
 
247
- <SubjectScopeFields
248
- subjectExpr={attach.subject_expr}
249
- scopeExpr={attach.scope_expr}
250
- subjectError={subjectError}
251
- suggestions={suggestions}
252
- templates={templates}
253
- onSubjectChange={(next) => {
254
- onChange({ ...attach, subject_expr: next });
255
- }}
256
- onScopeChange={(next) => {
257
- onChange({ ...attach, scope_expr: next });
258
- }}
259
- />
165
+ /** The state selector plus the remove control. */
166
+ function AttachStateHeader({
167
+ state,
168
+ statesCatalog,
169
+ onSelectState,
170
+ onRemove,
171
+ }: {
172
+ readonly state: string;
173
+ readonly statesCatalog: readonly BindingStateOption[];
174
+ readonly onSelectState: (next: string) => void;
175
+ readonly onRemove: () => void;
176
+ }): ReactNode {
177
+ return (
178
+ <div
179
+ style={{
180
+ display: 'flex',
181
+ gap: 'var(--tai-space-2)',
182
+ alignItems: 'flex-end',
183
+ flexWrap: 'wrap',
184
+ }}
185
+ >
186
+ <Field label="State">
187
+ <Select
188
+ aria-label="State"
189
+ placeholder="Choose a state"
190
+ value={state}
191
+ onValueChange={onSelectState}
192
+ options={statesCatalog.map((option) => ({ value: option.name, label: option.name }))}
193
+ />
194
+ </Field>
195
+ <Button
196
+ type="button"
197
+ variant="ghost"
198
+ aria-label={`Remove state ${state === '' ? '(unset)' : state}`}
199
+ onClick={onRemove}
200
+ >
201
+ <CloseIcon aria-hidden="true" />
202
+ </Button>
203
+ </div>
204
+ );
205
+ }
260
206
 
261
- <Field label="Inputs" group>
262
- <InjectionList
263
- injections={attach.input_injections}
264
- inputJq={inputJq}
265
- suggestions={suggestions}
266
- templates={templates}
267
- onChange={(next) => {
268
- onChange({ ...attach, input_injections: [...next] });
269
- }}
270
- />
271
- </Field>
207
+ /** The precedence warning shown when the target's own binding already sets this state's subject. */
208
+ function InheritedSubjectNote({ inherited }: { readonly inherited: InheritedSubject }): ReactNode {
209
+ return (
210
+ <div
211
+ role="status"
212
+ style={{
213
+ display: 'flex',
214
+ gap: 'var(--tai-space-2)',
215
+ alignItems: 'flex-start',
216
+ padding: 'var(--tai-space-2)',
217
+ borderRadius: 'var(--tai-radius-md)',
218
+ background: 'var(--tai-color-warn-tint)',
219
+ color: 'var(--tai-color-warn-text)',
220
+ }}
221
+ >
222
+ <AlertTriangleIcon aria-hidden="true" />
223
+ <div>
224
+ <strong>Overrides the preset&rsquo;s subject</strong>
225
+ <div style={{ display: 'flex', gap: 'var(--tai-space-2)', flexWrap: 'wrap' }}>
226
+ <span style={{ color: 'var(--tai-color-text-muted)', fontSize: 'var(--tai-text-sm)' }}>
227
+ Preset default:
228
+ </span>
229
+ <span style={{ fontFamily: 'var(--tai-font-mono)', fontSize: 'var(--tai-text-sm)' }}>
230
+ {`subject: ${templatedTextSummary(inherited.subject_expr)}`}
231
+ {inherited.scope_expr !== null
232
+ ? `, scope: ${templatedTextSummary(inherited.scope_expr)}`
233
+ : ''}
234
+ </span>
235
+ </div>
236
+ </div>
237
+ </div>
238
+ );
239
+ }
272
240
 
273
- <Field label="Updates" group>
274
- <UpdateList
275
- updates={attach.updates}
276
- updateJq={updateJq}
277
- sources={sources}
278
- suggestions={suggestions}
279
- templates={templates}
280
- onChange={(next) => {
281
- onChange({ ...attach, updates: [...next] });
282
- }}
283
- />
284
- </Field>
285
- </>
286
- ) : null}
241
+ /** The read-only fallback for a state/template the server no longer resolves: the raw jq. */
242
+ function UnresolvedBinding({ attach }: { readonly attach: StateAttach }): ReactNode {
243
+ return (
244
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 'var(--tai-space-2)' }}>
245
+ <p role="alert" style={{ margin: 0, color: 'var(--tai-color-err-text)' }}>
246
+ Template not attached.
247
+ </p>
248
+ <CodeBlock code={rawBindingLines(attach)} language="text" />
287
249
  </div>
288
250
  );
289
251
  }
252
+
253
+ /** The resolved binding editor: the template checklist, subject/scope, inputs and updates. */
254
+ function ResolvedAttachBody({
255
+ attach,
256
+ templatesCatalog,
257
+ attachedTemplates,
258
+ subjectError,
259
+ suggestions,
260
+ templates,
261
+ sources,
262
+ inputJq,
263
+ updateJq,
264
+ onChange,
265
+ onToggleTemplate,
266
+ }: {
267
+ readonly attach: StateAttach;
268
+ readonly templatesCatalog: readonly BindingTemplateOption[];
269
+ readonly attachedTemplates: readonly string[];
270
+ readonly subjectError?: string;
271
+ readonly suggestions: readonly TemplateJqSuggestion[];
272
+ readonly templates?: TemplatedTextCatalog;
273
+ readonly sources?: BindingSourceSchemas;
274
+ readonly inputJq: ReturnType<typeof resolveTemplateJq>;
275
+ readonly updateJq: ReturnType<typeof resolveTemplateJq>;
276
+ readonly onChange: (attach: StateAttach) => void;
277
+ readonly onToggleTemplate: (name: string, checked: boolean) => void;
278
+ }): ReactNode {
279
+ return (
280
+ <>
281
+ <Field
282
+ label="Templates"
283
+ group
284
+ description="One or more templates this binding attaches to the state."
285
+ >
286
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 'var(--tai-space-1)' }}>
287
+ {templatesCatalog.length === 0 ? (
288
+ <p style={{ margin: 0, color: 'var(--tai-color-text-muted)' }}>
289
+ No templates available.
290
+ </p>
291
+ ) : (
292
+ templatesCatalog.map((template) => {
293
+ const checked = attach.templates.includes(template.name);
294
+ const willAttach = checked && !attachedTemplates.includes(template.name);
295
+ return (
296
+ <div
297
+ key={template.name}
298
+ style={{ display: 'flex', flexDirection: 'column', gap: '2px' }}
299
+ >
300
+ <Checkbox
301
+ checked={checked}
302
+ label={template.name}
303
+ onCheckedChange={(next) => {
304
+ onToggleTemplate(template.name, next);
305
+ }}
306
+ />
307
+ {willAttach ? (
308
+ <span
309
+ style={{
310
+ color: 'var(--tai-color-text-muted)',
311
+ fontSize: 'var(--tai-text-sm)',
312
+ }}
313
+ >
314
+ {ATTACH_ON_USE_HINT}
315
+ </span>
316
+ ) : null}
317
+ </div>
318
+ );
319
+ })
320
+ )}
321
+ </div>
322
+ </Field>
323
+
324
+ <SubjectScopeFields
325
+ subjectExpr={attach.subject_expr}
326
+ scopeExpr={attach.scope_expr}
327
+ subjectError={subjectError}
328
+ suggestions={suggestions}
329
+ templates={templates}
330
+ onSubjectChange={(next) => {
331
+ onChange({ ...attach, subject_expr: next });
332
+ }}
333
+ onScopeChange={(next) => {
334
+ onChange({ ...attach, scope_expr: next });
335
+ }}
336
+ />
337
+
338
+ <Field label="Inputs" group>
339
+ <InjectionList
340
+ injections={attach.input_injections}
341
+ inputJq={inputJq}
342
+ suggestions={suggestions}
343
+ templates={templates}
344
+ onChange={(next) => {
345
+ onChange({ ...attach, input_injections: [...next] });
346
+ }}
347
+ />
348
+ </Field>
349
+
350
+ <Field label="Updates" group>
351
+ <UpdateList
352
+ updates={attach.updates}
353
+ updateJq={updateJq}
354
+ sources={sources}
355
+ suggestions={suggestions}
356
+ templates={templates}
357
+ onChange={(next) => {
358
+ onChange({ ...attach, updates: [...next] });
359
+ }}
360
+ />
361
+ </Field>
362
+ </>
363
+ );
364
+ }
@@ -0,0 +1,232 @@
1
+ /**
2
+ * One row of the adapter mapping form: it picks ONE of three value sources for a
3
+ * declared input key — a picked field (from the run's output / input schema), a
4
+ * hardcoded literal, or a jq expression — and shows the row's own compiled jq on
5
+ * demand. {@link AdapterMapping} composes one editor per declared key.
6
+ */
7
+ import { useState, type ReactNode } from 'react';
8
+
9
+ import { Badge } from '../components/badge';
10
+ import { Button, Skeleton } from '../components/primitives';
11
+ import { Field } from '../components/field';
12
+ import { Select } from '../components/select';
13
+ import { TextInput } from '../components/inputs';
14
+ import { BindingJqField, type TemplateJqSuggestion } from './BindingJqField';
15
+ import { rowValueJq, type FieldRoot, type MappingRow, type MappingSource } from './adapter';
16
+ import type { BindingSourceSchemas, SchemaFieldPath } from './types';
17
+
18
+ const ROOT_OPTIONS: readonly { value: FieldRoot; label: string }[] = [
19
+ { value: 'output', label: 'Run output' },
20
+ { value: 'input', label: 'Run input' },
21
+ ];
22
+
23
+ const SOURCE_OPTIONS = [
24
+ { value: 'field', label: 'Field' },
25
+ { value: 'literal', label: 'Literal' },
26
+ { value: 'jq', label: 'Jq' },
27
+ ];
28
+
29
+ function fieldsFor(
30
+ root: FieldRoot,
31
+ sources: BindingSourceSchemas | undefined,
32
+ ): readonly SchemaFieldPath[] {
33
+ if (root === 'output') return sources?.output ?? [];
34
+ return sources?.input ?? [];
35
+ }
36
+
37
+ /** The value control for one row's picked-field source: a Select where a schema is known, else a path input. */
38
+ function FieldSourceControl({
39
+ root,
40
+ path,
41
+ onRootChange,
42
+ onPathChange,
43
+ fields,
44
+ loading = false,
45
+ error,
46
+ }: {
47
+ readonly root: FieldRoot;
48
+ readonly path: readonly string[];
49
+ readonly onRootChange: (root: FieldRoot) => void;
50
+ readonly onPathChange: (path: readonly string[]) => void;
51
+ readonly fields: readonly SchemaFieldPath[];
52
+ readonly loading?: boolean;
53
+ readonly error?: string;
54
+ }): ReactNode {
55
+ const pathInput = (
56
+ <TextInput
57
+ aria-label="Field path"
58
+ placeholder="path.into.value"
59
+ value={path.join('.')}
60
+ onChange={(event) => {
61
+ const text = event.target.value.trim();
62
+ onPathChange(text === '' ? [] : text.split('.'));
63
+ }}
64
+ />
65
+ );
66
+ return (
67
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 'var(--tai-space-1)' }}>
68
+ <div style={{ display: 'flex', gap: 'var(--tai-space-2)', flexWrap: 'wrap' }}>
69
+ <Field label="Field root" hideLabel>
70
+ <Select
71
+ value={root}
72
+ onValueChange={(next) => {
73
+ onRootChange(next as FieldRoot);
74
+ }}
75
+ options={ROOT_OPTIONS.map((option) => ({ value: option.value, label: option.label }))}
76
+ />
77
+ </Field>
78
+ {loading ? (
79
+ <Skeleton height={32} width={220} />
80
+ ) : fields.length > 0 ? (
81
+ <Field label="Field" hideLabel>
82
+ <Select
83
+ placeholder="Choose a field"
84
+ value={path.length === 0 ? '' : JSON.stringify(path)}
85
+ onValueChange={(next) => {
86
+ onPathChange(next === '' ? [] : (JSON.parse(next) as string[]));
87
+ }}
88
+ options={[
89
+ { value: '', label: '(whole value)' },
90
+ ...fields.map((field) => ({
91
+ value: JSON.stringify(field.path),
92
+ label: field.label,
93
+ })),
94
+ ]}
95
+ />
96
+ </Field>
97
+ ) : (
98
+ pathInput
99
+ )}
100
+ </div>
101
+ {error !== undefined && !loading ? (
102
+ <span
103
+ role="status"
104
+ style={{ color: 'var(--tai-color-text-muted)', fontSize: 'var(--tai-text-sm)' }}
105
+ >
106
+ {error}
107
+ </span>
108
+ ) : null}
109
+ </div>
110
+ );
111
+ }
112
+
113
+ export function MappingRowEditor({
114
+ row,
115
+ onChange,
116
+ sources,
117
+ suggestions,
118
+ }: {
119
+ readonly row: MappingRow;
120
+ readonly onChange: (row: MappingRow) => void;
121
+ readonly sources?: BindingSourceSchemas;
122
+ readonly suggestions?: readonly TemplateJqSuggestion[];
123
+ }): ReactNode {
124
+ const [showJq, setShowJq] = useState(false);
125
+ const source = row.source;
126
+ const preview = rowValueJq(source);
127
+
128
+ const setSource = (next: MappingSource): void => {
129
+ onChange({ ...row, source: next });
130
+ };
131
+
132
+ const changeKind = (kind: string): void => {
133
+ if (kind === 'field') setSource({ kind: 'field', root: 'output', path: [] });
134
+ else if (kind === 'literal') setSource({ kind: 'literal', json: '' });
135
+ else setSource({ kind: 'jq', expr: '' });
136
+ };
137
+
138
+ return (
139
+ <div
140
+ data-testid={`adapter-row-${row.target}`}
141
+ style={{
142
+ display: 'flex',
143
+ flexDirection: 'column',
144
+ gap: 'var(--tai-space-1)',
145
+ padding: 'var(--tai-space-2)',
146
+ border: '1px solid var(--tai-color-border)',
147
+ borderRadius: 'var(--tai-radius-md)',
148
+ }}
149
+ >
150
+ <div
151
+ style={{
152
+ display: 'flex',
153
+ alignItems: 'center',
154
+ gap: 'var(--tai-space-2)',
155
+ flexWrap: 'wrap',
156
+ }}
157
+ >
158
+ <Badge variant="neutral">{row.target}</Badge>
159
+ <Field label={`Source for ${row.target}`} hideLabel>
160
+ <Select
161
+ aria-label={`Source for ${row.target}`}
162
+ value={source.kind}
163
+ onValueChange={changeKind}
164
+ options={SOURCE_OPTIONS}
165
+ />
166
+ </Field>
167
+ </div>
168
+
169
+ {source.kind === 'field' ? (
170
+ <FieldSourceControl
171
+ root={source.root}
172
+ path={source.path}
173
+ fields={fieldsFor(source.root, sources)}
174
+ loading={sources?.loading}
175
+ error={sources?.error}
176
+ onRootChange={(nextRoot) => {
177
+ setSource({ kind: 'field', root: nextRoot, path: [] });
178
+ }}
179
+ onPathChange={(nextPath) => {
180
+ setSource({ kind: 'field', root: source.root, path: nextPath });
181
+ }}
182
+ />
183
+ ) : source.kind === 'literal' ? (
184
+ <Field
185
+ label={`Literal for ${row.target}`}
186
+ hideLabel
187
+ error={preview.ok ? undefined : preview.error}
188
+ >
189
+ <TextInput
190
+ aria-label={`Literal for ${row.target}`}
191
+ placeholder='"a string", 42, true, or {"k":1}'
192
+ value={source.json}
193
+ onChange={(event) => {
194
+ setSource({ kind: 'literal', json: event.target.value });
195
+ }}
196
+ />
197
+ </Field>
198
+ ) : (
199
+ <BindingJqField
200
+ label={`Jq for ${row.target}`}
201
+ value={source.expr}
202
+ onChange={(next) => {
203
+ setSource({ kind: 'jq', expr: next });
204
+ }}
205
+ error={preview.ok ? undefined : preview.error}
206
+ suggestions={suggestions}
207
+ />
208
+ )}
209
+
210
+ <div>
211
+ <Button
212
+ type="button"
213
+ variant="ghost"
214
+ aria-expanded={showJq}
215
+ onClick={() => {
216
+ setShowJq((open) => !open);
217
+ }}
218
+ >
219
+ {showJq ? 'Hide jq' : 'Show jq'}
220
+ </Button>
221
+ {showJq ? (
222
+ <pre
223
+ data-testid={`adapter-row-jq-${row.target}`}
224
+ style={{ margin: 0, fontFamily: 'var(--tai-font-mono)', whiteSpace: 'pre-wrap' }}
225
+ >
226
+ {preview.ok ? preview.jq : preview.error}
227
+ </pre>
228
+ ) : null}
229
+ </div>
230
+ </div>
231
+ );
232
+ }
@@ -14,6 +14,7 @@ import type { ReactNode } from 'react';
14
14
  import { JsonTree } from '../components/json-tree';
15
15
  import { resolveRef } from '../schema-form/resolve';
16
16
  import type { JsonSchema } from '../schema-form/types';
17
+ import { isRecord } from '../guards';
17
18
 
18
19
  export interface StructuredOutputProps {
19
20
  /** The tool's declared MCP output schema, if any. */
@@ -25,10 +26,6 @@ export interface StructuredOutputProps {
25
26
  /** The pane's name when the payload has no schema to name it by. */
26
27
  const RAW_OUTPUT_LABEL = 'Structured output';
27
28
 
28
- function isRecord(value: unknown): value is Record<string, unknown> {
29
- return typeof value === 'object' && value !== null && !Array.isArray(value);
30
- }
31
-
32
29
  function isObjectSchema(
33
30
  schema: JsonSchema | undefined,
34
31
  root: JsonSchema | undefined,