mirror of
https://github.com/deepseek-ai/deepseek-harness.git
synced 2026-09-14 04:01:35 +00:00
102 lines
3.7 KiB
TypeScript
102 lines
3.7 KiB
TypeScript
/** Source-safe Agent Teams browser registration and Remote mount lifecycle. */
|
|
|
|
import type {
|
|
TeamMemberView as TeamRosterMember,
|
|
TeamView,
|
|
} from '@deepseek-ai/dsh-experimental-agent-team/client'
|
|
import type {} from '@deepseek-ai/dsh-experimental-agent-team/remote'
|
|
import type { Context as ClientContext } from '@deepseek-ai/cordis'
|
|
import type {} from '@deepseek-ai/dsh-api-remotes/client'
|
|
import type {} from '@deepseek-ai/dsh-api-session-controller/client'
|
|
import type { SessionId } from '@deepseek-ai/dsh-session/types'
|
|
import type {} from '@deepseek-ai/dsh-client-ui-conversation/client'
|
|
import type {} from '@deepseek-ai/dsh-client-locale/client'
|
|
import type {} from '@deepseek-ai/dsh-client-ui-renderer/client'
|
|
import type { TypertRemoteContribution } from '@deepseek-ai/dsh-typert-protocol'
|
|
import {
|
|
TeamAction, type TeamActionInjected, type TeamActionResult, type TeamTaskActionResult,
|
|
} from './TeamAction.tsx'
|
|
import { en, NS, zh, type TeamKey } from './locales.ts'
|
|
|
|
declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
interface LocaleNamespaceMap {
|
|
/** Agent Teams roster and task-board copy. */
|
|
'agent-team': TeamKey
|
|
}
|
|
}
|
|
|
|
/** Required browser services for RPC, navigation, slots, and localized copy. */
|
|
export const inject = ['sessions', 'remote', 'slots', 'locale']
|
|
|
|
function registerUi(ctx: ClientContext): void {
|
|
ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'client-ui-agent-team: dictionaries')
|
|
const sessions = ctx.sessions
|
|
const leadSessionId = (sessionId: SessionId): SessionId => {
|
|
const address = sessions.binding(sessionId)?.session.getSnapshot().subagent?.address
|
|
return address?.parentSessionId ?? sessionId
|
|
}
|
|
|
|
const actions: TeamActionInjected = {
|
|
async load(sessionId): Promise<TeamActionResult<TeamView>> {
|
|
return await ctx.remote.agentTeams.view(leadSessionId(sessionId))
|
|
},
|
|
async createTask(sessionId, input): Promise<TeamTaskActionResult> {
|
|
return await ctx.remote.agentTeams.createTask(leadSessionId(sessionId), input)
|
|
},
|
|
async updateTask(sessionId, input) {
|
|
const { owner, ...rest } = input
|
|
return await ctx.remote.agentTeams.updateTask(leadSessionId(sessionId), {
|
|
...rest,
|
|
...owner === undefined ? {} : { owner },
|
|
})
|
|
},
|
|
async openTeammate(sessionId: SessionId, member: TeamRosterMember): Promise<void> {
|
|
if (member.role !== 'teammate') return
|
|
const parentSessionId = leadSessionId(sessionId)
|
|
await sessions.refreshSubagents(parentSessionId)
|
|
if (sessions.list.getSnapshot().current !== sessionId) return
|
|
sessions.openSubagent({
|
|
parentSessionId,
|
|
childSessionId: member.id,
|
|
mode: 'continuable',
|
|
})
|
|
},
|
|
}
|
|
|
|
ctx.slots.inject(
|
|
'conversation.session.header.actions',
|
|
() => ctx.slots.register({
|
|
name: 'conversation.session.header.actions',
|
|
id: 'agent-team',
|
|
order: 20,
|
|
locale: NS,
|
|
inject: () => actions,
|
|
}, TeamAction),
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Mount one generated Team Remote contribution, then register its browser UI.
|
|
* @param ctx - Client Context carrying navigation, locale, slot, and Remote services.
|
|
* @param contribution - generated Team descriptors selected by the browser entry.
|
|
* @returns disposer for both the UI registrations and Remote namespace.
|
|
*/
|
|
export async function mountAgentTeamUi(
|
|
ctx: ClientContext,
|
|
contribution: TypertRemoteContribution,
|
|
): Promise<() => Promise<void>> {
|
|
const disposeRemote = await ctx.remote.$mount(contribution)
|
|
const ui = ctx.inject(['sessions', 'remote.agentTeams', 'slots', 'locale'], registerUi)
|
|
try {
|
|
await ui
|
|
} catch (error) {
|
|
await ui.dispose()
|
|
await disposeRemote()
|
|
throw error
|
|
}
|
|
return async () => {
|
|
await ui.dispose()
|
|
await disposeRemote()
|
|
}
|
|
}
|