Files
oh-my-opencode/src/hooks/team-session-events/team-member-error-handler.ts
T

82 lines
2.9 KiB
TypeScript
Raw Normal View History

import type { TeamModeConfig } from "../../config/schema/team-mode"
import { findResolvedMemberSession } from "../../features/team-mode/member-session-resolution"
2026-05-15 22:49:10 +09:00
import {
releaseDeliveryReservation,
reserveMessageForDelivery,
} from "../../features/team-mode/team-mailbox/reservation"
import { loadRuntimeState, transitionRuntimeState } from "../../features/team-mode/team-state-store/store"
2026-05-12 11:48:18 +09:00
import { resolveSessionEventID } from "../../shared/event-session-id"
import { log } from "../../shared/logger"
type HookInput = { event: { type: string; properties?: unknown } }
export type HookImpl = (input: HookInput) => Promise<void>
function getErroredSessionID(properties: unknown): string | undefined {
2026-05-12 11:48:18 +09:00
return resolveSessionEventID(properties)
}
2026-05-15 22:49:10 +09:00
async function requeuePendingLiveDeliveries(
teamRunId: string,
memberName: string,
messageIds: readonly string[],
config: TeamModeConfig,
): Promise<void> {
for (const messageId of messageIds) {
const reservation = await reserveMessageForDelivery(teamRunId, memberName, messageId, config)
if (reservation === null) {
continue
}
await releaseDeliveryReservation(reservation)
}
}
export function createTeamMemberErrorHandler(config: TeamModeConfig): HookImpl {
return async ({ event }: HookInput): Promise<void> => {
if (event.type !== "session.error") return
const erroredSessionID = getErroredSessionID(event.properties)
if (!erroredSessionID) return
try {
const runtimeMember = await findResolvedMemberSession(erroredSessionID, config, "team member error handler")
if (runtimeMember === null) {
return
}
const runtimeState = await loadRuntimeState(runtimeMember.teamRunId, config)
2026-05-15 22:49:10 +09:00
const memberEntry = runtimeState.members.find((member) => member.name === runtimeMember.memberName)
const pendingInjectedMessageIds = memberEntry?.pendingInjectedMessageIds ?? []
await requeuePendingLiveDeliveries(
runtimeState.teamRunId,
runtimeMember.memberName,
pendingInjectedMessageIds,
config,
)
await transitionRuntimeState(runtimeState.teamRunId, (currentRuntimeState) => ({
...currentRuntimeState,
members: currentRuntimeState.members.map((member) => (
member.name === runtimeMember.memberName
2026-05-15 22:49:10 +09:00
? { ...member, status: "errored", pendingInjectedMessageIds: [] }
: member
)),
}), config)
log("team member session errored", {
event: "team-mode-member-errored",
teamRunId: runtimeState.teamRunId,
teamName: runtimeState.teamName,
memberName: runtimeMember.memberName,
sessionID: erroredSessionID,
runtimeStatus: runtimeState.status,
})
} catch (error) {
log("team member error handler failed", {
event: "team-mode-member-error-handler-error",
sessionID: erroredSessionID,
error: error instanceof Error ? error.message : String(error),
})
}
}
}