{block.attachment !== undefined
- ? renderFactorySlot('conversation.trajectory.images.view', {
+ ? renderSlot('conversation.trajectory.images', {
images: [{ attachment: block.attachment, label: name }],
align: 'start',
thumbnail: true,
@@ -1480,7 +1480,7 @@ function ToolOutputBlocks({
error,
errorDetail,
preview,
- renderFactorySlot,
+ renderSlot,
loadImage,
}: {
blocks: readonly TrajectorySourceBlock[]
@@ -1488,7 +1488,7 @@ function ToolOutputBlocks({
/** Failure name and code preserved beside image-only error content. */
errorDetail?: string | undefined
preview: boolean
- renderFactorySlot: PropsRenderFactories['renderFactorySlot']
+ renderSlot: PropsRenderSlots<'conversation.trajectory.images'>['renderSlot']
loadImage: MessageImageLoader
}) {
return (
@@ -1504,7 +1504,7 @@ function ToolOutputBlocks({
block.attachment !== undefined
? (
- {renderFactorySlot('conversation.trajectory.images.view', { images: [{ attachment: block.attachment }], align: 'start', loadImage })}
+ {renderSlot('conversation.trajectory.images', { images: [{ attachment: block.attachment }], align: 'start', loadImage })}
)
: block.content !== ''
@@ -1522,7 +1522,7 @@ function MarkdownRecordContent({
thinkingExpanded,
onThinkingExpandedChange,
onOpenCall,
- renderFactorySlot,
+ renderSlot,
loadImage,
t,
}: {
@@ -1532,7 +1532,7 @@ function MarkdownRecordContent({
thinkingExpanded: boolean
onThinkingExpandedChange: (expanded: boolean) => void
onOpenCall: (callId: string) => void
- renderFactorySlot: PropsRenderFactories['renderFactorySlot']
+ renderSlot: PropsRenderSlots<'conversation.trajectory.images'>['renderSlot']
loadImage: MessageImageLoader
t: TrajectoryTranslate
}) {
@@ -1603,7 +1603,7 @@ function MarkdownRecordContent({
@@ -1635,7 +1635,7 @@ function MarkdownRecordContent({
/>
)}
+ renderSlot={renderSlot} loadImage={loadImage} t={t} />
)
}
@@ -1704,7 +1704,7 @@ function RecordPayload({
record,
direction,
preview = false,
- renderFactorySlot,
+ renderSlot,
loadImage,
stringWrapping,
t,
@@ -1712,7 +1712,7 @@ function RecordPayload({
record: TableRecord
direction: 'input' | 'output'
preview?: boolean
- renderFactorySlot: PropsRenderFactories['renderFactorySlot']
+ renderSlot: PropsRenderSlots<'conversation.trajectory.images'>['renderSlot']
loadImage: MessageImageLoader
stringWrapping: JsonTreeProps['stringWrapping']
t: TrajectoryTranslate
@@ -1754,7 +1754,7 @@ function RecordPayload({
error={error}
errorDetail={error ? value : undefined}
preview={preview}
- renderFactorySlot={renderFactorySlot}
+ renderSlot={renderSlot}
loadImage={loadImage}
/>
)
@@ -2085,7 +2085,7 @@ function OverviewSection({
export function TrajectoryTable({
t,
stringWrapping,
- renderFactorySlot,
+ renderSlot,
loadImage,
requestNumbers: sessionRequestNumbers,
turns,
@@ -3310,7 +3310,7 @@ export function TrajectoryTable({
>
{ activateTab('rendered') }}>
{selected.cell.inputDetail && (
{ activateTab('input') }}>
-
+
)}
{selected.cell.outputDetail && (
{ activateTab('output') }}>
-
+
)}
{ activateTab('schema') }}>
@@ -3488,7 +3488,7 @@ export function TrajectoryTable({
{!promptSelected && selected !== undefined && activeTab === 'rendered' && (
+ ?
:
)}
{!promptSelected && selected !== undefined && activeTab === 'output' && (
selectedProgram === undefined
- ?
+ ?
:
)}
{!promptSelected && selected !== undefined && activeTab === 'schema' && (
diff --git a/packages/client/ui-trajectory/src/client/TrajectoryView.tsx b/packages/client/ui-trajectory/src/client/TrajectoryView.tsx
index 1fd6a571bf..e36386e819 100644
--- a/packages/client/ui-trajectory/src/client/TrajectoryView.tsx
+++ b/packages/client/ui-trajectory/src/client/TrajectoryView.tsx
@@ -5,7 +5,7 @@ import type {
AssistantBlock, AssistantMessageNode, ConvViewProps, MessageImageLoader,
ToolCallBlock,
} from '@deepseek-ai/dsh-client-ui-conversation/client'
-import type { InjectFace, PropsLocale, PropsRenderFactories } from '@deepseek-ai/dsh-client-ui-slots'
+import type { InjectFace, PropsLocale, PropsRenderSlots } from '@deepseek-ai/dsh-client-ui-slots'
import type { SnapshotStore } from '@deepseek-ai/dsh-client-store'
import type { JsonTreeProps } from '@deepseek-ai/dsh-client-ui-primitives'
import {
@@ -131,9 +131,9 @@ function addUsage(
export function TrajectoryView({
useSession, useTrajectory, useDuration, loadOlder, loadImage, setActualDuration,
- viewRequest, completeViewRequest, renderFactorySlot, t, jsonStringWrapping,
+ viewRequest, completeViewRequest, renderSlot, t, jsonStringWrapping,
}: ConvViewProps
- & PropsRenderFactories
+ & Pick, 'renderSlot'>
& InjectFace
& PropsLocale<'trajectory'>) {
const [collapsedTurns, setCollapsedTurns] = useState>(EMPTY_TURN_IDS)
@@ -550,7 +550,7 @@ export function TrajectoryView({
...jsonStringWrapping,
label: t('record.wrapLines'),
}}
- renderFactorySlot={renderFactorySlot}
+ renderSlot={renderSlot}
loadImage={loadImage}
requestNumbers={requestNumbers}
turns={timelineTurns}
diff --git a/packages/client/ui-trajectory/src/client/index.ts b/packages/client/ui-trajectory/src/client/index.ts
index 57327710bf..0b438d1aae 100644
--- a/packages/client/ui-trajectory/src/client/index.ts
+++ b/packages/client/ui-trajectory/src/client/index.ts
@@ -27,7 +27,6 @@ import {
import type { TrajectorySnapshot } from './trajectory-contract.ts'
import { registerTrajectoryToolDefinition } from './trajectory-tool-definition.ts'
import { TrajectoryView, type TrajectoryViewInjected } from './TrajectoryView.tsx'
-import { TrajectoryImagesView } from './TrajectoryImagesView.tsx'
export type { TrajectoryKey } from './locales.ts'
export type {
@@ -77,17 +76,13 @@ export function apply(ctx: Context): void {
hooks: ['trajectory'],
resolve: binding => ({ hooks: { trajectory: trajectorySource(binding) } }),
})
- ctx.slots.registerFactory({
- name: 'conversation.trajectory.images.view',
- scope: 'session',
- children: { 'conversation.trajectory.images': { kind: 'single', scope: 'session' } },
- }, TrajectoryImagesView)
ctx.slots.inject('conversation.view', () => ctx.slots.register({
name: 'conversation.view',
id: 'trajectory',
order: 10,
locale: NS,
label: () => t('view.trajectory'),
+ children: { 'conversation.trajectory.images': { kind: 'single', scope: 'session' } },
inject: (sessionId: SessionId): TrajectoryViewInjected => {
const session = ctx.sessions.binding(sessionId)?.session
if (session === undefined) {
diff --git a/packages/client/ui-trajectory/src/client/trajectory-contract.ts b/packages/client/ui-trajectory/src/client/trajectory-contract.ts
index cd3c3b23bf..c75c32d346 100644
--- a/packages/client/ui-trajectory/src/client/trajectory-contract.ts
+++ b/packages/client/ui-trajectory/src/client/trajectory-contract.ts
@@ -93,15 +93,6 @@ declare module '@deepseek-ai/dsh-client-ui-slots' {
useTrajectory: UseTrajectory
}
- interface SlotFactoryMap {
- /** Portable Trajectory image position retaining its independent Slot. */
- 'conversation.trajectory.images.view': {
- scope: 'session'
- props: MessageImagesOwnerProps
- children: { 'conversation.trajectory.images': { kind: 'single'; scope: 'session' } }
- }
- }
-
interface SlotMap {
/**
* Renderer for one group of durable record images in the Trajectory
diff --git a/packages/client/ui-trajectory/tests/code-inspector.client.spec.tsx b/packages/client/ui-trajectory/tests/code-inspector.client.spec.tsx
index 59ff0a2146..ab9bd12d41 100644
--- a/packages/client/ui-trajectory/tests/code-inspector.client.spec.tsx
+++ b/packages/client/ui-trajectory/tests/code-inspector.client.spec.tsx
@@ -26,7 +26,7 @@ function Harness({ cell = CELL, getDefault = () => false, setDefault = () => {}
}) {
return null} loadImage={async () => 'blob:unused'} t={t}
+ renderSlot={() => null} loadImage={async () => 'blob:unused'} t={t}
stringWrapping={{ label: 'Wrap lines', getDefault, setDefault }}
collapsedTurns={new Set()} onToggleTurn={() => {}}
collapsedAssistants={new Set()} onToggleAssistant={() => {}}
diff --git a/packages/client/ui-trajectory/tests/table.client.spec.tsx b/packages/client/ui-trajectory/tests/table.client.spec.tsx
index b354525665..188b96bb5f 100644
--- a/packages/client/ui-trajectory/tests/table.client.spec.tsx
+++ b/packages/client/ui-trajectory/tests/table.client.spec.tsx
@@ -8,15 +8,14 @@ import { useState, type ComponentProps, type ReactNode } from 'react'
import { SessionId } from '@deepseek-ai/dsh-session/types'
import { SlotTestRuntime } from '@deepseek-ai/dsh-client-test-runtime'
import type { MessageImageLoader, MessageImagesOwnerProps } from '@deepseek-ai/dsh-client-ui-conversation/client'
-import type { PropsRenderFactories, PropsRenderSlots } from '@deepseek-ai/dsh-client-ui-slots'
-import { TrajectoryImagesView } from '../src/client/TrajectoryImagesView.tsx'
+import type { PropsRenderSlots } from '@deepseek-ai/dsh-client-ui-slots'
import { TrajectoryTable as LocalizedTrajectoryTable } from '../src/client/TrajectoryTable.tsx'
import { deriveTrajectoryLayout, type TrajectoryTurnModel } from '../src/client/layout.ts'
import { trajectoryRecordId } from '../src/client/trajectory-record.ts'
import { t, tZh } from './locale.client.ts'
const loadImage: MessageImageLoader = async () => 'blob:trajectory'
-const renderNoFactories: PropsRenderFactories['renderFactorySlot'] = () => null
+const renderNoImages: PropsRenderSlots<'conversation.trajectory.images'>['renderSlot'] = () => null
const RecordImages = ({ images }: MessageImagesOwnerProps) => (
@@ -29,30 +28,26 @@ const RecordImages = ({ images }: MessageImagesOwnerProps) => (
)
-async function imageFactory() {
+async function imageSlotFixture() {
const runtime = await SlotTestRuntime.create()
onTestFinished(() => runtime.dispose())
- runtime.slots.registerFactory({
- name: 'conversation.trajectory.images.view', scope: 'session',
- children: { 'conversation.trajectory.images': { kind: 'single', scope: 'session' } },
- }, TrajectoryImagesView)
- runtime.slots.register({ name: 'conversation.trajectory.images' }, RecordImages)
await runtime.sessions.add({ id: 'trajectory-images' })
const session = runtime.sessions.retainFor(runtime.ctx, SessionId('trajectory-images'))
- type Seats = PropsRenderFactories & Pick, 'SessionProvider'>
+ type Seats = PropsRenderSlots<'conversation.trajectory.images'>
const captured: { seats?: Seats; setContent?: (content: ReactNode) => void } = {}
- await runtime.root.declare({ 'conversation.view': { kind: 'list', scope: 'session' } }, function TestRoot(props) {
+ await runtime.root.declare({ 'conversation.trajectory.images': { kind: 'single', scope: 'session' } }, function TestRoot(props) {
const [content, setContent] = useState(null)
captured.seats = props
captured.setContent = setContent
const { SessionProvider } = props
return {content}
})
+ runtime.slots.register({ name: 'conversation.trajectory.images' }, RecordImages)
const view = runtime.renderRoot()
const { seats, setContent } = captured
if (seats === undefined || setContent === undefined) throw new Error('trajectory image fixture root did not render')
return {
- renderFactorySlot: seats.renderFactorySlot,
+ renderSlot: seats.renderSlot,
render: (content: ReactNode) => {
act(() => { setContent(content) })
return view
@@ -63,8 +58,8 @@ async function imageFactory() {
type TableProps = ComponentProps
function TrajectoryTable(
- props: Omit
- & Partial>,
+ props: Omit
+ & Partial>,
) {
const inferred: Array[number] & { firstIndex: number }> = []
for (const turn of props.turns) {
@@ -98,7 +93,7 @@ function TrajectoryTable(
.map(({ firstIndex: _firstIndex, ...request }, index) => ({ ...request, number: index + 1 }))
return (
{
render(
()}
onToggleTurn={() => {}}
@@ -1003,7 +998,7 @@ describe('TrajectoryTable', () => {
}]
const table = (status: 'running' | 'complete' | 'error') => (
{
partial: null,
runningCalls: [],
}, translate)
- const { render, renderFactorySlot: factorySlot } = await imageFactory()
- const renderFactorySlot = vi.fn(factorySlot)
+ const { render, renderSlot: slotRenderer } = await imageSlotFixture()
+ const renderSlot = vi.fn((name: 'conversation.trajectory.images', owner: object) => slotRenderer(name, owner as MessageImagesOwnerProps))
const view = render()
+ renderSlot={renderSlot} loadImage={loadImage} />)
fireEvent.click(view.container.querySelector('[data-trajectory-row-key]')!)
for (const tab of [summaryTab, previewTab]) {
fireEvent.click(screen.getByRole('tab', { name: tab }))
@@ -1184,7 +1179,7 @@ describe('TrajectoryTable', () => {
expect(names).toEqual([imageLabel, file.name, imageLabel.replace('1', '2')])
expect(within(list).getByText('TXT · 0B')).toBeTruthy()
expect(within(list).getAllByText('image/png · 68B · 40 × 800')).toHaveLength(2)
- expect(renderFactorySlot).toHaveBeenCalledWith('conversation.trajectory.images.view', {
+ expect(renderSlot).toHaveBeenCalledWith('conversation.trajectory.images', {
images: [{ attachment, label: imageLabel }], align: 'start', thumbnail: true, loadImage,
})
}
@@ -1203,7 +1198,7 @@ describe('TrajectoryTable', () => {
)
it('renders a tool-result image through the shared gallery in the Result tab', async () => {
- const { render, renderFactorySlot } = await imageFactory()
+ const { render, renderSlot } = await imageSlotFixture()
const attachment = {
attachmentId: AttachmentId(`sha256:${'b'.repeat(64)}`),
mediaType: 'image/png',
@@ -1229,7 +1224,7 @@ describe('TrajectoryTable', () => {
}],
}]
- render()
+ render()
fireEvent.click(screen.getByRole('row', { name: /TOOL/ }))
fireEvent.click(screen.getByRole('tab', { name: 'Result' }))
@@ -1240,7 +1235,7 @@ describe('TrajectoryTable', () => {
})
it('keeps the failure name beside an image-only error result', async () => {
- const { render, renderFactorySlot } = await imageFactory()
+ const { render, renderSlot } = await imageSlotFixture()
const attachment = {
attachmentId: AttachmentId(`sha256:${'c'.repeat(64)}`),
mediaType: 'image/png',
@@ -1267,7 +1262,7 @@ describe('TrajectoryTable', () => {
}],
}]
- render()
+ render()
fireEvent.click(screen.getByRole('row', { name: /TOOL/ }))
fireEvent.click(screen.getByRole('tab', { name: 'Result' }))
diff --git a/packages/client/ui-trajectory/tests/views.client.spec.tsx b/packages/client/ui-trajectory/tests/views.client.spec.tsx
index 0428ddeab3..2f5dd4a45e 100644
--- a/packages/client/ui-trajectory/tests/views.client.spec.tsx
+++ b/packages/client/ui-trajectory/tests/views.client.spec.tsx
@@ -7,7 +7,7 @@
* event ledger with its timing overview, and fiber disposal removes the tab.
* Timeline projection and inclusive focus edge cases ride along.
*/
-import type { GlobalStandardProps, PropsRenderFactories } from '@deepseek-ai/dsh-client-ui-slots'
+import type { GlobalStandardProps, PropsRenderSlots } from '@deepseek-ai/dsh-client-ui-slots'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { act, cleanup, fireEvent, render, screen, waitFor, within } from '@testing-library/react'
import { createElement, type ComponentProps, type FC, type ReactNode } from 'react'
@@ -244,7 +244,7 @@ function standaloneProps(
openView: () => {},
completeViewRequest: () => {},
// Image seats the outlet would bake: standalone renders omit the gallery.
- renderFactorySlot: () => null,
+ renderSlot: () => null,
loadImage: () => Promise.reject(new Error('standalone views load no images')),
// The locale seat the outlet would inject for the declared namespace.
t: tZh,
@@ -393,8 +393,8 @@ function mount(fixture: Awaited>) {
}
})()
: injected
- const viewProps: ConvViewProps & PropsRenderFactories = {
- ...owner, ...standardProps, renderFactorySlot: () => null,
+ const viewProps: ConvViewProps & Pick, 'renderSlot'> = {
+ ...owner, ...standardProps, renderSlot: () => null,
}
return (
ctx.slots.register(\n { name: \'conversation.chat.assistant-actions\', id: \'my-entry\', order: 100, label: \'My entry\' },\n () => React.createElement(\'div\', null, \'hello\'),\n ))\n },\n}',
- source: 'packages/client/ui-chat/src/client/contract/slots.ts:441',
+ source: 'packages/client/ui-chat/src/client/contract/slots.ts:439',
},
{
key: 'conversation.chat.commandview',
@@ -224,7 +224,7 @@ export const CLIENT_SLOT_API: readonly ClientSlotEntry[] = [
occupants: [],
replaceRisk: 'none',
example: 'return {\n inject: [\'slots\'],\n apply(ctx) {\n ctx.slots.inject(\'conversation.chat.commandview\', () => ctx.slots.register(\n { name: \'conversation.chat.commandview\', key: \'\' },\n () => React.createElement(\'div\', null, \'hello\'),\n ))\n },\n}',
- source: 'packages/client/ui-chat/src/client/contract/slots.ts:423',
+ source: 'packages/client/ui-chat/src/client/contract/slots.ts:421',
},
{
key: 'conversation.chat.flow',
@@ -267,7 +267,50 @@ export const CLIENT_SLOT_API: readonly ClientSlotEntry[] = [
],
replaceRisk: 'shadows-shipped-ui',
example: 'return {\n inject: [\'slots\'],\n apply(ctx) {\n ctx.slots.inject(\'conversation.chat.flow\', () => ctx.slots.register(\n { name: \'conversation.chat.flow\' },\n () => React.createElement(\'div\', null, \'hello\'),\n ))\n },\n}',
- source: 'packages/client/ui-chat/src/client/contract/slots.ts:392',
+ source: 'packages/client/ui-chat/src/client/contract/slots.ts:388',
+ },
+ {
+ key: 'conversation.chat.message.images',
+ kind: 'single',
+ scope: 'session',
+ summary: 'Renderer for one consecutive group of durable message images.',
+ doc: 'Renderer for one consecutive group of durable message images. The owner\nsupplies image references, an authorized loader, and alignment. A\nregistration replaces the shipped gallery; without one, images are omitted.',
+ registerOptions: [],
+ ownerProps: [
+ '/** Message image group handed to the optional attachment presentation plugin. */\nexport interface MessageImagesOwnerProps {\n /** Durable references or submission-echo previews in source order. */\n images: readonly MessageImageSource[]\n /** Session-authorized image URL loader for the durable arm. */\n loadImage: MessageImageLoader\n /** Horizontal placement inside the owning record. */\n align: \'start\' | \'end\'\n /** Force every image into the compact message-attachment tile size. */\n compact?: boolean\n /** Fixed, uncropped thumbnail for an attachment list row. */\n thumbnail?: boolean\n}',
+ ],
+ ownerPropsReferences: [
+ 'Message',
+ 'MessageImageLoader',
+ 'MessageImageSource',
+ ],
+ standardProps: [
+ 'useResource: UseResource',
+ 'useWorkspaces: SnapshotSelectorHook',
+ 'usePanelInfo: UsePanelInfo',
+ 'useSessions: UseSessions',
+ 'useSessionStatus: UseSessionStatus',
+ 'useSessionRetainInfo: UseSessionRetainInfo',
+ 'useWorkspaces: SnapshotSelectorHook',
+ 'useChat: UseChat',
+ 'useConversation: UseConversation',
+ 'useInput: SnapshotSelectorHook',
+ 'inputActions: InputActions',
+ 'useSession: SessionSnapshotSelector',
+ 'sessionId: SessionId',
+ 'useProjection: UseProjection',
+ 'useTrajectory: UseTrajectory',
+ ],
+ keyDomain: '',
+ hookContext: '',
+ slotInject: '',
+ declaredBy: 'an entry in \'conversation.chat.node\' (client-ui-chat), so it exists while that entry is mounted',
+ occupants: [
+ 'client-ui-attachment MessageImages',
+ ],
+ replaceRisk: 'shadows-shipped-ui',
+ example: 'return {\n inject: [\'slots\'],\n apply(ctx) {\n ctx.slots.inject(\'conversation.chat.message.images\', () => ctx.slots.register(\n { name: \'conversation.chat.message.images\' },\n () => React.createElement(\'div\', null, \'hello\'),\n ))\n },\n}',
+ source: 'packages/client/ui-chat/src/client/contract/slots.ts:413',
},
{
key: 'conversation.chat.node',
@@ -337,7 +380,7 @@ export const CLIENT_SLOT_API: readonly ClientSlotEntry[] = [
],
replaceRisk: 'shadows-shipped-ui',
example: 'return {\n inject: [\'slots\'],\n apply(ctx) {\n ctx.slots.inject(\'conversation.chat.node\', () => ctx.slots.register(\n { name: \'conversation.chat.node\', key: \'\' },\n () => React.createElement(\'div\', null, \'hello\'),\n ))\n },\n}',
- source: 'packages/client/ui-chat/src/client/contract/slots.ts:404',
+ source: 'packages/client/ui-chat/src/client/contract/slots.ts:400',
},
{
key: 'conversation.chat.reasoning.body',
@@ -377,7 +420,7 @@ export const CLIENT_SLOT_API: readonly ClientSlotEntry[] = [
],
replaceRisk: 'shadows-shipped-ui',
example: 'return {\n inject: [\'slots\'],\n apply(ctx) {\n ctx.slots.inject(\'conversation.chat.reasoning.body\', () => ctx.slots.register(\n { name: \'conversation.chat.reasoning.body\' },\n () => React.createElement(\'div\', null, \'hello\'),\n ))\n },\n}',
- source: 'packages/client/ui-chat/src/client/contract/slots.ts:429',
+ source: 'packages/client/ui-chat/src/client/contract/slots.ts:427',
},
{
key: 'conversation.chat.turnTail',
@@ -439,7 +482,50 @@ export const CLIENT_SLOT_API: readonly ClientSlotEntry[] = [
],
replaceRisk: 'none',
example: 'return {\n inject: [\'slots\'],\n apply(ctx) {\n ctx.slots.inject(\'conversation.chat.turnTail\', () => ctx.slots.register(\n { name: \'conversation.chat.turnTail\', id: \'my-entry\', order: 100, label: \'My entry\' },\n () => React.createElement(\'div\', null, \'hello\'),\n ))\n },\n}',
- source: 'packages/client/ui-chat/src/client/contract/slots.ts:435',
+ source: 'packages/client/ui-chat/src/client/contract/slots.ts:433',
+ },
+ {
+ key: 'conversation.chat.user.images',
+ kind: 'single',
+ scope: 'session',
+ summary: 'User-message images, including pending and local-echo previews, independently replaceable from output images.',
+ doc: 'User-message images, including pending and local-echo previews, independently replaceable from output images.',
+ registerOptions: [],
+ ownerProps: [
+ '/** Message image group handed to the optional attachment presentation plugin. */\nexport interface MessageImagesOwnerProps {\n /** Durable references or submission-echo previews in source order. */\n images: readonly MessageImageSource[]\n /** Session-authorized image URL loader for the durable arm. */\n loadImage: MessageImageLoader\n /** Horizontal placement inside the owning record. */\n align: \'start\' | \'end\'\n /** Force every image into the compact message-attachment tile size. */\n compact?: boolean\n /** Fixed, uncropped thumbnail for an attachment list row. */\n thumbnail?: boolean\n}',
+ ],
+ ownerPropsReferences: [
+ 'Message',
+ 'MessageImageLoader',
+ 'MessageImageSource',
+ ],
+ standardProps: [
+ 'useResource: UseResource',
+ 'useWorkspaces: SnapshotSelectorHook',
+ 'usePanelInfo: UsePanelInfo',
+ 'useSessions: UseSessions',
+ 'useSessionStatus: UseSessionStatus',
+ 'useSessionRetainInfo: UseSessionRetainInfo',
+ 'useWorkspaces: SnapshotSelectorHook',
+ 'useChat: UseChat',
+ 'useConversation: UseConversation',
+ 'useInput: SnapshotSelectorHook',
+ 'inputActions: InputActions',
+ 'useSession: SessionSnapshotSelector',
+ 'sessionId: SessionId',
+ 'useProjection: UseProjection',
+ 'useTrajectory: UseTrajectory',
+ ],
+ keyDomain: '',
+ hookContext: '',
+ slotInject: '',
+ declaredBy: 'factory \'conversation.chat.user.content\' (client-ui-chat), so it exists while that definition is registered',
+ occupants: [
+ 'client-ui-attachment MessageImages',
+ ],
+ replaceRisk: 'shadows-shipped-ui',
+ example: 'return {\n inject: [\'slots\'],\n apply(ctx) {\n ctx.slots.inject(\'conversation.chat.user.images\', () => ctx.slots.register(\n { name: \'conversation.chat.user.images\' },\n () => React.createElement(\'div\', null, \'hello\'),\n ))\n },\n}',
+ source: 'packages/client/ui-chat/src/client/contract/slots.ts:415',
},
{
key: 'conversation.composer',
@@ -1213,49 +1299,6 @@ export const CLIENT_SLOT_API: readonly ClientSlotEntry[] = [
example: 'return {\n inject: [\'slots\'],\n apply(ctx) {\n ctx.slots.inject(\'conversation.input.right\', () => ctx.slots.register(\n { name: \'conversation.input.right\', id: \'my-entry\', order: 100, label: \'My entry\' },\n () => React.createElement(\'div\', null, \'hello\'),\n ))\n },\n}',
source: 'packages/client/ui-conversation/src/client/contract/slots.ts:276',
},
- {
- key: 'conversation.message.images',
- kind: 'single',
- scope: 'session',
- summary: 'Renderer for one consecutive group of durable message images.',
- doc: 'Renderer for one consecutive group of durable message images. The owner\nsupplies image references, an authorized loader, and alignment. A\nregistration replaces the shipped gallery; without one, images are omitted.',
- registerOptions: [],
- ownerProps: [
- '/** Message image group handed to the optional attachment presentation plugin. */\nexport interface MessageImagesOwnerProps {\n /** Durable references or submission-echo previews in source order. */\n images: readonly MessageImageSource[]\n /** Session-authorized image URL loader for the durable arm. */\n loadImage: MessageImageLoader\n /** Horizontal placement inside the owning record. */\n align: \'start\' | \'end\'\n /** Force every image into the compact message-attachment tile size. */\n compact?: boolean\n /** Fixed, uncropped thumbnail for an attachment list row. */\n thumbnail?: boolean\n}',
- ],
- ownerPropsReferences: [
- 'Message',
- 'MessageImageLoader',
- 'MessageImageSource',
- ],
- standardProps: [
- 'useResource: UseResource',
- 'useWorkspaces: SnapshotSelectorHook',
- 'usePanelInfo: UsePanelInfo',
- 'useSessions: UseSessions',
- 'useSessionStatus: UseSessionStatus',
- 'useSessionRetainInfo: UseSessionRetainInfo',
- 'useWorkspaces: SnapshotSelectorHook',
- 'useChat: UseChat',
- 'useConversation: UseConversation',
- 'useInput: SnapshotSelectorHook',
- 'inputActions: InputActions',
- 'useSession: SessionSnapshotSelector',
- 'sessionId: SessionId',
- 'useProjection: UseProjection',
- 'useTrajectory: UseTrajectory',
- ],
- keyDomain: '',
- hookContext: '',
- slotInject: '',
- declaredBy: 'factory \'conversation.message.images.view\' (client-ui-chat), so it exists while that definition is registered',
- occupants: [
- 'client-ui-attachment MessageImages',
- ],
- replaceRisk: 'shadows-shipped-ui',
- example: 'return {\n inject: [\'slots\'],\n apply(ctx) {\n ctx.slots.inject(\'conversation.message.images\', () => ctx.slots.register(\n { name: \'conversation.message.images\' },\n () => React.createElement(\'div\', null, \'hello\'),\n ))\n },\n}',
- source: 'packages/client/ui-chat/src/client/contract/slots.ts:417',
- },
{
key: 'conversation.plan-review.actions',
kind: 'list',
@@ -1624,13 +1667,13 @@ export const CLIENT_SLOT_API: readonly ClientSlotEntry[] = [
keyDomain: '',
hookContext: '',
slotInject: '',
- declaredBy: 'factory \'conversation.trajectory.images.view\' (client-ui-trajectory), so it exists while that definition is registered',
+ declaredBy: 'an entry in \'conversation.view\' (client-ui-trajectory), so it exists while that entry is mounted',
occupants: [
'client-ui-attachment MessageImages',
],
replaceRisk: 'shadows-shipped-ui',
example: 'return {\n inject: [\'slots\'],\n apply(ctx) {\n ctx.slots.inject(\'conversation.trajectory.images\', () => ctx.slots.register(\n { name: \'conversation.trajectory.images\' },\n () => React.createElement(\'div\', null, \'hello\'),\n ))\n },\n}',
- source: 'packages/client/ui-trajectory/src/client/trajectory-contract.ts:112',
+ source: 'packages/client/ui-trajectory/src/client/trajectory-contract.ts:103',
},
{
key: 'conversation.user.text.node',
@@ -3071,7 +3114,7 @@ export const CLIENT_SLOT_API: readonly ClientSlotEntry[] = [
],
replaceRisk: 'none',
example: 'return {\n inject: [\'slots\'],\n apply(ctx) {\n ctx.slots.inject(\'shell.quota-notice\', () => ctx.slots.register(\n { name: \'shell.quota-notice\', select: owner => null },\n () => React.createElement(\'div\', null, \'hello\'),\n ))\n },\n}',
- source: 'packages/client/ui-chat/src/client/contract/slots.ts:449',
+ source: 'packages/client/ui-chat/src/client/contract/slots.ts:447',
},
{
key: 'sidebar',