@sparkelf/dsh-plus 0.2.8-alpha.50 → 0.2.9-alpha.51

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/package.json CHANGED
@@ -630,6 +630,25 @@
630
630
  "republish": false
631
631
  }
632
632
  },
633
+ {
634
+ "dsh": ">=0.2.2-alpha.2",
635
+ "file": "./patches/composer-structured-mentions.patch",
636
+ "id": "composer-structured-mentions",
637
+ "retireWhen": "官方 composer 原生支持结构化 @ mentions(SessionPromptRequest.mentions)后退役",
638
+ "target": {
639
+ "kind": "dsh-source",
640
+ "packages": [
641
+ "@deepseek-ai/dsh-api-session-controller",
642
+ "@deepseek-ai/dsh-client-ui-conversation",
643
+ "@deepseek-ai/dsh-client-ui-primitives"
644
+ ],
645
+ "paths": [
646
+ "packages/api/session-controller/",
647
+ "packages/client/ui-conversation/",
648
+ "packages/client/ui-primitives/"
649
+ ]
650
+ }
651
+ },
633
652
  {
634
653
  "dsh": ">=0.2.2-alpha.2",
635
654
  "file": "./patches/session-controller-image-downgrade-and-tool-visibility.patch",
@@ -719,7 +738,7 @@
719
738
  "@sparkelf/dsh-dataops-account": "0.2.0",
720
739
  "@sparkelf/dsh-dataops-managed": "0.3.39",
721
740
  "@sparkelf/dsh-genui": "0.15.0-sparkelf.3",
722
- "@sparkelf/dsh-group-chat": "0.5.3",
741
+ "@sparkelf/dsh-group-chat": "0.5.4",
723
742
  "@sparkelf/dsh-kb-citation": "0.1.3",
724
743
  "@sparkelf/dsh-knowledge-base": "0.1.32",
725
744
  "@sparkelf/dsh-mineru": "0.1.4",
@@ -790,5 +809,5 @@
790
809
  },
791
810
  "type": "module",
792
811
  "types": "lib/types/index.d.ts",
793
- "version": "0.2.8-alpha.50"
812
+ "version": "0.2.9-alpha.51"
794
813
  }
@@ -0,0 +1,368 @@
1
+ diff --git a/packages/api/session-controller/src/client/contract/session.ts b/packages/api/session-controller/src/client/contract/session.ts
2
+ index 9233ac84cb..21ce2a2dad 100644
3
+ --- a/packages/api/session-controller/src/client/contract/session.ts
4
+ +++ b/packages/api/session-controller/src/client/contract/session.ts
5
+ @@ -12,7 +12,7 @@ import type { MessageId } from '@deepseek-ai/dsh-llm/brand'
6
+ import type { SessionId, SessionSeq } from '@deepseek-ai/dsh-session/types'
7
+ import type { RemoteResult } from '@deepseek-ai/dsh-typert-protocol'
8
+ import type { ObservableSnapshot } from '@deepseek-ai/dsh-client-store'
9
+ -import type { PromptContentPart, QueueAction, SessionRequestId } from '../../types.ts'
10
+ +import type { PromptContentPart, QueueAction, SessionMentionRef, SessionRequestId } from '../../types.ts'
11
+ import type { PendingSubmissionAttachment, SessionSnapshot } from './snapshot.ts'
12
+
13
+ /**
14
+ @@ -100,6 +100,7 @@ export interface ISession {
15
+ mode: 'queue' | 'steer',
16
+ signal?: AbortSignal,
17
+ requestId?: SessionRequestId,
18
+ + mentions?: readonly SessionMentionRef[],
19
+ ): Promise<RemoteResult<{ accepted: true }>>
20
+ /**
21
+ * Resolve one stored image using this Session's gateway permission scope.
22
+ diff --git a/packages/api/session-controller/src/client/index.ts b/packages/api/session-controller/src/client/index.ts
23
+ index b9600f36a6..d48cb92447 100644
24
+ --- a/packages/api/session-controller/src/client/index.ts
25
+ +++ b/packages/api/session-controller/src/client/index.ts
26
+ @@ -28,6 +28,7 @@ export { createScope, scopeOf } from './scope.ts'
27
+ export type { AgentContext, AgentScopeHandle } from './scope.ts'
28
+ export { SessionCreateError, SessionForkError } from './sessions/service.ts'
29
+ export type { SessionBinding, SessionListState, SessionSummary } from './sessions/service.ts'
30
+ +export type { SessionMentionRef } from '../types.ts'
31
+ export type {
32
+ SessionListPhase,
33
+ SessionListSnapshot,
34
+ diff --git a/packages/api/session-controller/src/client/sessions/session.ts b/packages/api/session-controller/src/client/sessions/session.ts
35
+ index 253da9c463..0d5d4bbf67 100644
36
+ --- a/packages/api/session-controller/src/client/sessions/session.ts
37
+ +++ b/packages/api/session-controller/src/client/sessions/session.ts
38
+ @@ -17,6 +17,7 @@ import type {
39
+ SessionAssistantStreamBaseline,
40
+ SessionProjectionBaseline,
41
+ SessionRequestId,
42
+ + SessionMentionRef,
43
+ } from '../../types.ts'
44
+ import type {
45
+ BeginSubmissionInput, PendingSubmissionRetirement, SessionFace, SubmissionHandle,
46
+ @@ -263,6 +264,7 @@ export class Session implements SessionFace {
47
+ mode: 'queue' | 'steer',
48
+ signal?: AbortSignal,
49
+ requestId?: SessionRequestId,
50
+ + mentions?: readonly SessionMentionRef[],
51
+ ): Promise<RemoteResult<{ accepted: true }>> {
52
+ this.promptError = null
53
+ this.lastAgentError = null
54
+ @@ -278,6 +280,7 @@ export class Session implements SessionFace {
55
+ mode,
56
+ content,
57
+ clientTimeZone,
58
+ + ...(mentions === undefined || mentions.length === 0 ? {} : { mentions }),
59
+ }, signal)
60
+ } else if (content.some(part => part.type === 'file')) {
61
+ result = {
62
+ diff --git a/packages/api/session-controller/src/index.ts b/packages/api/session-controller/src/index.ts
63
+ index 94d08c77e3..3d9bf30009 100644
64
+ --- a/packages/api/session-controller/src/index.ts
65
+ +++ b/packages/api/session-controller/src/index.ts
66
+ @@ -484,6 +484,9 @@ export class SessionController extends TypertRemoteService {
67
+ rpcId: request.requestId,
68
+ ...(clientTimeZone === undefined ? {} : { clientTimeZone }),
69
+ ...(principal === undefined ? {} : { principal }),
70
+ + // Structured mentions ride the durable source, not the model content: a host plugin that
71
+ + // routes on identity reads them here, and the model only sees the text.
72
+ + ...(request.mentions === undefined || request.mentions.length === 0 ? {} : { mentions: request.mentions }),
73
+ }
74
+ return this.commands.prompt(request, source)
75
+ }
76
+ diff --git a/packages/api/session-controller/src/types.ts b/packages/api/session-controller/src/types.ts
77
+ index 9e399d8f3b..46a4507c56 100644
78
+ --- a/packages/api/session-controller/src/types.ts
79
+ +++ b/packages/api/session-controller/src/types.ts
80
+ @@ -317,6 +317,23 @@ export interface SessionForkValue {
81
+ readonly sessionId: SessionId
82
+ }
83
+
84
+ +/**
85
+ + * One structured mention a client declared when composing a prompt.
86
+ + *
87
+ + * The composer's `@` menu renders a chip per source, and a source opts in by inserting with
88
+ + * `appearance: 'mention'`; the reference travels here as identity plus the label the user saw, so
89
+ + * a host plugin can route it without parsing the prompt text. Never part of the model input: the
90
+ + * text already names the item.
91
+ + */
92
+ +export interface SessionMentionRef {
93
+ + /** Trigger source that produced the chip (e.g. a roster source). */
94
+ + readonly sourceId: string
95
+ + /** Source-scoped identity of the picked item. */
96
+ + readonly itemId: string
97
+ + /** Display label the user picked, for diagnostics and dedupe. */
98
+ + readonly displayName: string
99
+ +}
100
+ +
101
+ /** Session prompt request. */
102
+ export interface SessionPromptRequest {
103
+ /** Client-minted identity persisted on the exact accepted user message. */
104
+ @@ -325,6 +342,8 @@ export interface SessionPromptRequest {
105
+ readonly mode: 'queue' | 'steer'
106
+ /** At least one non-whitespace text part or attachment. */
107
+ readonly content: readonly PromptContentPart[]
108
+ + /** Structured mentions the composer declared, in document order. Absent when it carried none. */
109
+ + readonly mentions?: readonly SessionMentionRef[]
110
+ readonly clientTimeZone?: string
111
+ }
112
+
113
+ @@ -394,7 +413,13 @@ declare module '@deepseek-ai/dsh-llm' {
114
+ * caller that submitted the prompt. `principal` is written only for a
115
+ * caller other than the owner, so an absent `principal` means the owner.
116
+ */
117
+ - 'user-rpc': { kind: 'user'; rpcId: SessionRequestId; clientTimeZone?: string; principal?: Principal }
118
+ + 'user-rpc': {
119
+ + kind: 'user'
120
+ + rpcId: SessionRequestId
121
+ + clientTimeZone?: string
122
+ + principal?: Principal
123
+ + mentions?: readonly SessionMentionRef[]
124
+ + }
125
+ }
126
+ }
127
+
128
+ diff --git a/packages/client/ui-conversation/src/client/contract/draft-editor.ts b/packages/client/ui-conversation/src/client/contract/draft-editor.ts
129
+ index 0aee9f6be2..069ad977dd 100644
130
+ --- a/packages/client/ui-conversation/src/client/contract/draft-editor.ts
131
+ +++ b/packages/client/ui-conversation/src/client/contract/draft-editor.ts
132
+ @@ -15,7 +15,12 @@ export interface ReferenceInsert {
133
+ readonly source: string
134
+ readonly ref: string
135
+ readonly label: string
136
+ - readonly appearance?: 'session' | 'file' | 'folder' | 'resource'
137
+ + /**
138
+ + * Row glyph, and the submit-time declaration hook: `'mention'` marks a reference a host plugin
139
+ + * must receive as structured identity (`source`/`ref`) rather than re-parse out of the text.
140
+ + * Every other value is display-only.
141
+ + */
142
+ + readonly appearance?: 'session' | 'file' | 'folder' | 'resource' | 'mention'
143
+ readonly clipboardText: string
144
+ }
145
+
146
+ diff --git a/packages/client/ui-conversation/src/client/input/facade.ts b/packages/client/ui-conversation/src/client/input/facade.ts
147
+ index 6306216b1c..d8e2233001 100644
148
+ --- a/packages/client/ui-conversation/src/client/input/facade.ts
149
+ +++ b/packages/client/ui-conversation/src/client/input/facade.ts
150
+ @@ -20,8 +20,10 @@ import type {
151
+ SessionInput, SubmitAttempt, SubmitAttachment, SubmitOutcome,
152
+ } from '../contract/input.ts'
153
+ import type {
154
+ - ArbitrateKey, ArbitrateOutcome, ComposerKeyboard, DraftInput, DraftSnapshot, ReferenceInsert, TokenSpan,
155
+ + ArbitrateKey, ArbitrateOutcome, ComposerKeyboard, DraftInput, DraftSnapshot, Occurrence,
156
+ + ReferenceInsert, TokenSpan,
157
+ } from '../contract/draft-editor.ts'
158
+ +import type { SessionMentionRef } from '@deepseek-ai/dsh-api-session-controller/client'
159
+ import type { InputSubmitMode, MessageSubmission, MessageSubmissionState } from '../contract/composer-submission.ts'
160
+ import { serializeDraftPrompt } from './prompt.ts'
161
+ import { SubmitMachine } from './machine.ts'
162
+ @@ -69,6 +71,7 @@ export interface SessionInputDeps {
163
+ mode: InputSubmitMode,
164
+ signal: AbortSignal,
165
+ accept: () => void,
166
+ + mentions?: readonly SessionMentionRef[],
167
+ ): Promise<SubmitOutcome>
168
+ /** Live Session and composer-block policy for transcript insertion. */
169
+ quoteInsertionAllowed?: () => boolean
170
+ @@ -129,6 +132,29 @@ const EMPTY_LEXICON: ReadonlyMap<'/' | '@', readonly string[]> = new Map()
171
+ * setDraft/submit + the published InputState store, over a shell-owned
172
+ * Lexical editor.
173
+ */
174
+ +/**
175
+ + * Structured mentions declared by one draft, in document order.
176
+ + *
177
+ + * Only `appearance: 'mention'` chips qualify: a source opts in when it inserts through
178
+ + * `PickOutcome.insert`, and the host plugin that owns the roster reads the ids instead of parsing
179
+ + * `@name` out of the text (which would misread a code sample and let any message smuggle itself
180
+ + * into a routing decision). The same item picked twice is one mention.
181
+ + * @param occurrences - chip occurrences projected from the editor.
182
+ + * @returns `{sourceId, itemId, displayName}` records, or undefined when the draft declared none.
183
+ + */
184
+ +export const collectMentions = (occurrences: readonly Occurrence[]): readonly SessionMentionRef[] | undefined => {
185
+ + const seen = new Set<string>()
186
+ + const mentions: SessionMentionRef[] = []
187
+ + for (const occurrence of occurrences) {
188
+ + if (occurrence.appearance !== 'mention') continue
189
+ + const key = occurrence.source + '\u0000' + occurrence.ref
190
+ + if (seen.has(key)) continue
191
+ + seen.add(key)
192
+ + mentions.push({ sourceId: occurrence.source, itemId: occurrence.ref, displayName: occurrence.label })
193
+ + }
194
+ + return mentions.length === 0 ? undefined : mentions
195
+ +}
196
+ +
197
+ export class SessionInputShell implements SessionInput {
198
+ /** Published editor projection + submit-plane state + queue overlay (the InputZone currency source). */
199
+ readonly state: SnapshotStore<InputState>
200
+ @@ -726,7 +752,10 @@ export class SessionInputShell implements SessionInput {
201
+ })
202
+ const send = (text: string): void => {
203
+ if (this.dead(attempt)) return
204
+ - this.settleSink(attempt, this.deps.defaultSink(text, attachmentIds, mode, attempt.signal, () => { this.acceptSink(attempt) }))
205
+ + const mentions = collectMentions(attempt.occurrences)
206
+ + this.settleSink(attempt, mentions === undefined
207
+ + ? this.deps.defaultSink(text, attachmentIds, mode, attempt.signal, () => { this.acceptSink(attempt) })
208
+ + : this.deps.defaultSink(text, attachmentIds, mode, attempt.signal, () => { this.acceptSink(attempt) }, mentions))
209
+ }
210
+ if (!(prompt instanceof Promise)) { send(prompt); return }
211
+ void prompt.then(send, (error: unknown) => { this.failSink(attempt, error) })
212
+ diff --git a/packages/client/ui-conversation/src/client/input/hub.ts b/packages/client/ui-conversation/src/client/input/hub.ts
213
+ index 02897a18c6..5f1a3228a4 100644
214
+ --- a/packages/client/ui-conversation/src/client/input/hub.ts
215
+ +++ b/packages/client/ui-conversation/src/client/input/hub.ts
216
+ @@ -12,6 +12,7 @@ import type {
217
+ ISessions, SessionBinding, SessionFace,
218
+ } from '@deepseek-ai/dsh-api-session-controller/client'
219
+ import type { SessionId } from '@deepseek-ai/dsh-session/types'
220
+ +import type { SessionMentionRef } from '@deepseek-ai/dsh-api-session-controller/client'
221
+ import type { TranslateNS } from '@deepseek-ai/dsh-client-locale/client'
222
+ import type { InboxState } from '@deepseek-ai/dsh-agent/types'
223
+ import type { ModelSelectionProjection } from '@deepseek-ai/dsh-agent/types'
224
+ @@ -49,6 +50,7 @@ interface ConversationAttachmentFace {
225
+ mode: InputSubmitMode,
226
+ signal?: AbortSignal,
227
+ accept?: () => void,
228
+ + mentions?: readonly SessionMentionRef[],
229
+ ): Promise<SubmitOutcome>
230
+ serializeDraftAttachments(attachmentIds: readonly DraftAttachmentId[]): Promise<DraftAttachmentSerializationResult>
231
+ releaseDraftAttachment(id: DraftAttachmentId): void
232
+ @@ -125,7 +127,7 @@ export class InputHub implements SessionInputResolver {
233
+ inputTriggers: () => this.controller(actx),
234
+ popup: () => this.popup(actx),
235
+ inbox: session.projections.faceOf('inbox') as ObservableSnapshot<InboxState | undefined>,
236
+ - defaultSink: (text, attachmentIds, mode, signal, accept) => this.sink(session, text, attachmentIds, mode, signal, accept),
237
+ + defaultSink: (text, attachmentIds, mode, signal, accept, mentions) => this.sink(session, text, attachmentIds, mode, signal, accept, mentions),
238
+ quoteRemoveLabel: () => this.t('quote.remove'),
239
+ quoteInsertionAllowed: () => {
240
+ const state = session.getSnapshot()
241
+ @@ -250,9 +252,13 @@ export class InputHub implements SessionInputResolver {
242
+ mode: InputSubmitMode,
243
+ signal: AbortSignal,
244
+ accept: () => void,
245
+ + mentions?: readonly SessionMentionRef[],
246
+ ): Promise<SubmitOutcome> {
247
+ if (text === '' && attachmentIds.length === 0) return Promise.resolve({ kind: 'success' })
248
+ - return this.conversation().sendSession(session, text, attachmentIds, mode, signal, accept)
249
+ + // A draft that declared mentions takes one extra argument; the ordinary send keeps its shape.
250
+ + return mentions === undefined || mentions.length === 0
251
+ + ? this.conversation().sendSession(session, text, attachmentIds, mode, signal, accept)
252
+ + : this.conversation().sendSession(session, text, attachmentIds, mode, signal, accept, mentions)
253
+ }
254
+
255
+ /**
256
+ diff --git a/packages/client/ui-conversation/src/client/service.ts b/packages/client/ui-conversation/src/client/service.ts
257
+ index af19eb7721..4ae2286dcd 100644
258
+ --- a/packages/client/ui-conversation/src/client/service.ts
259
+ +++ b/packages/client/ui-conversation/src/client/service.ts
260
+ @@ -9,6 +9,7 @@
261
+ */
262
+ import { Service } from '@deepseek-ai/cordis'
263
+ import type { Context } from '@deepseek-ai/cordis'
264
+ +import type { SessionMentionRef } from '@deepseek-ai/dsh-api-session-controller/client'
265
+ import { randomUUID } from '@deepseek-ai/dsh-util-crypto'
266
+ // Type-only imports: a plugin-to-plugin value import is a bundle purity
267
+ // error, so scope resolution goes through the sessions service (scopeOf
268
+ @@ -238,6 +239,7 @@ export class ConversationController extends Service implements IConversation {
269
+ mode: InputSubmitMode,
270
+ signal?: AbortSignal,
271
+ accept?: () => void,
272
+ + mentions?: readonly SessionMentionRef[],
273
+ ): Promise<SubmitOutcome> {
274
+ const attachments = this.resolveDraftAttachments(attachmentIds)
275
+ if (attachments.length !== attachmentIds.length) {
276
+ @@ -306,7 +308,12 @@ export class ConversationController extends Service implements IConversation {
277
+ }
278
+ // An Inbox row can show the acceptance before the receipt; a receipt that fails afterwards changes
279
+ // nothing here because the Host already holds the message.
280
+ - const result = await Promise.race([session.prompt(content, mode, signal, submission.requestId), acceptance.promise])
281
+ + // Only a draft that declared mentions takes the extra argument, so the ordinary send keeps the
282
+ + // four-argument prompt every caller and test double already knows.
283
+ + const prompting = mentions === undefined || mentions.length === 0
284
+ + ? session.prompt(content, mode, signal, submission.requestId)
285
+ + : session.prompt(content, mode, signal, submission.requestId, mentions)
286
+ + const result = await Promise.race([prompting, acceptance.promise])
287
+ if (result !== undefined && !result.ok) return { kind: 'error' }
288
+ ownership.accepted = true
289
+ // An accepted prompt whose echo already retired unobserved, as when its queue entry was removed.
290
+ diff --git a/packages/client/ui-conversation/tests/mentions.client.spec.ts b/packages/client/ui-conversation/tests/mentions.client.spec.ts
291
+ new file mode 100644
292
+ index 0000000000..7439cbfff0
293
+ --- /dev/null
294
+ +++ b/packages/client/ui-conversation/tests/mentions.client.spec.ts
295
+ @@ -0,0 +1,45 @@
296
+ +import { describe, expect, it } from 'vitest'
297
+ +import type { Occurrence } from '../src/client/contract/draft-editor.ts'
298
+ +import { collectMentions } from '../src/client/input/facade.ts'
299
+ +
300
+ +/** One projected chip occurrence; only the fields the collector reads are interesting. */
301
+ +const occurrence = (patch: Partial<Occurrence> & Pick<Occurrence, 'source' | 'ref'>): Occurrence => ({
302
+ + occurrenceId: 1,
303
+ + offset: 0,
304
+ + length: 4,
305
+ + label: 'label',
306
+ + clipboardText: '@label',
307
+ + ...patch,
308
+ +})
309
+ +
310
+ +describe('collecting declared mentions', () => {
311
+ + it('takes mention chips only, in document order', () => {
312
+ + const mentions = collectMentions([
313
+ + occurrence({ source: 'reference', ref: 'src/a.ts', appearance: 'file', label: 'a.ts' }),
314
+ + occurrence({ source: 'roster', ref: 'u-1', appearance: 'mention', label: '张三' }),
315
+ + occurrence({ source: 'roster', ref: 'u-2', appearance: 'mention', label: '李四' }),
316
+ + ])
317
+ +
318
+ + // A file chip is a reference the model reads, not an identity a host plugin routes on.
319
+ + expect(mentions).toEqual([
320
+ + { sourceId: 'roster', itemId: 'u-1', displayName: '张三' },
321
+ + { sourceId: 'roster', itemId: 'u-2', displayName: '李四' },
322
+ + ])
323
+ + })
324
+ +
325
+ + it('reports one mention when the same item is picked twice', () => {
326
+ + const mentions = collectMentions([
327
+ + occurrence({ source: 'roster', ref: 'u-1', appearance: 'mention', label: '张三' }),
328
+ + occurrence({ source: 'roster', ref: 'u-1', appearance: 'mention', label: '张三' }),
329
+ + ])
330
+ +
331
+ + expect(mentions).toEqual([{ sourceId: 'roster', itemId: 'u-1', displayName: '张三' }])
332
+ + })
333
+ +
334
+ + it('answers undefined for a draft that declared none', () => {
335
+ + // Undefined, not an empty array: the sink keeps its original argument shape, so callers and
336
+ + // test doubles that never saw a mention stay unchanged.
337
+ + expect(collectMentions([])).toBeUndefined()
338
+ + expect(collectMentions([occurrence({ source: 'reference', ref: 'x', appearance: 'session' })])).toBeUndefined()
339
+ + })
340
+ +})
341
+
342
+ diff --git a/packages/client/ui-primitives/src/ReferenceIcon.tsx b/packages/client/ui-primitives/src/ReferenceIcon.tsx
343
+ index 198e6bbb1d..7fd75f96a2 100644
344
+ --- a/packages/client/ui-primitives/src/ReferenceIcon.tsx
345
+ +++ b/packages/client/ui-primitives/src/ReferenceIcon.tsx
346
+ @@ -1,12 +1,12 @@
347
+ import type { ReactNode } from 'react'
348
+ -import { ICON_MEDIUM_STROKE, ICON_REGULAR_STROKE } from './icons/index.tsx'
349
+ +import { ICON_MEDIUM_STROKE, ICON_REGULAR_STROKE, IconUserOutlineRegular } from './icons/index.tsx'
350
+ import type { IconProps } from './icons/props.ts'
351
+ import {
352
+ BrowseOutlineArtwork, ChatLinesOutlineArtwork, FolderCloseArtwork,
353
+ } from './icons/shared-artwork.tsx'
354
+
355
+ /** Reference domains with distinct composer and transcript glyphs. */
356
+ -export type ReferenceIconKind = 'session' | 'file' | 'folder' | 'resource'
357
+ +export type ReferenceIconKind = 'session' | 'file' | 'folder' | 'resource' | 'mention'
358
+
359
+ /** Props shared by inline reference glyphs. */
360
+ export interface ReferenceIconProps extends IconProps {
361
+ @@ -25,6 +25,7 @@ interface WeightedReferenceIconProps extends ReferenceIconProps {
362
+ function ReferenceIconArtwork({ kind, size = 16, className, strokeWidth }: WeightedReferenceIconProps): ReactNode {
363
+ switch (kind) {
364
+ case 'session': return <ChatLinesOutlineArtwork size={size} className={className} strokeWidth={strokeWidth} />
365
+ + case 'mention': return <IconUserOutlineRegular size={size} className={className} />
366
+ case 'file': return <BrowseOutlineArtwork size={size} className={className} strokeWidth={strokeWidth} />
367
+ case 'folder': return <FolderCloseArtwork size={size} className={className} strokeWidth={strokeWidth} />
368
+ case 'resource': return (