Merge remote-tracking branch 'origin/master' into worktree/context-source-cards

# Conflicts:
#	packages/client/runtime/README.i18n.yaml
#	packages/client/ui-conversation/README.i18n.yaml
This commit is contained in:
creatixchu
2026-08-06 11:57:17 +08:00
100 changed files with 1065 additions and 837 deletions

View File

@@ -10,14 +10,8 @@ import type {} from '@deepseek-ai/dsh-client-ui-conversation/client'
import { createTrajectoryDurationStore } from './duration-store.ts'
import { TrajectoryView, type TrajectoryViewInjected } from './TrajectoryView.tsx'
/**
* Required services (cordis fiber inject). 'conversation' is an ordering
* edge, not a call dependency: the 'conversation.view' slot is declared by
* ui-conversation's apply (which then provides the service), and register()
* into an undeclared slot throws — service waiting is what orders this
* apply after the declaring one.
*/
export const inject = ['slots', 'conversation', 'sessionHistory']
/** Required services: the conversation view slot and independent history source. */
export const inject = ['slots', 'sessionHistory']
/**
* Client plugin body: register the trajectory view tab. The registration
@@ -26,7 +20,7 @@ export const inject = ['slots', 'conversation', 'sessionHistory']
*/
export function apply(ctx: Context): void {
const duration = createTrajectoryDurationStore()
ctx.slots.register({
ctx.slots.inject('conversation.view', () => ctx.slots.register({
name: 'conversation.view',
id: 'trajectory',
order: 10,
@@ -40,5 +34,5 @@ export function apply(ctx: Context): void {
setActualDuration: (value) => { duration.set(value) },
}
},
}, TrajectoryView)
}, TrajectoryView))
}

View File

@@ -61,7 +61,7 @@ describe('tsdown client artifact', () => {
const { handoff, surface } = await loadArtifact()
expect(handoff.id).toBe(PLUGIN_ID)
expect(surface.apply).toBeTypeOf('function')
expect(surface.inject).toEqual(['slots', 'conversation', 'sessionHistory'])
expect(surface.inject).toEqual(['slots', 'sessionHistory'])
})
it.skipIf(code === undefined)('mounted as an object plugin, apply registers the view tab on the real ring', async () => {
@@ -73,10 +73,8 @@ describe('tsdown client artifact', () => {
name: 'root',
children: { 'conversation.view': { kind: 'list', scope: 'session' } },
}, (_p: { renderSlot?: unknown }) => null)
// The plugin injects 'conversation' as an ordering edge and
// 'sessionHistory' for its per-session history source; this bench
// supplies both.
ctx.provide('conversation', {})
// The plugin reads sessionHistory for its per-session history source;
// slot availability is tracked by slots.inject.
ctx.provide('sessionHistory', {})
const fiber = ctx.plugin(surface as { apply: (ctx: Context) => void })
await fiber.await()

View File

@@ -168,9 +168,6 @@ async function bench(snapshot = historySnapshot(NODES)) {
const chatBody = vi.fn(() => <div data-testid="chat-body" />)
slots.register(
{ name: 'conversation.view', id: 'chat', order: 0, label: 'Chat' } as never, chatBody as never)
// 'conversation' inject is an ordering edge; the bench declares the ring
// itself, so a stub satisfies the wait.
ctx.provide('conversation', {})
ctx.provide('sessionHistory', { source: () => history })
const fiber = ctx.plugin({ inject: [...inject], apply })
await fiber.await()