@tangle-network/ui 11.16.3 → 11.16.5
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/CHANGELOG.md +14 -0
- package/dist/chat/agent-timeline.js +3 -2
- package/dist/chat/chat-message.js +2 -2
- package/dist/chat/thinking-indicator.js +1 -1
- package/dist/chat/user-message.js +2 -2
- package/dist/markdown/code-block.js +9 -1
- package/dist/openui/schema-compiled.js +108 -209
- package/dist/openui/schema-data.js +0 -1
- package/dist/openui-schema.js +4 -0
- package/dist/run/expandable-content.js +2 -2
- package/dist/run/expanded-tool-detail.js +3 -0
- package/package.json +1 -1
- package/src/chat/agent-timeline.test.tsx +0 -14
- package/src/chat/agent-timeline.tsx +18 -2
- package/src/chat/chat-message.tsx +2 -2
- package/src/chat/thinking-indicator.tsx +1 -1
- package/src/chat/user-message.tsx +2 -2
- package/src/markdown/code-block.tsx +14 -2
- package/src/openui/schema-compiled.ts +1 -1
- package/src/openui/schema-data.ts +5 -1
- package/src/openui/schema.test.tsx +45 -0
- package/src/openui/schema.ts +5 -0
- package/src/run/expandable-content.tsx +8 -1
- package/src/run/expanded-tool-detail.tsx +6 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @tangle-network/ui
|
|
2
2
|
|
|
3
|
+
## 11.16.5
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 44ce397: Let model tool-schema converters accept the OpenUI node schema: container `children` no longer declares a nonempty minimum, which formed a required recursive loop that opencode rejected for `render_ui`. The persistence gate still rejects an empty stack, grid, or card children list.
|
|
8
|
+
|
|
9
|
+
## 11.16.4
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 11fbba5: Chat text renders at the 15px body size. The user bubble, assistant prose, legacy `ChatMessage` and thinking timer wrote their size tokens as `text-[var(--font-size-*)]`, which Tailwind compiles to a color, so assistant prose fell back to the Markdown default of 14px and the user bubble inherited 16px. They now use `text-[length:var(...)]`, and the dist check fails on the untyped form.
|
|
14
|
+
|
|
15
|
+
The streaming caret follows the last word instead of starting a new line. A code block that scrolls sideways takes keyboard focus as a named region (axe `scrollable-region-focusable`). The Show more toggle under a tool's output or error sits inside the card's inset instead of against its edge.
|
|
16
|
+
|
|
3
17
|
## 11.16.3
|
|
4
18
|
|
|
5
19
|
### Patch Changes
|
|
@@ -53,13 +53,14 @@ function spacingBefore(prev, next) {
|
|
|
53
53
|
return "mt-3";
|
|
54
54
|
}
|
|
55
55
|
const ROW_BLEED = "-mx-3";
|
|
56
|
+
const STREAMING_CARET = "[&>:last-child:not(ul,ol)]:after:ml-0.5 [&>:last-child:not(ul,ol)]:after:inline-block [&>:last-child:not(ul,ol)]:after:h-[1em] [&>:last-child:not(ul,ol)]:after:w-0.5 [&>:last-child:not(ul,ol)]:after:animate-pulse [&>:last-child:not(ul,ol)]:after:rounded-full [&>:last-child:not(ul,ol)]:after:bg-muted-foreground [&>:last-child:not(ul,ol)]:after:align-text-bottom [&>:last-child:not(ul,ol)]:after:content-[''] [&>:is(ul,ol):last-child>li:last-child]:after:ml-0.5 [&>:is(ul,ol):last-child>li:last-child]:after:inline-block [&>:is(ul,ol):last-child>li:last-child]:after:h-[1em] [&>:is(ul,ol):last-child>li:last-child]:after:w-0.5 [&>:is(ul,ol):last-child>li:last-child]:after:animate-pulse [&>:is(ul,ol):last-child>li:last-child]:after:rounded-full [&>:is(ul,ol):last-child>li:last-child]:after:bg-muted-foreground [&>:is(ul,ol):last-child>li:last-child]:after:align-text-bottom [&>:is(ul,ol):last-child>li:last-child]:after:content-['']";
|
|
56
57
|
function AssistantMessage({ item }) {
|
|
57
58
|
return /* @__PURE__ */ jsxs("div", { children: [
|
|
58
59
|
item.content && /* @__PURE__ */ jsx(Markdown, {
|
|
59
|
-
className: "tangle-prose text-[var(--font-size-base)] leading-[1.5]",
|
|
60
|
+
className: cn("tangle-prose text-[length:var(--font-size-base)] leading-[1.5]", item.isStreaming && STREAMING_CARET),
|
|
60
61
|
children: item.content
|
|
61
62
|
}),
|
|
62
|
-
item.isStreaming && /* @__PURE__ */ jsx("span", {
|
|
63
|
+
item.isStreaming && !item.content && /* @__PURE__ */ jsx("span", {
|
|
63
64
|
"aria-hidden": true,
|
|
64
65
|
"data-streaming-caret": "",
|
|
65
66
|
className: "ml-0.5 inline-block h-[1em] w-0.5 animate-pulse rounded-full bg-muted-foreground align-text-bottom"
|
|
@@ -19,10 +19,10 @@ function ChatMessage({ role, content, toolCalls, isStreaming, timestamp, classNa
|
|
|
19
19
|
}), /* @__PURE__ */ jsxs("div", {
|
|
20
20
|
className: cn("min-w-0 max-w-[85%] space-y-1", isUser ? "rounded-[var(--radius-lg)] bg-foreground px-[var(--chat-message-px)] py-[var(--chat-message-py)] text-background" : isAssistant ? "text-foreground" : "rounded-[var(--radius-lg)] border border-border bg-card px-[var(--chat-message-px)] py-[var(--chat-message-py)]"),
|
|
21
21
|
children: [isUser ? /* @__PURE__ */ jsx("div", {
|
|
22
|
-
className: "whitespace-pre-wrap text-[var(--font-size-base)] leading-[var(--line-height-base)]",
|
|
22
|
+
className: "whitespace-pre-wrap text-[length:var(--font-size-base)] leading-[var(--line-height-base)]",
|
|
23
23
|
children: content
|
|
24
24
|
}) : /* @__PURE__ */ jsxs(Fragment, { children: [content && /* @__PURE__ */ jsx(Markdown, {
|
|
25
|
-
className: "tangle-prose text-[var(--font-size-base)] leading-[var(--line-height-base)]",
|
|
25
|
+
className: "tangle-prose text-[length:var(--font-size-base)] leading-[var(--line-height-base)]",
|
|
26
26
|
children: content
|
|
27
27
|
}), isStreaming && /* @__PURE__ */ jsx("span", { className: "ml-0.5 inline-block h-4 w-2 animate-pulse rounded-sm bg-[var(--brand-cool)] align-text-bottom" })] }), toolCalls]
|
|
28
28
|
})]
|
|
@@ -29,7 +29,7 @@ function ThinkingIndicator({ className }) {
|
|
|
29
29
|
})
|
|
30
30
|
]
|
|
31
31
|
}), elapsed > 3 && /* @__PURE__ */ jsxs("span", {
|
|
32
|
-
className: "text-[var(--font-size-xs)] tabular-nums text-muted-foreground",
|
|
32
|
+
className: "text-[length:var(--font-size-xs)] tabular-nums text-muted-foreground",
|
|
33
33
|
children: [elapsed, "s"]
|
|
34
34
|
})]
|
|
35
35
|
});
|
|
@@ -23,10 +23,10 @@ function UserBubble({ text, timestamp, actions }) {
|
|
|
23
23
|
className: "relative w-full min-w-0 rounded-2xl bg-foreground px-4 py-3 text-background",
|
|
24
24
|
children: [timestamp ? /* @__PURE__ */ jsx("span", {
|
|
25
25
|
"data-user-message-time": "",
|
|
26
|
-
className: "pointer-events-none absolute right-full top-1/2 mr-3 -translate-y-1/2 whitespace-nowrap text-[var(--font-size-xs)] text-muted-foreground opacity-0 transition-opacity group-hover:opacity-100",
|
|
26
|
+
className: "pointer-events-none absolute right-full top-1/2 mr-3 -translate-y-1/2 whitespace-nowrap text-[length:var(--font-size-xs)] text-muted-foreground opacity-0 transition-opacity group-hover:opacity-100",
|
|
27
27
|
children: formatTime(timestamp)
|
|
28
28
|
}) : null, /* @__PURE__ */ jsx("div", {
|
|
29
|
-
className: "break-words whitespace-pre-wrap text-[var(--font-size-base)] leading-[1.5]",
|
|
29
|
+
className: "break-words whitespace-pre-wrap text-[length:var(--font-size-base)] leading-[1.5]",
|
|
30
30
|
children: text
|
|
31
31
|
})]
|
|
32
32
|
}), actions ? /* @__PURE__ */ jsx(MessageActions, { children: actions }) : null]
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { focusRing } from "../lib/focus.js";
|
|
1
|
+
import { focusRing, focusRingInset } from "../lib/focus.js";
|
|
2
2
|
import { cn } from "../lib/utils.js";
|
|
3
3
|
import { memo, useCallback, useEffect, useRef, useState } from "react";
|
|
4
4
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -93,6 +93,12 @@ const CodeBlock = memo(({ code, language, label, showLineNumbers = false, light,
|
|
|
93
93
|
overflowX: "auto"
|
|
94
94
|
};
|
|
95
95
|
const codeTagProps = { style: { fontFamily: "var(--font-mono, 'JetBrains Mono', ui-monospace, monospace)" } };
|
|
96
|
+
const scrollRegion = {
|
|
97
|
+
tabIndex: 0,
|
|
98
|
+
role: "region",
|
|
99
|
+
"aria-label": headerLabel ? `${headerLabel} code` : "Code",
|
|
100
|
+
className: focusRingInset
|
|
101
|
+
};
|
|
96
102
|
return /* @__PURE__ */ jsxs("div", {
|
|
97
103
|
className: cn("group relative overflow-hidden rounded-lg border font-mono", "bg-card border-border", className),
|
|
98
104
|
...props,
|
|
@@ -121,8 +127,10 @@ const CodeBlock = memo(({ code, language, label, showLineNumbers = false, light,
|
|
|
121
127
|
customStyle,
|
|
122
128
|
codeTagProps,
|
|
123
129
|
wrapLines: false,
|
|
130
|
+
...scrollRegion,
|
|
124
131
|
children: code
|
|
125
132
|
}) : /* @__PURE__ */ jsx("pre", {
|
|
133
|
+
...scrollRegion,
|
|
126
134
|
style: {
|
|
127
135
|
...syntaxTheme.hljs,
|
|
128
136
|
...customStyle
|
|
@@ -1592,7 +1592,6 @@ const schema33 = {
|
|
|
1592
1592
|
"wrap": { "type": "boolean" },
|
|
1593
1593
|
"children": {
|
|
1594
1594
|
"type": "array",
|
|
1595
|
-
"minItems": 1,
|
|
1596
1595
|
"items": { "$ref": "#/$defs/node" }
|
|
1597
1596
|
}
|
|
1598
1597
|
},
|
|
@@ -1807,7 +1806,6 @@ const schema46 = {
|
|
|
1807
1806
|
] },
|
|
1808
1807
|
"children": {
|
|
1809
1808
|
"type": "array",
|
|
1810
|
-
"minItems": 1,
|
|
1811
1809
|
"items": { "$ref": "#/$defs/node" }
|
|
1812
1810
|
}
|
|
1813
1811
|
},
|
|
@@ -1909,30 +1907,19 @@ function validate27(data, { instancePath = "", parentData, parentDataProperty, r
|
|
|
1909
1907
|
const _errs7 = errors;
|
|
1910
1908
|
if (errors === _errs7) {
|
|
1911
1909
|
if (Array.isArray(data4)) {
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
for (let i0 = 0; i0 < len0; i0++) {
|
|
1924
|
-
const _errs9 = errors;
|
|
1925
|
-
if (!wrapper1.validate(data4[i0], {
|
|
1926
|
-
instancePath: instancePath + "/children/" + i0,
|
|
1927
|
-
parentData: data4,
|
|
1928
|
-
parentDataProperty: i0,
|
|
1929
|
-
rootData
|
|
1930
|
-
})) {
|
|
1931
|
-
vErrors = vErrors === null ? wrapper1.validate.errors : vErrors.concat(wrapper1.validate.errors);
|
|
1932
|
-
errors = vErrors.length;
|
|
1933
|
-
}
|
|
1934
|
-
if (!(_errs9 === errors)) break;
|
|
1910
|
+
const len0 = data4.length;
|
|
1911
|
+
for (let i0 = 0; i0 < len0; i0++) {
|
|
1912
|
+
const _errs9 = errors;
|
|
1913
|
+
if (!wrapper1.validate(data4[i0], {
|
|
1914
|
+
instancePath: instancePath + "/children/" + i0,
|
|
1915
|
+
parentData: data4,
|
|
1916
|
+
parentDataProperty: i0,
|
|
1917
|
+
rootData
|
|
1918
|
+
})) {
|
|
1919
|
+
vErrors = vErrors === null ? wrapper1.validate.errors : vErrors.concat(wrapper1.validate.errors);
|
|
1920
|
+
errors = vErrors.length;
|
|
1935
1921
|
}
|
|
1922
|
+
if (!(_errs9 === errors)) break;
|
|
1936
1923
|
}
|
|
1937
1924
|
} else {
|
|
1938
1925
|
validate27.errors = [{
|
|
@@ -2319,30 +2306,19 @@ function validate29(data, { instancePath = "", parentData, parentDataProperty, r
|
|
|
2319
2306
|
const _errs34 = errors;
|
|
2320
2307
|
if (errors === _errs34) {
|
|
2321
2308
|
if (Array.isArray(data16)) {
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
for (let i1 = 0; i1 < len1; i1++) {
|
|
2334
|
-
const _errs36 = errors;
|
|
2335
|
-
if (!wrapper1.validate(data16[i1], {
|
|
2336
|
-
instancePath: instancePath + "/children/" + i1,
|
|
2337
|
-
parentData: data16,
|
|
2338
|
-
parentDataProperty: i1,
|
|
2339
|
-
rootData
|
|
2340
|
-
})) {
|
|
2341
|
-
vErrors = vErrors === null ? wrapper1.validate.errors : vErrors.concat(wrapper1.validate.errors);
|
|
2342
|
-
errors = vErrors.length;
|
|
2343
|
-
}
|
|
2344
|
-
if (!(_errs36 === errors)) break;
|
|
2309
|
+
const len1 = data16.length;
|
|
2310
|
+
for (let i1 = 0; i1 < len1; i1++) {
|
|
2311
|
+
const _errs36 = errors;
|
|
2312
|
+
if (!wrapper1.validate(data16[i1], {
|
|
2313
|
+
instancePath: instancePath + "/children/" + i1,
|
|
2314
|
+
parentData: data16,
|
|
2315
|
+
parentDataProperty: i1,
|
|
2316
|
+
rootData
|
|
2317
|
+
})) {
|
|
2318
|
+
vErrors = vErrors === null ? wrapper1.validate.errors : vErrors.concat(wrapper1.validate.errors);
|
|
2319
|
+
errors = vErrors.length;
|
|
2345
2320
|
}
|
|
2321
|
+
if (!(_errs36 === errors)) break;
|
|
2346
2322
|
}
|
|
2347
2323
|
} else {
|
|
2348
2324
|
validate29.errors = [{
|
|
@@ -4139,30 +4115,19 @@ function validate23(data, { instancePath = "", parentData, parentDataProperty, r
|
|
|
4139
4115
|
const _errs10 = errors;
|
|
4140
4116
|
if (errors === _errs10) {
|
|
4141
4117
|
if (Array.isArray(data6)) {
|
|
4142
|
-
|
|
4143
|
-
|
|
4144
|
-
|
|
4145
|
-
|
|
4146
|
-
|
|
4147
|
-
|
|
4148
|
-
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
for (let i0 = 0; i0 < len0; i0++) {
|
|
4154
|
-
const _errs12 = errors;
|
|
4155
|
-
if (!validate24(data6[i0], {
|
|
4156
|
-
instancePath: instancePath + "/children/" + i0,
|
|
4157
|
-
parentData: data6,
|
|
4158
|
-
parentDataProperty: i0,
|
|
4159
|
-
rootData
|
|
4160
|
-
})) {
|
|
4161
|
-
vErrors = vErrors === null ? validate24.errors : vErrors.concat(validate24.errors);
|
|
4162
|
-
errors = vErrors.length;
|
|
4163
|
-
}
|
|
4164
|
-
if (!(_errs12 === errors)) break;
|
|
4118
|
+
const len0 = data6.length;
|
|
4119
|
+
for (let i0 = 0; i0 < len0; i0++) {
|
|
4120
|
+
const _errs12 = errors;
|
|
4121
|
+
if (!validate24(data6[i0], {
|
|
4122
|
+
instancePath: instancePath + "/children/" + i0,
|
|
4123
|
+
parentData: data6,
|
|
4124
|
+
parentDataProperty: i0,
|
|
4125
|
+
rootData
|
|
4126
|
+
})) {
|
|
4127
|
+
vErrors = vErrors === null ? validate24.errors : vErrors.concat(validate24.errors);
|
|
4128
|
+
errors = vErrors.length;
|
|
4165
4129
|
}
|
|
4130
|
+
if (!(_errs12 === errors)) break;
|
|
4166
4131
|
}
|
|
4167
4132
|
} else {
|
|
4168
4133
|
validate23.errors = [{
|
|
@@ -4532,30 +4497,19 @@ function validate38(data, { instancePath = "", parentData, parentDataProperty, r
|
|
|
4532
4497
|
const _errs10 = errors;
|
|
4533
4498
|
if (errors === _errs10) {
|
|
4534
4499
|
if (Array.isArray(data6)) {
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
|
|
4539
|
-
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
|
|
4545
|
-
|
|
4546
|
-
for (let i0 = 0; i0 < len0; i0++) {
|
|
4547
|
-
const _errs12 = errors;
|
|
4548
|
-
if (!wrapper3.validate(data6[i0], {
|
|
4549
|
-
instancePath: instancePath + "/children/" + i0,
|
|
4550
|
-
parentData: data6,
|
|
4551
|
-
parentDataProperty: i0,
|
|
4552
|
-
rootData
|
|
4553
|
-
})) {
|
|
4554
|
-
vErrors = vErrors === null ? wrapper3.validate.errors : vErrors.concat(wrapper3.validate.errors);
|
|
4555
|
-
errors = vErrors.length;
|
|
4556
|
-
}
|
|
4557
|
-
if (!(_errs12 === errors)) break;
|
|
4500
|
+
const len0 = data6.length;
|
|
4501
|
+
for (let i0 = 0; i0 < len0; i0++) {
|
|
4502
|
+
const _errs12 = errors;
|
|
4503
|
+
if (!wrapper3.validate(data6[i0], {
|
|
4504
|
+
instancePath: instancePath + "/children/" + i0,
|
|
4505
|
+
parentData: data6,
|
|
4506
|
+
parentDataProperty: i0,
|
|
4507
|
+
rootData
|
|
4508
|
+
})) {
|
|
4509
|
+
vErrors = vErrors === null ? wrapper3.validate.errors : vErrors.concat(wrapper3.validate.errors);
|
|
4510
|
+
errors = vErrors.length;
|
|
4558
4511
|
}
|
|
4512
|
+
if (!(_errs12 === errors)) break;
|
|
4559
4513
|
}
|
|
4560
4514
|
} else {
|
|
4561
4515
|
validate38.errors = [{
|
|
@@ -4944,30 +4898,19 @@ function validate40(data, { instancePath = "", parentData, parentDataProperty, r
|
|
|
4944
4898
|
const _errs34 = errors;
|
|
4945
4899
|
if (errors === _errs34) {
|
|
4946
4900
|
if (Array.isArray(data16)) {
|
|
4947
|
-
|
|
4948
|
-
|
|
4949
|
-
|
|
4950
|
-
|
|
4951
|
-
|
|
4952
|
-
|
|
4953
|
-
|
|
4954
|
-
|
|
4955
|
-
|
|
4956
|
-
|
|
4957
|
-
|
|
4958
|
-
for (let i1 = 0; i1 < len1; i1++) {
|
|
4959
|
-
const _errs36 = errors;
|
|
4960
|
-
if (!wrapper3.validate(data16[i1], {
|
|
4961
|
-
instancePath: instancePath + "/children/" + i1,
|
|
4962
|
-
parentData: data16,
|
|
4963
|
-
parentDataProperty: i1,
|
|
4964
|
-
rootData
|
|
4965
|
-
})) {
|
|
4966
|
-
vErrors = vErrors === null ? wrapper3.validate.errors : vErrors.concat(wrapper3.validate.errors);
|
|
4967
|
-
errors = vErrors.length;
|
|
4968
|
-
}
|
|
4969
|
-
if (!(_errs36 === errors)) break;
|
|
4901
|
+
const len1 = data16.length;
|
|
4902
|
+
for (let i1 = 0; i1 < len1; i1++) {
|
|
4903
|
+
const _errs36 = errors;
|
|
4904
|
+
if (!wrapper3.validate(data16[i1], {
|
|
4905
|
+
instancePath: instancePath + "/children/" + i1,
|
|
4906
|
+
parentData: data16,
|
|
4907
|
+
parentDataProperty: i1,
|
|
4908
|
+
rootData
|
|
4909
|
+
})) {
|
|
4910
|
+
vErrors = vErrors === null ? wrapper3.validate.errors : vErrors.concat(wrapper3.validate.errors);
|
|
4911
|
+
errors = vErrors.length;
|
|
4970
4912
|
}
|
|
4913
|
+
if (!(_errs36 === errors)) break;
|
|
4971
4914
|
}
|
|
4972
4915
|
} else {
|
|
4973
4916
|
validate40.errors = [{
|
|
@@ -6733,30 +6676,19 @@ function validate34(data, { instancePath = "", parentData, parentDataProperty, r
|
|
|
6733
6676
|
const _errs7 = errors;
|
|
6734
6677
|
if (errors === _errs7) {
|
|
6735
6678
|
if (Array.isArray(data4)) {
|
|
6736
|
-
|
|
6737
|
-
|
|
6738
|
-
|
|
6739
|
-
|
|
6740
|
-
|
|
6741
|
-
|
|
6742
|
-
|
|
6743
|
-
|
|
6744
|
-
|
|
6745
|
-
|
|
6746
|
-
|
|
6747
|
-
for (let i0 = 0; i0 < len0; i0++) {
|
|
6748
|
-
const _errs9 = errors;
|
|
6749
|
-
if (!validate35(data4[i0], {
|
|
6750
|
-
instancePath: instancePath + "/children/" + i0,
|
|
6751
|
-
parentData: data4,
|
|
6752
|
-
parentDataProperty: i0,
|
|
6753
|
-
rootData
|
|
6754
|
-
})) {
|
|
6755
|
-
vErrors = vErrors === null ? validate35.errors : vErrors.concat(validate35.errors);
|
|
6756
|
-
errors = vErrors.length;
|
|
6757
|
-
}
|
|
6758
|
-
if (!(_errs9 === errors)) break;
|
|
6679
|
+
const len0 = data4.length;
|
|
6680
|
+
for (let i0 = 0; i0 < len0; i0++) {
|
|
6681
|
+
const _errs9 = errors;
|
|
6682
|
+
if (!validate35(data4[i0], {
|
|
6683
|
+
instancePath: instancePath + "/children/" + i0,
|
|
6684
|
+
parentData: data4,
|
|
6685
|
+
parentDataProperty: i0,
|
|
6686
|
+
rootData
|
|
6687
|
+
})) {
|
|
6688
|
+
vErrors = vErrors === null ? validate35.errors : vErrors.concat(validate35.errors);
|
|
6689
|
+
errors = vErrors.length;
|
|
6759
6690
|
}
|
|
6691
|
+
if (!(_errs9 === errors)) break;
|
|
6760
6692
|
}
|
|
6761
6693
|
} else {
|
|
6762
6694
|
validate34.errors = [{
|
|
@@ -7124,30 +7056,19 @@ function validate49(data, { instancePath = "", parentData, parentDataProperty, r
|
|
|
7124
7056
|
const _errs10 = errors;
|
|
7125
7057
|
if (errors === _errs10) {
|
|
7126
7058
|
if (Array.isArray(data6)) {
|
|
7127
|
-
|
|
7128
|
-
|
|
7129
|
-
|
|
7130
|
-
|
|
7131
|
-
|
|
7132
|
-
|
|
7133
|
-
|
|
7134
|
-
|
|
7135
|
-
|
|
7136
|
-
|
|
7137
|
-
|
|
7138
|
-
for (let i0 = 0; i0 < len0; i0++) {
|
|
7139
|
-
const _errs12 = errors;
|
|
7140
|
-
if (!wrapper6.validate(data6[i0], {
|
|
7141
|
-
instancePath: instancePath + "/children/" + i0,
|
|
7142
|
-
parentData: data6,
|
|
7143
|
-
parentDataProperty: i0,
|
|
7144
|
-
rootData
|
|
7145
|
-
})) {
|
|
7146
|
-
vErrors = vErrors === null ? wrapper6.validate.errors : vErrors.concat(wrapper6.validate.errors);
|
|
7147
|
-
errors = vErrors.length;
|
|
7148
|
-
}
|
|
7149
|
-
if (!(_errs12 === errors)) break;
|
|
7059
|
+
const len0 = data6.length;
|
|
7060
|
+
for (let i0 = 0; i0 < len0; i0++) {
|
|
7061
|
+
const _errs12 = errors;
|
|
7062
|
+
if (!wrapper6.validate(data6[i0], {
|
|
7063
|
+
instancePath: instancePath + "/children/" + i0,
|
|
7064
|
+
parentData: data6,
|
|
7065
|
+
parentDataProperty: i0,
|
|
7066
|
+
rootData
|
|
7067
|
+
})) {
|
|
7068
|
+
vErrors = vErrors === null ? wrapper6.validate.errors : vErrors.concat(wrapper6.validate.errors);
|
|
7069
|
+
errors = vErrors.length;
|
|
7150
7070
|
}
|
|
7071
|
+
if (!(_errs12 === errors)) break;
|
|
7151
7072
|
}
|
|
7152
7073
|
} else {
|
|
7153
7074
|
validate49.errors = [{
|
|
@@ -7279,30 +7200,19 @@ function validate51(data, { instancePath = "", parentData, parentDataProperty, r
|
|
|
7279
7200
|
const _errs7 = errors;
|
|
7280
7201
|
if (errors === _errs7) {
|
|
7281
7202
|
if (Array.isArray(data4)) {
|
|
7282
|
-
|
|
7283
|
-
|
|
7284
|
-
|
|
7285
|
-
|
|
7286
|
-
|
|
7287
|
-
|
|
7288
|
-
|
|
7289
|
-
|
|
7290
|
-
|
|
7291
|
-
|
|
7292
|
-
|
|
7293
|
-
for (let i0 = 0; i0 < len0; i0++) {
|
|
7294
|
-
const _errs9 = errors;
|
|
7295
|
-
if (!wrapper6.validate(data4[i0], {
|
|
7296
|
-
instancePath: instancePath + "/children/" + i0,
|
|
7297
|
-
parentData: data4,
|
|
7298
|
-
parentDataProperty: i0,
|
|
7299
|
-
rootData
|
|
7300
|
-
})) {
|
|
7301
|
-
vErrors = vErrors === null ? wrapper6.validate.errors : vErrors.concat(wrapper6.validate.errors);
|
|
7302
|
-
errors = vErrors.length;
|
|
7303
|
-
}
|
|
7304
|
-
if (!(_errs9 === errors)) break;
|
|
7203
|
+
const len0 = data4.length;
|
|
7204
|
+
for (let i0 = 0; i0 < len0; i0++) {
|
|
7205
|
+
const _errs9 = errors;
|
|
7206
|
+
if (!wrapper6.validate(data4[i0], {
|
|
7207
|
+
instancePath: instancePath + "/children/" + i0,
|
|
7208
|
+
parentData: data4,
|
|
7209
|
+
parentDataProperty: i0,
|
|
7210
|
+
rootData
|
|
7211
|
+
})) {
|
|
7212
|
+
vErrors = vErrors === null ? wrapper6.validate.errors : vErrors.concat(wrapper6.validate.errors);
|
|
7213
|
+
errors = vErrors.length;
|
|
7305
7214
|
}
|
|
7215
|
+
if (!(_errs9 === errors)) break;
|
|
7306
7216
|
}
|
|
7307
7217
|
} else {
|
|
7308
7218
|
validate51.errors = [{
|
|
@@ -9322,30 +9232,19 @@ function validate45(data, { instancePath = "", parentData, parentDataProperty, r
|
|
|
9322
9232
|
const _errs34 = errors;
|
|
9323
9233
|
if (errors === _errs34) {
|
|
9324
9234
|
if (Array.isArray(data16)) {
|
|
9325
|
-
|
|
9326
|
-
|
|
9327
|
-
|
|
9328
|
-
|
|
9329
|
-
|
|
9330
|
-
|
|
9331
|
-
|
|
9332
|
-
|
|
9333
|
-
|
|
9334
|
-
|
|
9335
|
-
|
|
9336
|
-
for (let i1 = 0; i1 < len1; i1++) {
|
|
9337
|
-
const _errs36 = errors;
|
|
9338
|
-
if (!validate46(data16[i1], {
|
|
9339
|
-
instancePath: instancePath + "/children/" + i1,
|
|
9340
|
-
parentData: data16,
|
|
9341
|
-
parentDataProperty: i1,
|
|
9342
|
-
rootData
|
|
9343
|
-
})) {
|
|
9344
|
-
vErrors = vErrors === null ? validate46.errors : vErrors.concat(validate46.errors);
|
|
9345
|
-
errors = vErrors.length;
|
|
9346
|
-
}
|
|
9347
|
-
if (!(_errs36 === errors)) break;
|
|
9235
|
+
const len1 = data16.length;
|
|
9236
|
+
for (let i1 = 0; i1 < len1; i1++) {
|
|
9237
|
+
const _errs36 = errors;
|
|
9238
|
+
if (!validate46(data16[i1], {
|
|
9239
|
+
instancePath: instancePath + "/children/" + i1,
|
|
9240
|
+
parentData: data16,
|
|
9241
|
+
parentDataProperty: i1,
|
|
9242
|
+
rootData
|
|
9243
|
+
})) {
|
|
9244
|
+
vErrors = vErrors === null ? validate46.errors : vErrors.concat(validate46.errors);
|
|
9245
|
+
errors = vErrors.length;
|
|
9348
9246
|
}
|
|
9247
|
+
if (!(_errs36 === errors)) break;
|
|
9349
9248
|
}
|
|
9350
9249
|
} else {
|
|
9351
9250
|
validate45.errors = [{
|
package/dist/openui-schema.js
CHANGED
|
@@ -26,6 +26,10 @@ function findUnsupportedOpenUINode(value) {
|
|
|
26
26
|
message: `Unsupported OpenUI node type: ${String(record.type)}.`
|
|
27
27
|
};
|
|
28
28
|
if (record.type === "stack" || record.type === "grid" || record.type === "card") {
|
|
29
|
+
if (Array.isArray(record.children) && record.children.length === 0) return {
|
|
30
|
+
path: `${path}.children`,
|
|
31
|
+
message: "OpenUI containers need at least one child."
|
|
32
|
+
};
|
|
29
33
|
if (Array.isArray(record.children)) for (const [index, child] of record.children.entries()) {
|
|
30
34
|
const issue = visit(child, `${path}.children[${index}]`, depth + 1);
|
|
31
35
|
if (issue) return issue;
|
|
@@ -7,7 +7,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
7
7
|
* "Show more / Show less" toggle. Content shorter than the cap renders
|
|
8
8
|
* as-is with no toggle.
|
|
9
9
|
*/
|
|
10
|
-
function ExpandableContent({ children, collapsedMaxPx = 180, fadeClassName = "from-muted", className }) {
|
|
10
|
+
function ExpandableContent({ children, collapsedMaxPx = 180, fadeClassName = "from-muted", className, toggleClassName }) {
|
|
11
11
|
const [expanded, setExpanded] = useState(false);
|
|
12
12
|
const [overflowing, setOverflowing] = useState(false);
|
|
13
13
|
const contentRef = useRef(null);
|
|
@@ -32,7 +32,7 @@ function ExpandableContent({ children, collapsedMaxPx = 180, fadeClassName = "fr
|
|
|
32
32
|
}), overflowing ? /* @__PURE__ */ jsx("button", {
|
|
33
33
|
type: "button",
|
|
34
34
|
onClick: () => setExpanded((value) => !value),
|
|
35
|
-
className: "mt-1 text-[11px] font-medium text-muted-foreground transition-colors hover:text-foreground",
|
|
35
|
+
className: cn("mt-1 text-[11px] font-medium text-muted-foreground transition-colors hover:text-foreground", toggleClassName),
|
|
36
36
|
children: expanded ? "Show less" : "Show more"
|
|
37
37
|
}) : null]
|
|
38
38
|
});
|
|
@@ -13,6 +13,7 @@ import { memo } from "react";
|
|
|
13
13
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
14
14
|
import { AlertCircle, ArrowLeft, ArrowRight, FileText, Loader2 } from "lucide-react";
|
|
15
15
|
//#region src/run/expanded-tool-detail.tsx
|
|
16
|
+
const FLUSH_TOGGLE = "mx-3 mb-2";
|
|
16
17
|
const EXT_LANG = {
|
|
17
18
|
ts: "typescript",
|
|
18
19
|
tsx: "tsx",
|
|
@@ -131,6 +132,7 @@ const ExpandedToolDetail = memo(({ part }) => {
|
|
|
131
132
|
})]
|
|
132
133
|
}), /* @__PURE__ */ jsx(ExpandableContent, {
|
|
133
134
|
fadeClassName: "from-card",
|
|
135
|
+
toggleClassName: FLUSH_TOGGLE,
|
|
134
136
|
children: /* @__PURE__ */ jsx(CodeBlock, {
|
|
135
137
|
code: outputStr.length > 2e3 ? outputStr.slice(0, 2e3) + "\n...(truncated)" : outputStr,
|
|
136
138
|
language: "json",
|
|
@@ -148,6 +150,7 @@ const ExpandedToolDetail = memo(({ part }) => {
|
|
|
148
150
|
})]
|
|
149
151
|
}), /* @__PURE__ */ jsx(ExpandableContent, {
|
|
150
152
|
fadeClassName: "from-[var(--surface-danger-bg)]",
|
|
153
|
+
toggleClassName: FLUSH_TOGGLE,
|
|
151
154
|
children: /* @__PURE__ */ jsx("pre", {
|
|
152
155
|
className: "bg-[var(--surface-danger-bg)] p-3 text-xs font-mono whitespace-pre-wrap break-all text-[var(--surface-danger-text)]",
|
|
153
156
|
children: error
|
package/package.json
CHANGED
|
@@ -253,20 +253,6 @@ describe("AgentTimeline tool actions", () => {
|
|
|
253
253
|
expect(classes[4]).toContain("mt-4") // prose → user
|
|
254
254
|
})
|
|
255
255
|
|
|
256
|
-
it("softens the streaming cursor to a muted caret", () => {
|
|
257
|
-
const { container } = render(
|
|
258
|
-
<AgentTimeline
|
|
259
|
-
items={[
|
|
260
|
-
{ id: "a-1", kind: "message", role: "assistant", content: "Typing", isStreaming: true },
|
|
261
|
-
]}
|
|
262
|
-
/>,
|
|
263
|
-
)
|
|
264
|
-
const caret = container.querySelector("[data-streaming-caret]")
|
|
265
|
-
expect(caret).not.toBeNull()
|
|
266
|
-
expect(caret!.className).toContain("bg-muted-foreground")
|
|
267
|
-
expect(caret!.className).not.toContain("bg-primary")
|
|
268
|
-
})
|
|
269
|
-
|
|
270
256
|
it("renders the source part's real input in the expanded detail", async () => {
|
|
271
257
|
const user = userEvent.setup()
|
|
272
258
|
const probePart: ToolPart = {
|
|
@@ -162,13 +162,29 @@ function spacingBefore(prev: StepKind | undefined, next: StepKind): string {
|
|
|
162
162
|
// wider than the bleed, so nothing clips.
|
|
163
163
|
const ROW_BLEED = "-mx-3";
|
|
164
164
|
|
|
165
|
+
// The streaming caret ends the last line of text. It is drawn as the `::after`
|
|
166
|
+
// of the prose's last block (the last item of a trailing list), so it follows
|
|
167
|
+
// the final word instead of starting a line of its own below the paragraph.
|
|
168
|
+
const STREAMING_CARET =
|
|
169
|
+
"[&>:last-child:not(ul,ol)]:after:ml-0.5 [&>:last-child:not(ul,ol)]:after:inline-block [&>:last-child:not(ul,ol)]:after:h-[1em] [&>:last-child:not(ul,ol)]:after:w-0.5 [&>:last-child:not(ul,ol)]:after:animate-pulse [&>:last-child:not(ul,ol)]:after:rounded-full [&>:last-child:not(ul,ol)]:after:bg-muted-foreground [&>:last-child:not(ul,ol)]:after:align-text-bottom [&>:last-child:not(ul,ol)]:after:content-[''] " +
|
|
170
|
+
"[&>:is(ul,ol):last-child>li:last-child]:after:ml-0.5 [&>:is(ul,ol):last-child>li:last-child]:after:inline-block [&>:is(ul,ol):last-child>li:last-child]:after:h-[1em] [&>:is(ul,ol):last-child>li:last-child]:after:w-0.5 [&>:is(ul,ol):last-child>li:last-child]:after:animate-pulse [&>:is(ul,ol):last-child>li:last-child]:after:rounded-full [&>:is(ul,ol):last-child>li:last-child]:after:bg-muted-foreground [&>:is(ul,ol):last-child>li:last-child]:after:align-text-bottom [&>:is(ul,ol):last-child>li:last-child]:after:content-['']";
|
|
171
|
+
|
|
165
172
|
function AssistantMessage({ item }: { item: AgentTimelineMessageItem }) {
|
|
166
173
|
return (
|
|
167
174
|
<div>
|
|
168
175
|
{item.content && (
|
|
169
|
-
<Markdown
|
|
176
|
+
<Markdown
|
|
177
|
+
// `length:` types the token: a bare `text-[var(--x)]` compiles to a
|
|
178
|
+
// color, which left the reading size at the Markdown default.
|
|
179
|
+
className={cn(
|
|
180
|
+
"tangle-prose text-[length:var(--font-size-base)] leading-[1.5]",
|
|
181
|
+
item.isStreaming && STREAMING_CARET,
|
|
182
|
+
)}
|
|
183
|
+
>
|
|
184
|
+
{item.content}
|
|
185
|
+
</Markdown>
|
|
170
186
|
)}
|
|
171
|
-
{item.isStreaming && (
|
|
187
|
+
{item.isStreaming && !item.content && (
|
|
172
188
|
<span
|
|
173
189
|
aria-hidden
|
|
174
190
|
data-streaming-caret=""
|