diff --git a/packages/ui/src/stores/message-v2/bridge.ts b/packages/ui/src/stores/message-v2/bridge.ts index d4cec513..a2a40abf 100644 --- a/packages/ui/src/stores/message-v2/bridge.ts +++ b/packages/ui/src/stores/message-v2/bridge.ts @@ -164,6 +164,34 @@ export function upsertPermissionV2(instanceId: string, permission: PermissionReq }) } +export function reconcilePendingPermissionsV2(instanceId: string, sessionId?: string): void { + const store = messageStoreBus.getOrCreate(instanceId) + const pending = store.state.permissions.queue + if (!pending || pending.length === 0) return + + for (const entry of pending) { + if (!entry || entry.partId) continue + const permission = entry.permission + if (!permission) continue + + const permissionSessionId = (permission as any)?.sessionID ?? (permission as any)?.sessionId ?? undefined + if (sessionId && permissionSessionId && permissionSessionId !== sessionId) { + continue + } + + const messageId = entry.messageId ?? extractPermissionMessageId(permission) + const callId = extractPermissionCallId(permission) + const resolvedPartId = resolvePartIdFromCallId(store, messageId, callId) + if (!resolvedPartId) continue + + store.upsertPermission({ + ...entry, + messageId, + partId: resolvedPartId, + }) + } +} + export function removePermissionV2(instanceId: string, permissionId: string): void { if (!permissionId) return const store = messageStoreBus.getOrCreate(instanceId) diff --git a/packages/ui/src/stores/session-api.ts b/packages/ui/src/stores/session-api.ts index 47611470..39a1853c 100644 --- a/packages/ui/src/stores/session-api.ts +++ b/packages/ui/src/stores/session-api.ts @@ -29,7 +29,7 @@ import { DEFAULT_MODEL_OUTPUT_LIMIT, getDefaultModel, isModelValid } from "./ses import { normalizeMessagePart } from "./message-v2/normalizers" import { updateSessionInfo } from "./message-v2/session-info" import { deriveSessionStatusFromMessages } from "./session-status" -import { seedSessionMessagesV2 } from "./message-v2/bridge" +import { seedSessionMessagesV2, reconcilePendingPermissionsV2 } from "./message-v2/bridge" import { messageStoreBus } from "./message-v2/bus" import { clearCacheForSession } from "../lib/global-cache" import { getLogger } from "../lib/logger" @@ -610,11 +610,15 @@ async function loadMessages(instanceId: string, sessionId: string, force = false } seedSessionMessagesV2(instanceId, sessionForV2, messages, messagesInfo) + // Permissions can be hydrated before messages/tool parts exist in the store. + // After message hydration, try to attach any pending permissions to tool-call part ids. + reconcilePendingPermissionsV2(instanceId, sessionId) + if (!alreadyLoaded) { const nextStatus = deriveSessionStatusFromMessages(instanceId, sessionId) setSessionStatus(instanceId, sessionId, nextStatus) } - + } catch (error) { log.error("Failed to load messages:", error) throw error