feat(team-mode): add member session resolution and routing logic

This commit is contained in:
YeonGyu-Kim
2026-04-28 10:45:36 +09:00
parent 8a42d7fd69
commit 41d6e12f0d
2 changed files with 132 additions and 0 deletions
@@ -0,0 +1,63 @@
import type { TeamModeConfig } from "../../config/schema/team-mode"
import { log } from "../../shared/logger"
import { lookupTeamSession } from "./team-session-registry"
import { listActiveTeams, loadRuntimeState } from "./team-state-store/store"
export type ResolvedMemberSession = {
teamRunId: string
memberName: string
}
export async function findResolvedMemberSession(
sessionID: string,
config: TeamModeConfig,
logContext: string,
): Promise<ResolvedMemberSession | null> {
const registryEntry = lookupTeamSession(sessionID)
if (registryEntry?.role === "member") {
try {
const runtimeState = await loadRuntimeState(registryEntry.teamRunId, config)
const memberEntry = runtimeState.members.find(
(member) => member.name === registryEntry.memberName
&& (member.sessionId === undefined || member.sessionId === sessionID),
)
if (memberEntry !== undefined) {
return {
teamRunId: runtimeState.teamRunId,
memberName: memberEntry.name,
}
}
} catch (error) {
log(`${logContext} registry lookup failed`, {
event: `${logContext}-registry-error`,
teamRunId: registryEntry.teamRunId,
sessionID,
error: error instanceof Error ? error.message : String(error),
})
}
}
const activeTeams = await listActiveTeams(config)
for (const activeTeam of activeTeams) {
try {
const runtimeState = await loadRuntimeState(activeTeam.teamRunId, config)
const memberEntry = runtimeState.members.find((member) => member.sessionId === sessionID)
if (memberEntry !== undefined) {
return {
teamRunId: runtimeState.teamRunId,
memberName: memberEntry.name,
}
}
} catch (error) {
log(`${logContext} skipped runtime`, {
event: `${logContext}-runtime-error`,
teamRunId: activeTeam.teamRunId,
sessionID,
error: error instanceof Error ? error.message : String(error),
})
}
}
return null
}
@@ -0,0 +1,69 @@
import { stripAgentListSortPrefix } from "../../shared/agent-display-names"
import { resolveRegisteredAgentName } from "../claude-code-session-state"
import { applySessionPromptParams } from "../../shared/session-prompt-params-helpers"
import { SessionCategoryRegistry } from "../../shared/session-category-registry"
import type { RuntimeStateMember } from "./types"
type PromptGenerationModel = {
reasoningEffort?: string
temperature?: number
top_p?: number
maxTokens?: number
thinking?: { type: "enabled" | "disabled"; budgetTokens?: number }
}
export type TeamMemberPromptBody = {
parts: Array<{ type: "text"; text: string }>
agent?: string
model?: { providerID: string; modelID: string }
variant?: string
temperature?: number
topP?: number
maxOutputTokens?: number
options?: Record<string, unknown>
}
function buildPromptGenerationParams(model: PromptGenerationModel | undefined): Omit<TeamMemberPromptBody, "parts" | "agent" | "model" | "variant"> {
if (!model) {
return {}
}
const promptOptions: Record<string, unknown> = {
...(model.reasoningEffort ? { reasoningEffort: model.reasoningEffort } : {}),
...(model.thinking ? { thinking: model.thinking } : {}),
}
return {
...(model.temperature !== undefined ? { temperature: model.temperature } : {}),
...(model.top_p !== undefined ? { topP: model.top_p } : {}),
...(model.maxTokens !== undefined ? { maxOutputTokens: model.maxTokens } : {}),
...(Object.keys(promptOptions).length > 0 ? { options: promptOptions } : {}),
}
}
export function applyMemberSessionRouting(sessionID: string, member: RuntimeStateMember): void {
if (member.category) {
SessionCategoryRegistry.register(sessionID, member.category)
}
applySessionPromptParams(sessionID, member.model)
}
export function buildMemberPromptBody(member: RuntimeStateMember, text: string): TeamMemberPromptBody {
const normalizedAgent = member.subagent_type ? stripAgentListSortPrefix(member.subagent_type) : undefined
const launchAgent = resolveRegisteredAgentName(normalizedAgent) ?? normalizedAgent
const model = member.model
? {
providerID: member.model.providerID,
modelID: member.model.modelID,
}
: undefined
return {
...(launchAgent ? { agent: launchAgent } : {}),
...(model ? { model } : {}),
...(member.model?.variant ? { variant: member.model.variant } : {}),
...buildPromptGenerationParams(member.model),
parts: [{ type: "text", text }],
}
}