@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.
- package/dist/components/explorer-body.d.ts +49 -0
- package/dist/components/explorer-body.d.ts.map +1 -0
- package/dist/components/explorer-body.js +67 -0
- package/dist/components/explorer-body.js.map +1 -0
- package/dist/components/explorer-page-size.d.ts +4 -0
- package/dist/components/explorer-page-size.d.ts.map +1 -0
- package/dist/components/explorer-page-size.js +36 -0
- package/dist/components/explorer-page-size.js.map +1 -0
- package/dist/components/explorer-tag-filter.d.ts +17 -0
- package/dist/components/explorer-tag-filter.d.ts.map +1 -0
- package/dist/components/explorer-tag-filter.js +29 -0
- package/dist/components/explorer-tag-filter.js.map +1 -0
- package/dist/components/explorer-tags.d.ts +22 -0
- package/dist/components/explorer-tags.d.ts.map +1 -0
- package/dist/components/explorer-tags.js +51 -0
- package/dist/components/explorer-tags.js.map +1 -0
- package/dist/components/explorer-view.d.ts +3 -17
- package/dist/components/explorer-view.d.ts.map +1 -1
- package/dist/components/explorer-view.js +53 -170
- package/dist/components/explorer-view.js.map +1 -1
- package/dist/components/extension-combo-builder.d.ts +0 -5
- package/dist/components/extension-combo-builder.d.ts.map +1 -1
- package/dist/components/extension-combo-builder.js +4 -42
- package/dist/components/extension-combo-builder.js.map +1 -1
- package/dist/components/extension-combo-parts.d.ts +44 -0
- package/dist/components/extension-combo-parts.d.ts.map +1 -0
- package/dist/components/extension-combo-parts.js +57 -0
- package/dist/components/extension-combo-parts.js.map +1 -0
- package/dist/components/fleet-report.d.ts.map +1 -1
- package/dist/components/fleet-report.js +51 -37
- package/dist/components/fleet-report.js.map +1 -1
- package/dist/components/icons/chrome-marks.d.ts +50 -0
- package/dist/components/icons/chrome-marks.d.ts.map +1 -0
- package/dist/components/icons/chrome-marks.js +51 -0
- package/dist/components/icons/chrome-marks.js.map +1 -0
- package/dist/components/icons/icon-frame.d.ts +29 -0
- package/dist/components/icons/icon-frame.d.ts.map +1 -0
- package/dist/components/icons/icon-frame.js +19 -0
- package/dist/components/icons/icon-frame.js.map +1 -0
- package/dist/components/icons/index.d.ts +40 -0
- package/dist/components/icons/index.d.ts.map +1 -0
- package/dist/components/icons/index.js +6 -0
- package/dist/components/icons/index.js.map +1 -0
- package/dist/components/icons/nav-map.d.ts +14 -0
- package/dist/components/icons/nav-map.d.ts.map +1 -0
- package/dist/components/icons/nav-map.js +28 -0
- package/dist/components/icons/nav-map.js.map +1 -0
- package/dist/components/icons/nav-marks.d.ts +44 -0
- package/dist/components/icons/nav-marks.d.ts.map +1 -0
- package/dist/components/icons/nav-marks.js +45 -0
- package/dist/components/icons/nav-marks.js.map +1 -0
- package/dist/components/icons/status-marks.d.ts +21 -0
- package/dist/components/icons/status-marks.d.ts.map +1 -0
- package/dist/components/icons/status-marks.js +22 -0
- package/dist/components/icons/status-marks.js.map +1 -0
- package/dist/components/icons/theme-marks.d.ts +9 -0
- package/dist/components/icons/theme-marks.d.ts.map +1 -0
- package/dist/components/icons/theme-marks.js +10 -0
- package/dist/components/icons/theme-marks.js.map +1 -0
- package/dist/components/json-diff.d.ts.map +1 -1
- package/dist/components/json-diff.js +1 -3
- package/dist/components/json-diff.js.map +1 -1
- package/dist/components/json-tree-context.d.ts +13 -0
- package/dist/components/json-tree-context.d.ts.map +1 -0
- package/dist/components/json-tree-context.js +15 -0
- package/dist/components/json-tree-context.js.map +1 -0
- package/dist/components/json-tree-model.d.ts +56 -0
- package/dist/components/json-tree-model.d.ts.map +1 -0
- package/dist/components/json-tree-model.js +125 -0
- package/dist/components/json-tree-model.js.map +1 -0
- package/dist/components/json-tree-nodes.d.ts +30 -0
- package/dist/components/json-tree-nodes.d.ts.map +1 -0
- package/dist/components/json-tree-nodes.js +118 -0
- package/dist/components/json-tree-nodes.js.map +1 -0
- package/dist/components/json-tree.d.ts.map +1 -1
- package/dist/components/json-tree.js +7 -295
- package/dist/components/json-tree.js.map +1 -1
- package/dist/components/json-value-format.d.ts +20 -0
- package/dist/components/json-value-format.d.ts.map +1 -0
- package/dist/components/json-value-format.js +63 -0
- package/dist/components/json-value-format.js.map +1 -0
- package/dist/components/markdown-blocks.d.ts +38 -0
- package/dist/components/markdown-blocks.d.ts.map +1 -0
- package/dist/components/markdown-blocks.js +168 -0
- package/dist/components/markdown-blocks.js.map +1 -0
- package/dist/components/markdown-inline.d.ts +24 -0
- package/dist/components/markdown-inline.d.ts.map +1 -0
- package/dist/components/markdown-inline.js +257 -0
- package/dist/components/markdown-inline.js.map +1 -0
- package/dist/components/markdown.d.ts +3 -52
- package/dist/components/markdown.d.ts.map +1 -1
- package/dist/components/markdown.js +4 -376
- package/dist/components/markdown.js.map +1 -1
- package/dist/components/observer-registry.d.ts +38 -0
- package/dist/components/observer-registry.d.ts.map +1 -0
- package/dist/components/observer-registry.js +131 -0
- package/dist/components/observer-registry.js.map +1 -0
- package/dist/components/overflow-measure.d.ts +38 -0
- package/dist/components/overflow-measure.d.ts.map +1 -0
- package/dist/components/overflow-measure.js +54 -0
- package/dist/components/overflow-measure.js.map +1 -0
- package/dist/components/prose-regions.d.ts +81 -0
- package/dist/components/prose-regions.d.ts.map +1 -0
- package/dist/components/prose-regions.js +128 -0
- package/dist/components/prose-regions.js.map +1 -0
- package/dist/components/scroll-region.d.ts.map +1 -1
- package/dist/components/scroll-region.js +3 -298
- package/dist/components/scroll-region.js.map +1 -1
- package/dist/components/tab-stop-parse.d.ts +53 -0
- package/dist/components/tab-stop-parse.d.ts.map +1 -0
- package/dist/components/tab-stop-parse.js +202 -0
- package/dist/components/tab-stop-parse.js.map +1 -0
- package/dist/components/templated-text-field.d.ts.map +1 -1
- package/dist/components/templated-text-field.js +10 -148
- package/dist/components/templated-text-field.js.map +1 -1
- package/dist/components/templated-text-kwargs-editor.d.ts +24 -0
- package/dist/components/templated-text-kwargs-editor.d.ts.map +1 -0
- package/dist/components/templated-text-kwargs-editor.js +48 -0
- package/dist/components/templated-text-kwargs-editor.js.map +1 -0
- package/dist/components/templated-text-kwargs.d.ts +37 -0
- package/dist/components/templated-text-kwargs.d.ts.map +1 -0
- package/dist/components/templated-text-kwargs.js +66 -0
- package/dist/components/templated-text-kwargs.js.map +1 -0
- package/dist/components/templated-text-source.d.ts +33 -0
- package/dist/components/templated-text-source.d.ts.map +1 -0
- package/dist/components/templated-text-source.js +53 -0
- package/dist/components/templated-text-source.js.map +1 -0
- package/dist/components/tool-picker-parts.d.ts +39 -0
- package/dist/components/tool-picker-parts.d.ts.map +1 -0
- package/dist/components/tool-picker-parts.js +87 -0
- package/dist/components/tool-picker-parts.js.map +1 -0
- package/dist/components/tool-picker.d.ts +1 -2
- package/dist/components/tool-picker.d.ts.map +1 -1
- package/dist/components/tool-picker.js +4 -66
- package/dist/components/tool-picker.js.map +1 -1
- package/dist/components/version-history-panel.d.ts.map +1 -1
- package/dist/components/version-history-panel.js +7 -34
- package/dist/components/version-history-panel.js.map +1 -1
- package/dist/components/version-history-rows.d.ts +48 -0
- package/dist/components/version-history-rows.d.ts.map +1 -0
- package/dist/components/version-history-rows.js +51 -0
- package/dist/components/version-history-rows.js.map +1 -0
- package/dist/guards.d.ts +6 -0
- package/dist/guards.d.ts.map +1 -0
- package/dist/guards.js +8 -0
- package/dist/guards.js.map +1 -0
- package/dist/hooks/interactions-connection.d.ts +43 -0
- package/dist/hooks/interactions-connection.d.ts.map +1 -0
- package/dist/hooks/interactions-connection.js +171 -0
- package/dist/hooks/interactions-connection.js.map +1 -0
- package/dist/hooks/interactions-stream.d.ts +80 -0
- package/dist/hooks/interactions-stream.d.ts.map +1 -0
- package/dist/hooks/interactions-stream.js +233 -0
- package/dist/hooks/interactions-stream.js.map +1 -0
- package/dist/hooks/useApi.d.ts +2409 -2293
- package/dist/hooks/useApi.d.ts.map +1 -1
- package/dist/hooks/useSse.d.ts +3 -6
- package/dist/hooks/useSse.d.ts.map +1 -1
- package/dist/hooks/useSse.js +38 -451
- package/dist/hooks/useSse.js.map +1 -1
- package/dist/navigation/app-link.d.ts +25 -0
- package/dist/navigation/app-link.d.ts.map +1 -0
- package/dist/navigation/app-link.js +33 -0
- package/dist/navigation/app-link.js.map +1 -0
- package/dist/navigation/context.d.ts +3 -20
- package/dist/navigation/context.d.ts.map +1 -1
- package/dist/navigation/context.js +7 -267
- package/dist/navigation/context.js.map +1 -1
- package/dist/navigation/entry-state.d.ts +23 -0
- package/dist/navigation/entry-state.d.ts.map +1 -0
- package/dist/navigation/entry-state.js +39 -0
- package/dist/navigation/entry-state.js.map +1 -0
- package/dist/navigation/guard-registry.d.ts +30 -0
- package/dist/navigation/guard-registry.d.ts.map +1 -0
- package/dist/navigation/guard-registry.js +46 -0
- package/dist/navigation/guard-registry.js.map +1 -0
- package/dist/navigation/guarded-navigation.d.ts +24 -0
- package/dist/navigation/guarded-navigation.d.ts.map +1 -0
- package/dist/navigation/guarded-navigation.js +102 -0
- package/dist/navigation/guarded-navigation.js.map +1 -0
- package/dist/navigation/index.d.ts +3 -2
- package/dist/navigation/index.d.ts.map +1 -1
- package/dist/navigation/index.js +2 -1
- package/dist/navigation/index.js.map +1 -1
- package/dist/navigation/types.d.ts +8 -11
- package/dist/navigation/types.d.ts.map +1 -1
- package/dist/navigation/use-back-forward-guard.d.ts +5 -0
- package/dist/navigation/use-back-forward-guard.d.ts.map +1 -0
- package/dist/navigation/use-back-forward-guard.js +82 -0
- package/dist/navigation/use-back-forward-guard.js.map +1 -0
- package/dist/plugin/registry.d.ts +6 -15
- package/dist/plugin/registry.d.ts.map +1 -1
- package/dist/plugin/registry.js +83 -75
- package/dist/plugin/registry.js.map +1 -1
- package/dist/schema-editor/SchemaEditor.d.ts +8 -1
- package/dist/schema-editor/SchemaEditor.d.ts.map +1 -1
- package/dist/schema-editor/SchemaEditor.js +2 -2
- package/dist/schema-editor/SchemaEditor.js.map +1 -1
- package/dist/schema-form/SecretRefField.d.ts +2 -3
- package/dist/schema-form/SecretRefField.d.ts.map +1 -1
- package/dist/schema-form/SecretRefField.js +23 -12
- package/dist/schema-form/SecretRefField.js.map +1 -1
- package/dist/schema-form/classify.d.ts +1 -122
- package/dist/schema-form/classify.d.ts.map +1 -1
- package/dist/schema-form/classify.js +174 -237
- package/dist/schema-form/classify.js.map +1 -1
- package/dist/schema-form/default-value.d.ts.map +1 -1
- package/dist/schema-form/default-value.js +42 -19
- package/dist/schema-form/default-value.js.map +1 -1
- package/dist/schema-form/enum-field.d.ts +1 -1
- package/dist/schema-form/enum-field.d.ts.map +1 -1
- package/dist/schema-form/field-model.d.ts +121 -0
- package/dist/schema-form/field-model.d.ts.map +1 -0
- package/dist/schema-form/field-model.js +2 -0
- package/dist/schema-form/field-model.js.map +1 -0
- package/dist/schema-form/field-node.d.ts.map +1 -1
- package/dist/schema-form/field-node.js +25 -14
- package/dist/schema-form/field-node.js.map +1 -1
- package/dist/schema-form/media-field.d.ts +1 -1
- package/dist/schema-form/media-field.d.ts.map +1 -1
- package/dist/schema-form/media-field.js +47 -28
- package/dist/schema-form/media-field.js.map +1 -1
- package/dist/schema-form/string-annotations.d.ts +20 -0
- package/dist/schema-form/string-annotations.d.ts.map +1 -0
- package/dist/schema-form/string-annotations.js +105 -0
- package/dist/schema-form/string-annotations.js.map +1 -0
- package/dist/schema-form/string-field.d.ts +1 -1
- package/dist/schema-form/string-field.d.ts.map +1 -1
- package/dist/schema-form/union-field.d.ts +1 -1
- package/dist/schema-form/union-field.d.ts.map +1 -1
- package/dist/schema-form/union-field.js.map +1 -1
- package/dist/schema-form/union.d.ts +1 -1
- package/dist/schema-form/union.d.ts.map +1 -1
- package/dist/schema-form/validate.d.ts.map +1 -1
- package/dist/schema-form/validate.js +126 -105
- package/dist/schema-form/validate.js.map +1 -1
- package/dist/state-binding/AdapterMapping.d.ts.map +1 -1
- package/dist/state-binding/AdapterMapping.js +0 -0
- package/dist/state-binding/AdapterMapping.js.map +1 -1
- package/dist/state-binding/StateAttachRow.d.ts.map +1 -1
- package/dist/state-binding/StateAttachRow.js +52 -36
- package/dist/state-binding/StateAttachRow.js.map +1 -1
- package/dist/state-binding/adapter-mapping-row.d.ts +17 -0
- package/dist/state-binding/adapter-mapping-row.d.ts.map +1 -0
- package/dist/state-binding/adapter-mapping-row.js +87 -0
- package/dist/state-binding/adapter-mapping-row.js.map +1 -0
- package/dist/structured-output/StructuredOutput.d.ts.map +1 -1
- package/dist/structured-output/StructuredOutput.js +1 -3
- package/dist/structured-output/StructuredOutput.js.map +1 -1
- package/package.json +2 -2
- package/src/components/explorer-body.tsx +239 -0
- package/src/components/explorer-page-size.ts +39 -0
- package/src/components/explorer-tag-filter.tsx +80 -0
- package/src/components/explorer-tags.ts +64 -0
- package/src/components/explorer-view.tsx +114 -366
- package/src/components/extension-combo-builder.tsx +35 -152
- package/src/components/extension-combo-parts.tsx +237 -0
- package/src/components/fleet-report.tsx +97 -54
- package/src/components/icons/chrome-marks.tsx +195 -0
- package/src/components/icons/icon-frame.tsx +50 -0
- package/src/components/icons/index.ts +84 -0
- package/src/components/icons/nav-map.ts +55 -0
- package/src/components/icons/nav-marks.tsx +205 -0
- package/src/components/icons/status-marks.tsx +46 -0
- package/src/components/icons/theme-marks.tsx +33 -0
- package/src/components/json-diff.tsx +1 -4
- package/src/components/json-tree-context.ts +26 -0
- package/src/components/json-tree-model.ts +139 -0
- package/src/components/json-tree-nodes.tsx +224 -0
- package/src/components/json-tree.tsx +15 -434
- package/src/components/json-value-format.ts +64 -0
- package/src/components/markdown-blocks.ts +198 -0
- package/src/components/markdown-inline.tsx +365 -0
- package/src/components/markdown.tsx +5 -471
- package/src/components/observer-registry.ts +139 -0
- package/src/components/overflow-measure.ts +69 -0
- package/src/components/prose-regions.ts +153 -0
- package/src/components/scroll-region.tsx +20 -360
- package/src/components/tab-stop-parse.ts +217 -0
- package/src/components/templated-text-field.tsx +38 -330
- package/src/components/templated-text-kwargs-editor.tsx +147 -0
- package/src/components/templated-text-kwargs.ts +92 -0
- package/src/components/templated-text-source.tsx +226 -0
- package/src/components/tool-picker-parts.tsx +184 -0
- package/src/components/tool-picker.tsx +22 -114
- package/src/components/version-history-panel.tsx +38 -142
- package/src/components/version-history-rows.tsx +220 -0
- package/src/guards.ts +7 -0
- package/src/hooks/interactions-connection.ts +227 -0
- package/src/hooks/interactions-stream.ts +274 -0
- package/src/hooks/useSse.ts +50 -477
- package/src/navigation/app-link.tsx +70 -0
- package/src/navigation/context.tsx +11 -330
- package/src/navigation/entry-state.ts +42 -0
- package/src/navigation/guard-registry.ts +65 -0
- package/src/navigation/guarded-navigation.ts +147 -0
- package/src/navigation/index.ts +2 -2
- package/src/navigation/types.ts +8 -11
- package/src/navigation/use-back-forward-guard.ts +90 -0
- package/src/plugin/registry.ts +111 -90
- package/src/schema-editor/SchemaEditor.tsx +9 -1
- package/src/schema-form/SecretRefField.tsx +121 -71
- package/src/schema-form/classify.ts +244 -395
- package/src/schema-form/default-value.ts +48 -17
- package/src/schema-form/enum-field.tsx +1 -1
- package/src/schema-form/field-model.ts +133 -0
- package/src/schema-form/field-node.tsx +94 -38
- package/src/schema-form/media-field.tsx +134 -65
- package/src/schema-form/string-annotations.ts +111 -0
- package/src/schema-form/string-field.tsx +1 -1
- package/src/schema-form/union-field.tsx +2 -1
- package/src/schema-form/union.ts +1 -1
- package/src/schema-form/validate.ts +184 -103
- package/src/state-binding/AdapterMapping.tsx +0 -0
- package/src/state-binding/StateAttachRow.tsx +222 -147
- package/src/state-binding/adapter-mapping-row.tsx +232 -0
- package/src/structured-output/StructuredOutput.tsx +1 -4
- package/dist/components/icons.d.ts +0 -160
- package/dist/components/icons.d.ts.map +0 -1
- package/dist/components/icons.js +0 -160
- package/dist/components/icons.js.map +0 -1
- 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
|
-
<
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
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
|
-
|
|
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
|
-
<
|
|
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’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
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
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
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
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
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
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’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
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
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,
|