@adea-ai/ui 0.67.1 → 0.68.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/README.md +58 -0
  2. package/dist/NOTICE +34 -0
  3. package/dist/components/conversation/index.d.ts +1 -0
  4. package/dist/components/conversation/index.d.ts.map +1 -1
  5. package/dist/components/conversation/index.js +2 -1
  6. package/dist/components/conversation/transcript-composition.d.ts +66 -0
  7. package/dist/components/conversation/transcript-composition.d.ts.map +1 -0
  8. package/dist/components/conversation/transcript-composition.js +395 -0
  9. package/dist/components/conversation/transcript-composition.js.map +1 -0
  10. package/dist/components/conversation/transcript-folding.d.ts +22 -0
  11. package/dist/components/conversation/transcript-folding.d.ts.map +1 -0
  12. package/dist/components/conversation/transcript-folding.js +43 -0
  13. package/dist/components/conversation/transcript-folding.js.map +1 -0
  14. package/dist/components/conversation/transcript-grouping.d.ts +54 -0
  15. package/dist/components/conversation/transcript-grouping.d.ts.map +1 -0
  16. package/dist/components/conversation/transcript-grouping.js +155 -0
  17. package/dist/components/conversation/transcript-grouping.js.map +1 -0
  18. package/dist/index.js +2 -1
  19. package/dist/r/conversation.json +15 -0
  20. package/dist/r/registry.json +15 -0
  21. package/dist/r/src/components/conversation/index.ts +17 -0
  22. package/dist/r/src/components/conversation/transcript-composition.tsx +555 -0
  23. package/dist/r/src/components/conversation/transcript-folding.ts +61 -0
  24. package/dist/r/src/components/conversation/transcript-grouping.ts +204 -0
  25. package/package.json +8 -1
  26. package/registry.json +15 -0
  27. package/src/components/conversation/index.ts +17 -0
  28. package/src/components/conversation/transcript-composition.tsx +555 -0
  29. package/src/components/conversation/transcript-folding.ts +61 -0
  30. package/src/components/conversation/transcript-grouping.ts +204 -0
@@ -0,0 +1,204 @@
1
+ /*
2
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ * Licensed under the Apache License, Version 2.0.
4
+ *
5
+ * Substantially translated from KiroCrew groupDisplayItems.ts at
6
+ * 283e136c0f902e965a535a7c9548c57c7504fed0. Protocol classification is supplied
7
+ * by the host; no Kiro role, metadata parser, store, or transport is imported.
8
+ */
9
+
10
+ /** Immutable, already-redacted host rows. Unknown rows remain visible singles. */
11
+ export type TranscriptRow<T> = Readonly<{
12
+ id: string
13
+ value: T
14
+ hidden?: boolean
15
+ groupable?: boolean
16
+ working?: boolean
17
+ /** True only for a content-bearing reasoning trace, never an empty placeholder. */
18
+ reasoning?: boolean
19
+ opensTurn?: 'reset' | 'continue'
20
+ synthesis?: boolean
21
+ /** A proven answer boundary, supplied by the host rather than inferred from text. */
22
+ turnEnd?: boolean
23
+ /** Content that a synthesis does not restate; prevents interim folding. */
24
+ foreign?: boolean
25
+ /** Explicit host eligibility; unknown content never folds. */
26
+ fold?: 'tool' | 'prose'
27
+ /** Errors, approvals, questions, diffs, renderables and interactive payloads bypass every fold. */
28
+ alwaysVisible?: boolean
29
+ /** A host-designated substantive answer. No text-length or role heuristic is applied. */
30
+ conclusion?: boolean
31
+ /** Request/result classification is supplied by the host, never parsed from display text. */
32
+ call?: Readonly<{ phase: 'request' | 'result'; id?: string }>
33
+ }>
34
+
35
+ export type TranscriptTurnItem<T> =
36
+ | Readonly<{ kind: 'single'; row: TranscriptRow<T>; index: number }>
37
+ | Readonly<{ kind: 'group'; rows: readonly TranscriptRow<T>[]; startIndex: number }>
38
+
39
+ export type TranscriptDisplayItem<T> =
40
+ | TranscriptTurnItem<T>
41
+ | Readonly<{
42
+ kind: 'turn'
43
+ items: readonly TranscriptTurnItem<T>[]
44
+ /** Presentation bookkeeping, never evidence of successful runtime completion. */
45
+ complete: boolean
46
+ interim?: boolean
47
+ }>
48
+
49
+ export type GroupedTranscript<T> = Readonly<{
50
+ turns: readonly TranscriptDisplayItem<T>[]
51
+ trailingTurnIndex: number
52
+ }>
53
+
54
+ /** Ordered O(N) grouping; approvals are retained unless their host explicitly owns them elsewhere. */
55
+ export function groupTranscriptRows<T>(rows: readonly TranscriptRow<T>[]): GroupedTranscript<T> {
56
+ const raw: TranscriptTurnItem<T>[] = []
57
+ let group: TranscriptRow<T>[] = []
58
+ let groupStart = 0
59
+ rows.forEach((row, index) => {
60
+ if (row.hidden) return
61
+ if (row.groupable) {
62
+ if (!group.length) groupStart = index
63
+ group.push(row)
64
+ } else {
65
+ if (group.length) {
66
+ raw.push({ kind: 'group', rows: group, startIndex: groupStart })
67
+ group = []
68
+ }
69
+ raw.push({ kind: 'single', row, index })
70
+ }
71
+ })
72
+ if (group.length) raw.push({ kind: 'group', rows: group, startIndex: groupStart })
73
+
74
+ const turns: TranscriptDisplayItem<T>[] = []
75
+ let items: TranscriptTurnItem<T>[] = []
76
+ let regionStart = 0
77
+ let foreign = false
78
+ let pendingAnswer = false
79
+ const flush = (batch: TranscriptTurnItem<T>[]) => {
80
+ const working = batch.some((item) => item.kind === 'group' || item.row.working)
81
+ const reasoning = batch.reduce(
82
+ (count, item) => count + Number(item.kind === 'single' && item.row.reasoning === true),
83
+ 0
84
+ )
85
+ if ((working && batch.length > 2) || reasoning >= 2)
86
+ turns.push({ kind: 'turn', items: batch, complete: true })
87
+ else turns.push(...batch)
88
+ }
89
+ const foldInterim = () => {
90
+ const region = turns.splice(regionStart)
91
+ const folded = region.flatMap((item) => (item.kind === 'turn' ? [...item.items] : [item]))
92
+ if (folded.length) turns.push({ kind: 'turn', items: folded, complete: true, interim: true })
93
+ }
94
+ const settleAnswer = () => {
95
+ if (!pendingAnswer) return
96
+ const end = items.findIndex((item) => item.kind === 'single' && item.row.turnEnd)
97
+ if (end >= 0) {
98
+ flush(items.slice(0, end + 1))
99
+ items = items.slice(end + 1)
100
+ regionStart = turns.length
101
+ // Recompute from retained rows: an unrelated injection after the answer
102
+ // must still protect the next wave, while an earlier one must not poison it.
103
+ foreign = items.some((item) => item.kind === 'single' && item.row.foreign)
104
+ } else foreign = true
105
+ pendingAnswer = false
106
+ }
107
+ for (const item of raw) {
108
+ if (item.kind === 'single' && item.row.synthesis) {
109
+ settleAnswer()
110
+ if (items.length) {
111
+ flush(items)
112
+ items = []
113
+ }
114
+ if (!foreign) foldInterim()
115
+ items.push(item)
116
+ regionStart = turns.length
117
+ pendingAnswer = true
118
+ continue
119
+ }
120
+ if (item.kind === 'single' && item.row.foreign) foreign = true
121
+ if (item.kind === 'single' && item.row.opensTurn) {
122
+ settleAnswer()
123
+ if (items.length) {
124
+ flush(items)
125
+ items = []
126
+ }
127
+ turns.push(item)
128
+ if (item.row.opensTurn === 'reset') {
129
+ regionStart = turns.length
130
+ foreign = false
131
+ pendingAnswer = false
132
+ }
133
+ continue
134
+ }
135
+ items.push(item)
136
+ }
137
+ let trailingTurnIndex = -1
138
+ if (items.length) {
139
+ const before = turns.length
140
+ flush(items)
141
+ if (turns.length === before + 1 && turns.at(-1)?.kind === 'turn')
142
+ trailingTurnIndex = turns.length - 1
143
+ }
144
+ return { turns, trailingTurnIndex }
145
+ }
146
+
147
+ function sameItem<T>(a: TranscriptTurnItem<T>, b: TranscriptTurnItem<T>): boolean {
148
+ if (a.kind === 'single') return b.kind === 'single' && a.row === b.row && a.index === b.index
149
+ if (b.kind !== 'group' || a.startIndex !== b.startIndex || a.rows.length !== b.rows.length)
150
+ return false
151
+ return a.rows.every((row, index) => row === b.rows[index])
152
+ }
153
+
154
+ function sameDisplayItem<T>(a: TranscriptDisplayItem<T>, b: TranscriptDisplayItem<T>): boolean {
155
+ if (a.kind === 'turn') {
156
+ return (
157
+ b.kind === 'turn' &&
158
+ a.complete === b.complete &&
159
+ !!a.interim === !!b.interim &&
160
+ a.items.length === b.items.length &&
161
+ a.items.every((item, index) => sameItem(item, b.items[index]!))
162
+ )
163
+ }
164
+ return b.kind !== 'turn' && sameItem(a, b)
165
+ }
166
+
167
+ /** One previous immutable input/result pair per caller; no global or growing transcript cache. */
168
+ export function createTranscriptGrouper<T>(): (
169
+ rows: readonly TranscriptRow<T>[]
170
+ ) => GroupedTranscript<T> {
171
+ let previousRows: readonly TranscriptRow<T>[] | undefined
172
+ let previous: GroupedTranscript<T> | undefined
173
+ return (rows) => {
174
+ if (previous && rows === previousRows) return previous
175
+ const fresh = groupTranscriptRows(rows)
176
+ const turns = [...fresh.turns]
177
+ let allReused =
178
+ previous?.turns.length === turns.length &&
179
+ previous.trailingTurnIndex === fresh.trailingTurnIndex
180
+ if (previous) {
181
+ for (let index = 0; index < turns.length; index++) {
182
+ const candidate = previous.turns[index]
183
+ if (candidate && sameDisplayItem(turns[index]!, candidate)) turns[index] = candidate
184
+ else allReused = false
185
+ }
186
+ }
187
+ previousRows = rows
188
+ if (previous && allReused) return previous
189
+ previous = { turns, trailingTurnIndex: fresh.trailingTurnIndex }
190
+ return previous
191
+ }
192
+ }
193
+
194
+ /** Shallow-copies the display list and changes only its trailing turn. The host supplies running authority. */
195
+ export function applyTranscriptRunningState<T>(
196
+ grouped: GroupedTranscript<T>,
197
+ running: boolean
198
+ ): readonly TranscriptDisplayItem<T>[] {
199
+ if (grouped.trailingTurnIndex < 0 || !running) return grouped.turns
200
+ const turns = [...grouped.turns]
201
+ const trailing = turns[grouped.trailingTurnIndex]
202
+ if (trailing?.kind === 'turn') turns[grouped.trailingTurnIndex] = { ...trailing, complete: false }
203
+ return turns
204
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adea-ai/ui",
3
- "version": "0.67.1",
3
+ "version": "0.68.0",
4
4
  "description": "The Adea design system: Kobalte-backed Solid components, semantic OKLCH tokens, and the app-shell layout primitives shared by Adea and Cortana.",
5
5
  "keywords": [
6
6
  "adea",
@@ -76,6 +76,12 @@
76
76
  "solid": "./src/components/conversation/paste-tokens.ts",
77
77
  "development": "./src/components/conversation/paste-tokens.ts",
78
78
  "import": "./dist/components/conversation/paste-tokens.js"
79
+ },
80
+ "./components/conversation/transcript-composition": {
81
+ "types": "./dist/components/conversation/transcript-composition.d.ts",
82
+ "solid": "./src/components/conversation/transcript-composition.tsx",
83
+ "development": "./src/components/conversation/transcript-composition.tsx",
84
+ "import": "./dist/components/conversation/transcript-composition.js"
79
85
  }
80
86
  },
81
87
  "scripts": {
@@ -93,6 +99,7 @@
93
99
  "check:packed-layout": "node scripts/check-packed-layout.mjs",
94
100
  "check:packed-consumer": "bun scripts/check-packed-consumer.ts",
95
101
  "check:packed-conversation": "bun scripts/check-packed-conversation.ts",
102
+ "check:packed-transcript": "bun scripts/check-packed-transcript.ts",
96
103
  "check:packed-layout-renderer": "bun scripts/check-packed-layout-renderer.ts",
97
104
  "check:packed-appearance": "bun scripts/check-packed-appearance.ts",
98
105
  "check:packed-paste-model": "node scripts/check-packed-paste-model.mjs"
package/registry.json CHANGED
@@ -1890,6 +1890,21 @@
1890
1890
  "path": "src/components/conversation/thread-panel.tsx",
1891
1891
  "type": "registry:ui",
1892
1892
  "target": "components/conversation/thread-panel.tsx"
1893
+ },
1894
+ {
1895
+ "path": "src/components/conversation/transcript-composition.tsx",
1896
+ "type": "registry:ui",
1897
+ "target": "components/conversation/transcript-composition.tsx"
1898
+ },
1899
+ {
1900
+ "path": "src/components/conversation/transcript-folding.ts",
1901
+ "type": "registry:ui",
1902
+ "target": "components/conversation/transcript-folding.ts"
1903
+ },
1904
+ {
1905
+ "path": "src/components/conversation/transcript-grouping.ts",
1906
+ "type": "registry:ui",
1907
+ "target": "components/conversation/transcript-grouping.ts"
1893
1908
  }
1894
1909
  ]
1895
1910
  },
@@ -23,6 +23,23 @@ export {
23
23
  MessageRow,
24
24
  type MessageRowProps,
25
25
  } from './message-row'
26
+ export {
27
+ TranscriptComposition,
28
+ transcriptDisclosureKey,
29
+ type TranscriptCompositionProps,
30
+ type TranscriptCompositionFold,
31
+ type TranscriptCompositionRowContext,
32
+ type TranscriptCompositionRendererProps,
33
+ type TranscriptDisplayKind,
34
+ type GroupedTranscript,
35
+ type TranscriptDisplayItem,
36
+ type TranscriptFoldState,
37
+ type TranscriptFoldMode,
38
+ type TranscriptFoldPlan,
39
+ type TranscriptMounting,
40
+ type TranscriptRow,
41
+ type TranscriptTurnItem,
42
+ } from './transcript-composition'
26
43
  export {
27
44
  AttachmentCard,
28
45
  ThreadPanel,