@dxos/react-ui-assistant 0.11.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/LICENSE +105 -0
- package/dist/lib/index.mjs +839 -0
- package/dist/lib/index.mjs.map +1 -0
- package/dist/lib/testing.mjs +214 -0
- package/dist/lib/testing.mjs.map +1 -0
- package/dist/types/src/components/ChatThread/ChatThread.d.ts +52 -0
- package/dist/types/src/components/ChatThread/ChatThread.d.ts.map +1 -0
- package/dist/types/src/components/ChatThread/ChatThread.stories.d.ts +38 -0
- package/dist/types/src/components/ChatThread/ChatThread.stories.d.ts.map +1 -0
- package/dist/types/src/components/ChatThread/index.d.ts +2 -0
- package/dist/types/src/components/ChatThread/index.d.ts.map +1 -0
- package/dist/types/src/components/MessageChrome/MessageChrome.d.ts +28 -0
- package/dist/types/src/components/MessageChrome/MessageChrome.d.ts.map +1 -0
- package/dist/types/src/components/MessageChrome/index.d.ts +2 -0
- package/dist/types/src/components/MessageChrome/index.d.ts.map +1 -0
- package/dist/types/src/components/index.d.ts +4 -0
- package/dist/types/src/components/index.d.ts.map +1 -0
- package/dist/types/src/components/widgets/FallbackWidget.d.ts +7 -0
- package/dist/types/src/components/widgets/FallbackWidget.d.ts.map +1 -0
- package/dist/types/src/components/widgets/ReasoningWidget.d.ts +25 -0
- package/dist/types/src/components/widgets/ReasoningWidget.d.ts.map +1 -0
- package/dist/types/src/components/widgets/ReasoningWidget.stories.d.ts +18 -0
- package/dist/types/src/components/widgets/ReasoningWidget.stories.d.ts.map +1 -0
- package/dist/types/src/components/widgets/ReferenceWidget.d.ts +9 -0
- package/dist/types/src/components/widgets/ReferenceWidget.d.ts.map +1 -0
- package/dist/types/src/components/widgets/SelectWidget.d.ts +14 -0
- package/dist/types/src/components/widgets/SelectWidget.d.ts.map +1 -0
- package/dist/types/src/components/widgets/StatsWidget.d.ts +12 -0
- package/dist/types/src/components/widgets/StatsWidget.d.ts.map +1 -0
- package/dist/types/src/components/widgets/StatusWidget.d.ts +12 -0
- package/dist/types/src/components/widgets/StatusWidget.d.ts.map +1 -0
- package/dist/types/src/components/widgets/SuggestionWidget.d.ts +11 -0
- package/dist/types/src/components/widgets/SuggestionWidget.d.ts.map +1 -0
- package/dist/types/src/components/widgets/SummaryWidget.d.ts +4 -0
- package/dist/types/src/components/widgets/SummaryWidget.d.ts.map +1 -0
- package/dist/types/src/components/widgets/ToolWidget.d.ts +10 -0
- package/dist/types/src/components/widgets/ToolWidget.d.ts.map +1 -0
- package/dist/types/src/components/widgets/ToolWidget.stories.d.ts +31 -0
- package/dist/types/src/components/widgets/ToolWidget.stories.d.ts.map +1 -0
- package/dist/types/src/components/widgets/defaults.d.ts +11 -0
- package/dist/types/src/components/widgets/defaults.d.ts.map +1 -0
- package/dist/types/src/components/widgets/format-time.d.ts +2 -0
- package/dist/types/src/components/widgets/format-time.d.ts.map +1 -0
- package/dist/types/src/components/widgets/index.d.ts +11 -0
- package/dist/types/src/components/widgets/index.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +6 -0
- package/dist/types/src/index.d.ts.map +1 -0
- package/dist/types/src/registry.d.ts +11 -0
- package/dist/types/src/registry.d.ts.map +1 -0
- package/dist/types/src/renderer.d.ts +25 -0
- package/dist/types/src/renderer.d.ts.map +1 -0
- package/dist/types/src/testing/index.d.ts +2 -0
- package/dist/types/src/testing/index.d.ts.map +1 -0
- package/dist/types/src/testing/test-generator.d.ts +7 -0
- package/dist/types/src/testing/test-generator.d.ts.map +1 -0
- package/dist/types/src/testing/test-generator.test.d.ts +2 -0
- package/dist/types/src/testing/test-generator.test.d.ts.map +1 -0
- package/dist/types/src/translations.d.ts +19 -0
- package/dist/types/src/translations.d.ts.map +1 -0
- package/dist/types/src/types.d.ts +28 -0
- package/dist/types/src/types.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -0
- package/package.json +67 -0
- package/src/components/ChatThread/ChatThread.stories.tsx +419 -0
- package/src/components/ChatThread/ChatThread.tsx +188 -0
- package/src/components/ChatThread/index.ts +5 -0
- package/src/components/MessageChrome/MessageChrome.tsx +147 -0
- package/src/components/MessageChrome/index.ts +5 -0
- package/src/components/index.ts +7 -0
- package/src/components/widgets/FallbackWidget.tsx +26 -0
- package/src/components/widgets/ReasoningWidget.stories.tsx +68 -0
- package/src/components/widgets/ReasoningWidget.ts +139 -0
- package/src/components/widgets/ReferenceWidget.ts +28 -0
- package/src/components/widgets/SelectWidget.ts +39 -0
- package/src/components/widgets/StatsWidget.ts +31 -0
- package/src/components/widgets/StatusWidget.ts +53 -0
- package/src/components/widgets/SuggestionWidget.ts +50 -0
- package/src/components/widgets/SummaryWidget.tsx +27 -0
- package/src/components/widgets/ToolWidget.stories.tsx +55 -0
- package/src/components/widgets/ToolWidget.tsx +185 -0
- package/src/components/widgets/defaults.ts +14 -0
- package/src/components/widgets/format-time.ts +45 -0
- package/src/components/widgets/index.ts +14 -0
- package/src/index.ts +9 -0
- package/src/registry.tsx +144 -0
- package/src/renderer.ts +216 -0
- package/src/testing/index.ts +5 -0
- package/src/testing/test-generator.test.ts +75 -0
- package/src/testing/test-generator.ts +280 -0
- package/src/translations.ts +27 -0
- package/src/types.ts +32 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import * as Effect from 'effect/Effect';
|
|
6
|
+
import * as Layer from 'effect/Layer';
|
|
7
|
+
import { describe, test } from 'vitest';
|
|
8
|
+
|
|
9
|
+
import { Database, Entity, Feed, Obj } from '@dxos/echo';
|
|
10
|
+
import { EffectEx } from '@dxos/effect';
|
|
11
|
+
import { type Message } from '@dxos/types';
|
|
12
|
+
|
|
13
|
+
import { createMessageGenerator } from './test-generator';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* In-memory Database.Service that records appendToFeed calls and emits a change event
|
|
17
|
+
* whenever `appendToFeed` is called. Used to verify the streaming-message generator
|
|
18
|
+
* emits per-chunk updates.
|
|
19
|
+
*/
|
|
20
|
+
const makeRecordingDatabaseLayer = () => {
|
|
21
|
+
const items: Message.Message[] = [];
|
|
22
|
+
const subscribers = new Set<() => void>();
|
|
23
|
+
|
|
24
|
+
const dbService: Database.Database = {
|
|
25
|
+
get spaceId() {
|
|
26
|
+
return 'recording' as any;
|
|
27
|
+
},
|
|
28
|
+
add: (obj: any) => obj as any,
|
|
29
|
+
addType: async () => undefined as any,
|
|
30
|
+
remove: () => {},
|
|
31
|
+
appendToFeed: async (_feed: Feed.Feed, newItems: Entity.Unknown[]) => {
|
|
32
|
+
items.push(...(newItems as Message.Message[]));
|
|
33
|
+
for (const fn of subscribers) {
|
|
34
|
+
fn();
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
removeFeedItemsByIds: async () => {},
|
|
38
|
+
queryFeed: () => ({ subscribe: () => () => {}, results: [], run: async () => [] }) as any,
|
|
39
|
+
query: () => ({ subscribe: () => () => {}, results: [], run: async () => [] }) as any,
|
|
40
|
+
syncFeed: async () => {},
|
|
41
|
+
getFeedSyncState: async () => ({ blocksToPull: 0, blocksToPush: 0, totalBlocks: 0 }),
|
|
42
|
+
flush: async () => {},
|
|
43
|
+
makeRef: () => undefined as any,
|
|
44
|
+
deleteFromFeed: async () => {},
|
|
45
|
+
} as unknown as Database.Database;
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
items,
|
|
49
|
+
onAppend: (cb: () => void) => subscribers.add(cb),
|
|
50
|
+
layer: Layer.succeed(Database.Service, { db: dbService }),
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
describe('createMessageGenerator', () => {
|
|
55
|
+
test('streaming message publishes updates for chunk mutations', async ({ expect }) => {
|
|
56
|
+
const recording = makeRecordingDatabaseLayer();
|
|
57
|
+
let updates = 0;
|
|
58
|
+
recording.onAppend(() => updates++);
|
|
59
|
+
|
|
60
|
+
const feed = Obj.make(Feed.Feed, { name: 'recording' });
|
|
61
|
+
|
|
62
|
+
// The streaming step is the third entry (index 2) — earlier indices are the initial
|
|
63
|
+
// user prompt and an assistant message with an Organization link (which requires
|
|
64
|
+
// a real database; the recording layer stub is sufficient for this streaming test).
|
|
65
|
+
await EffectEx.runAndForwardErrors(
|
|
66
|
+
createMessageGenerator()[2]!.pipe(
|
|
67
|
+
Effect.provide(Layer.mergeAll(Feed.ContextFeedService.layer(feed), recording.layer)),
|
|
68
|
+
),
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
expect(recording.items).toHaveLength(1);
|
|
72
|
+
expect(updates).toBeGreaterThan(1);
|
|
73
|
+
expect(recording.items[0].blocks[0]).toMatchObject({ pending: false });
|
|
74
|
+
});
|
|
75
|
+
});
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import * as Effect from 'effect/Effect';
|
|
6
|
+
|
|
7
|
+
import { Database, Feed, Obj } from '@dxos/echo';
|
|
8
|
+
import { type Mutable } from '@dxos/echo/Obj';
|
|
9
|
+
import { random } from '@dxos/random';
|
|
10
|
+
import { renderObjectLink, textStream } from '@dxos/react-ui-markdown';
|
|
11
|
+
import { type Actor, type ContentBlock, Message, Organization } from '@dxos/types';
|
|
12
|
+
import { trim } from '@dxos/util';
|
|
13
|
+
|
|
14
|
+
export const createMessage = (role: Actor.Role, blocks: ContentBlock.Any[]): Message.Message => {
|
|
15
|
+
return Obj.make(Message.Message, {
|
|
16
|
+
created: new Date().toISOString(),
|
|
17
|
+
sender: { role },
|
|
18
|
+
blocks,
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export type MessageGenerator = Effect.Effect<void, never, Database.Service | Feed.ContextFeedService>;
|
|
23
|
+
|
|
24
|
+
export const createMessageGenerator = (): MessageGenerator[] => [
|
|
25
|
+
Effect.gen(function* () {
|
|
26
|
+
const { feed } = yield* Feed.ContextFeedService;
|
|
27
|
+
yield* Feed.append(feed, [
|
|
28
|
+
createMessage('user', [
|
|
29
|
+
{
|
|
30
|
+
_tag: 'text',
|
|
31
|
+
text: random.lorem.sentence(5),
|
|
32
|
+
},
|
|
33
|
+
]),
|
|
34
|
+
]);
|
|
35
|
+
}),
|
|
36
|
+
|
|
37
|
+
Effect.gen(function* () {
|
|
38
|
+
const { feed } = yield* Feed.ContextFeedService;
|
|
39
|
+
const { db } = yield* Database.Service;
|
|
40
|
+
const obj1 = db.add(
|
|
41
|
+
Obj.make(Organization.Organization, {
|
|
42
|
+
name: 'DXOS',
|
|
43
|
+
website: 'https://dxos.org',
|
|
44
|
+
description: 'DXOS is a decentralized network for collaborative applications.',
|
|
45
|
+
}),
|
|
46
|
+
);
|
|
47
|
+
// const obj2 = db.add(Obj.make(Person.Person, { fullName: 'Alice' }));
|
|
48
|
+
// const obj3 = db.add(Obj.make(Person.Person, { fullName: 'Bob' }));
|
|
49
|
+
// const obj4 = db.add(Obj.make(Person.Person, { fullName: 'Charlie' }));
|
|
50
|
+
yield* Feed.append(feed, [
|
|
51
|
+
createMessage('assistant', [
|
|
52
|
+
// Inline tag.
|
|
53
|
+
{
|
|
54
|
+
_tag: 'text',
|
|
55
|
+
text: [random.lorem.paragraph(), renderObjectLink(obj1), random.lorem.paragraph(), '\n'].join(' '),
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
// Inline cards.
|
|
59
|
+
// ...[obj1, obj2, obj3, obj4].map(
|
|
60
|
+
// (obj) =>
|
|
61
|
+
// ({
|
|
62
|
+
// _tag: 'text',
|
|
63
|
+
// text: renderObjectLink(obj, true) + '\n',
|
|
64
|
+
// }) satisfies ContentBlock.Text,
|
|
65
|
+
// ),
|
|
66
|
+
]),
|
|
67
|
+
]);
|
|
68
|
+
}),
|
|
69
|
+
|
|
70
|
+
// Streaming text block: appends a pending text block, then mutates `text` in chunks
|
|
71
|
+
// so the syncer renders progressive deltas through the feed (not via the controller).
|
|
72
|
+
Effect.gen(function* () {
|
|
73
|
+
const { feed } = yield* Feed.ContextFeedService;
|
|
74
|
+
const { db } = yield* Database.Service;
|
|
75
|
+
const message = createMessage('assistant', [{ _tag: 'text', text: '', pending: true }]);
|
|
76
|
+
yield* Feed.append(feed, [message]);
|
|
77
|
+
|
|
78
|
+
const fullText = [
|
|
79
|
+
'Streaming a response **word by word** through the feed:',
|
|
80
|
+
random.lorem.paragraph(),
|
|
81
|
+
random.lorem.paragraph(),
|
|
82
|
+
].join('\n\n');
|
|
83
|
+
|
|
84
|
+
yield* Effect.promise(async () => {
|
|
85
|
+
for await (const chunk of textStream(fullText, { wordsPerChunk: 2, chunkDelay: 60 })) {
|
|
86
|
+
Obj.update(message, (message) => {
|
|
87
|
+
const block = message.blocks[0] as Mutable<ContentBlock.Text>;
|
|
88
|
+
block.text += chunk;
|
|
89
|
+
});
|
|
90
|
+
// Feed queries only react to feed-level updates, not in-place object mutations.
|
|
91
|
+
await db.appendToFeed(feed, []);
|
|
92
|
+
}
|
|
93
|
+
Obj.update(message, (message) => {
|
|
94
|
+
const block = message.blocks[0] as Mutable<ContentBlock.Text>;
|
|
95
|
+
block.pending = false;
|
|
96
|
+
});
|
|
97
|
+
await db.appendToFeed(feed, []);
|
|
98
|
+
});
|
|
99
|
+
}),
|
|
100
|
+
|
|
101
|
+
Effect.gen(function* () {
|
|
102
|
+
const { feed } = yield* Feed.ContextFeedService;
|
|
103
|
+
yield* Feed.append(feed, [
|
|
104
|
+
createMessage('assistant', [
|
|
105
|
+
{
|
|
106
|
+
_tag: 'text',
|
|
107
|
+
text:
|
|
108
|
+
trim`
|
|
109
|
+
## Markdown
|
|
110
|
+
Here is a [link](https://dxos.org)
|
|
111
|
+
|
|
112
|
+
And some **bold** text.
|
|
113
|
+
|
|
114
|
+
And some JSON
|
|
115
|
+
\`\`\`json
|
|
116
|
+
{
|
|
117
|
+
"key": "value"
|
|
118
|
+
}
|
|
119
|
+
\`\`\`
|
|
120
|
+
|
|
121
|
+
And some code
|
|
122
|
+
\`\`\`js
|
|
123
|
+
const x = 1;
|
|
124
|
+
\`\`\`
|
|
125
|
+
` + '\n',
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
_tag: 'text',
|
|
129
|
+
disposition: 'cot',
|
|
130
|
+
text:
|
|
131
|
+
[
|
|
132
|
+
random.lorem.paragraph(),
|
|
133
|
+
'',
|
|
134
|
+
...Array.from({
|
|
135
|
+
length: random.number.int({ min: 3, max: 5 }),
|
|
136
|
+
}).map((_, idx) => `${idx + 1}. ${random.lorem.paragraph()}`),
|
|
137
|
+
].join('\n') + '\n',
|
|
138
|
+
},
|
|
139
|
+
]),
|
|
140
|
+
]);
|
|
141
|
+
}),
|
|
142
|
+
|
|
143
|
+
Effect.gen(function* () {
|
|
144
|
+
const { feed } = yield* Feed.ContextFeedService;
|
|
145
|
+
yield* Feed.append(feed, [
|
|
146
|
+
createMessage('assistant', [
|
|
147
|
+
{
|
|
148
|
+
_tag: 'text',
|
|
149
|
+
text: 'How can I help?',
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
_tag: 'suggestion',
|
|
153
|
+
text: 'List tools',
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
_tag: 'suggestion',
|
|
157
|
+
text: 'Show info',
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
_tag: 'suggestion',
|
|
161
|
+
text: random.lorem.paragraph(),
|
|
162
|
+
},
|
|
163
|
+
]),
|
|
164
|
+
createMessage('assistant', [
|
|
165
|
+
{
|
|
166
|
+
_tag: 'text',
|
|
167
|
+
text: 'Select an option:',
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
_tag: 'select',
|
|
171
|
+
options: ['Option 1', 'Option 2', 'Option 3'],
|
|
172
|
+
},
|
|
173
|
+
]),
|
|
174
|
+
]);
|
|
175
|
+
}),
|
|
176
|
+
|
|
177
|
+
Effect.gen(function* () {
|
|
178
|
+
const { feed } = yield* Feed.ContextFeedService;
|
|
179
|
+
yield* Feed.append(feed, [
|
|
180
|
+
createMessage('assistant', [
|
|
181
|
+
{
|
|
182
|
+
_tag: 'toolkit',
|
|
183
|
+
},
|
|
184
|
+
]),
|
|
185
|
+
]);
|
|
186
|
+
}),
|
|
187
|
+
|
|
188
|
+
Effect.gen(function* () {
|
|
189
|
+
const { feed } = yield* Feed.ContextFeedService;
|
|
190
|
+
yield* Feed.append(feed, [
|
|
191
|
+
createMessage('user', [
|
|
192
|
+
{
|
|
193
|
+
_tag: 'text',
|
|
194
|
+
text: random.lorem.sentence(5),
|
|
195
|
+
},
|
|
196
|
+
]),
|
|
197
|
+
]);
|
|
198
|
+
}),
|
|
199
|
+
|
|
200
|
+
Effect.gen(function* () {
|
|
201
|
+
const { feed } = yield* Feed.ContextFeedService;
|
|
202
|
+
yield* Feed.append(feed, [
|
|
203
|
+
createMessage('assistant', [
|
|
204
|
+
{
|
|
205
|
+
_tag: 'text',
|
|
206
|
+
text: random.lorem.paragraph() + '\n',
|
|
207
|
+
},
|
|
208
|
+
]),
|
|
209
|
+
createMessage('assistant', [
|
|
210
|
+
{
|
|
211
|
+
_tag: 'toolCall',
|
|
212
|
+
toolCallId: '1234',
|
|
213
|
+
name: 'search',
|
|
214
|
+
input: JSON.stringify({}),
|
|
215
|
+
providerExecuted: false,
|
|
216
|
+
},
|
|
217
|
+
]),
|
|
218
|
+
createMessage('user', [
|
|
219
|
+
{
|
|
220
|
+
_tag: 'toolResult',
|
|
221
|
+
toolCallId: '1234',
|
|
222
|
+
name: 'search',
|
|
223
|
+
result: 'This is a tool result.',
|
|
224
|
+
providerExecuted: false,
|
|
225
|
+
},
|
|
226
|
+
]),
|
|
227
|
+
]);
|
|
228
|
+
}),
|
|
229
|
+
|
|
230
|
+
Effect.gen(function* () {
|
|
231
|
+
const { feed } = yield* Feed.ContextFeedService;
|
|
232
|
+
yield* Feed.append(feed, [
|
|
233
|
+
createMessage('assistant', [
|
|
234
|
+
{
|
|
235
|
+
_tag: 'text',
|
|
236
|
+
text: random.lorem.paragraph() + '\n',
|
|
237
|
+
},
|
|
238
|
+
]),
|
|
239
|
+
createMessage('assistant', [
|
|
240
|
+
{
|
|
241
|
+
_tag: 'toolCall',
|
|
242
|
+
toolCallId: '4567',
|
|
243
|
+
name: 'create',
|
|
244
|
+
input: JSON.stringify({}),
|
|
245
|
+
providerExecuted: false,
|
|
246
|
+
},
|
|
247
|
+
]),
|
|
248
|
+
createMessage('user', [
|
|
249
|
+
{
|
|
250
|
+
_tag: 'toolResult',
|
|
251
|
+
toolCallId: '4567',
|
|
252
|
+
name: 'create',
|
|
253
|
+
result: 'This is a tool result.',
|
|
254
|
+
providerExecuted: false,
|
|
255
|
+
},
|
|
256
|
+
]),
|
|
257
|
+
createMessage('assistant', [
|
|
258
|
+
{
|
|
259
|
+
_tag: 'text',
|
|
260
|
+
text:
|
|
261
|
+
Array.from({ length: random.number.int({ min: 2, max: 3 }) })
|
|
262
|
+
.map(() => random.lorem.paragraph())
|
|
263
|
+
.join('\n\n') + '\n',
|
|
264
|
+
},
|
|
265
|
+
]),
|
|
266
|
+
]);
|
|
267
|
+
}),
|
|
268
|
+
|
|
269
|
+
Effect.gen(function* () {
|
|
270
|
+
const { feed } = yield* Feed.ContextFeedService;
|
|
271
|
+
yield* Feed.append(feed, [
|
|
272
|
+
createMessage('assistant', [
|
|
273
|
+
{
|
|
274
|
+
_tag: 'text',
|
|
275
|
+
text: random.lorem.paragraph(),
|
|
276
|
+
},
|
|
277
|
+
]),
|
|
278
|
+
]);
|
|
279
|
+
}),
|
|
280
|
+
];
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { type Resource } from '@dxos/react-ui';
|
|
6
|
+
|
|
7
|
+
export const translationKey = '@dxos/react-ui-assistant';
|
|
8
|
+
|
|
9
|
+
export const translations = [
|
|
10
|
+
{
|
|
11
|
+
'en-US': {
|
|
12
|
+
[translationKey]: {
|
|
13
|
+
'copy.label': 'Copy',
|
|
14
|
+
'rewind.label': 'Rewind to this prompt',
|
|
15
|
+
'summary.label': 'Summary',
|
|
16
|
+
'stats.label': 'Stats',
|
|
17
|
+
'tool-call.label': 'Calling',
|
|
18
|
+
'tool-result.label': 'Result',
|
|
19
|
+
'tool-error.label': 'Tool error',
|
|
20
|
+
'nav-first.label': 'First message',
|
|
21
|
+
'nav-previous.label': 'Previous message',
|
|
22
|
+
'nav-next.label': 'Next message',
|
|
23
|
+
'nav-last.label': 'Last message',
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
] as const satisfies Resource[];
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import * as Schema from 'effect/Schema';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Which projection of the thread the reader sees. A view is a filter over blocks, applied by the
|
|
9
|
+
* renderer — the model always carries everything.
|
|
10
|
+
*
|
|
11
|
+
* - `summary`: only conversational text (prompts and replies).
|
|
12
|
+
* - `normal`: everything except reasoning.
|
|
13
|
+
* - `thinking`: everything, reasoning included.
|
|
14
|
+
* - `debug`: every block, raw fallbacks visible.
|
|
15
|
+
*/
|
|
16
|
+
export const ChatView = Schema.Union([
|
|
17
|
+
Schema.Literal('normal').annotate({ title: 'Normal' }),
|
|
18
|
+
Schema.Literal('summary').annotate({ title: 'Summary' }),
|
|
19
|
+
Schema.Literal('thinking').annotate({ title: 'Thinking' }),
|
|
20
|
+
Schema.Literal('debug').annotate({ title: 'Debug' }),
|
|
21
|
+
]);
|
|
22
|
+
export type ChatView = Schema.Schema.Type<typeof ChatView>;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* What the thread reports outward. Deliberately the same shapes the assistant plugin's event bus
|
|
26
|
+
* speaks, so a host can pipe these straight through.
|
|
27
|
+
*/
|
|
28
|
+
export type ChatThreadEvent =
|
|
29
|
+
/** A suggestion or select option was chosen — the text is ready to submit. */
|
|
30
|
+
| { type: 'submit'; text: string }
|
|
31
|
+
/** Soft-fork the thread from the given message (the prompt toolbar's rewind). */
|
|
32
|
+
| { type: 'rewind'; id: string };
|