Files
oh-my-openagent/src/shared/background-output-consumption.ts
YeonGyu-Kim b2497f1327 fix: resolve 3 community-reported bugs (#2915, #2917, #2918)
- background_output: snapshot read cursor before consuming, restore on
  /undo message removal so re-reads return data (fixes #2915)
- MCP loader: preserve oauth field in transformMcpServer, add scope/
  projectPath filtering so local-scoped MCPs only load in matching
  directories (fixes #2917)
- runtime-fallback: add 'reached your usage limit' to retryable error
  patterns so quota exhaustion triggers model fallback (fixes #2918)

Verified: bun test (4606 pass / 0 fail), tsc --noEmit clean
2026-03-29 04:53:43 +09:00

70 lines
2.2 KiB
TypeScript

import { getMessageCursor, restoreMessageCursor, type CursorState } from "./session-cursor"
type MessageConsumptionKey = `${string}:${string}`
const cursorSnapshotsByMessage = new Map<MessageConsumptionKey, Map<string, CursorState | undefined>>()
function getMessageKey(sessionID: string, messageID: string): MessageConsumptionKey {
return `${sessionID}:${messageID}`
}
export function recordBackgroundOutputConsumption(
parentSessionID: string | undefined,
parentMessageID: string | undefined,
taskSessionID: string | undefined
): void {
if (!parentSessionID || !parentMessageID || !taskSessionID) return
const messageKey = getMessageKey(parentSessionID, parentMessageID)
const existing = cursorSnapshotsByMessage.get(messageKey) ?? new Map<string, CursorState | undefined>()
if (!cursorSnapshotsByMessage.has(messageKey)) {
cursorSnapshotsByMessage.set(messageKey, existing)
}
if (existing.has(taskSessionID)) return
existing.set(taskSessionID, getMessageCursor(taskSessionID))
}
export function restoreBackgroundOutputConsumption(
parentSessionID: string | undefined,
parentMessageID: string | undefined
): void {
if (!parentSessionID || !parentMessageID) return
const messageKey = getMessageKey(parentSessionID, parentMessageID)
const snapshots = cursorSnapshotsByMessage.get(messageKey)
if (!snapshots) return
cursorSnapshotsByMessage.delete(messageKey)
for (const [taskSessionID, cursor] of snapshots) {
restoreMessageCursor(taskSessionID, cursor)
}
}
export function clearBackgroundOutputConsumptionsForParentSession(sessionID: string | undefined): void {
if (!sessionID) return
const prefix = `${sessionID}:`
for (const messageKey of cursorSnapshotsByMessage.keys()) {
if (messageKey.startsWith(prefix)) {
cursorSnapshotsByMessage.delete(messageKey)
}
}
}
export function clearBackgroundOutputConsumptionsForTaskSession(taskSessionID: string | undefined): void {
if (!taskSessionID) return
for (const [messageKey, snapshots] of cursorSnapshotsByMessage) {
snapshots.delete(taskSessionID)
if (snapshots.size === 0) {
cursorSnapshotsByMessage.delete(messageKey)
}
}
}
export function clearBackgroundOutputConsumptionState(): void {
cursorSnapshotsByMessage.clear()
}