2026-03-11 20:09:24 +09:00
|
|
|
import type { HookDeps, RuntimeFallbackHook, RuntimeFallbackInterval, RuntimeFallbackOptions, RuntimeFallbackPluginInput, RuntimeFallbackTimeout } from "./types"
|
2026-02-17 16:29:52 -05:00
|
|
|
import { DEFAULT_CONFIG, HOOK_NAME } from "./constants"
|
|
|
|
|
import { log } from "../../shared/logger"
|
|
|
|
|
import { loadPluginConfig } from "../../plugin-config"
|
|
|
|
|
import { createAutoRetryHelpers } from "./auto-retry"
|
|
|
|
|
import { createEventHandler } from "./event-handler"
|
|
|
|
|
import { createMessageUpdateHandler } from "./message-update-handler"
|
|
|
|
|
import { createChatMessageHandler } from "./chat-message-handler"
|
|
|
|
|
|
2026-03-11 20:09:24 +09:00
|
|
|
declare function setInterval(callback: () => void, delay?: number): RuntimeFallbackInterval
|
|
|
|
|
declare function clearInterval(interval: RuntimeFallbackInterval): void
|
|
|
|
|
declare function clearTimeout(timeout: RuntimeFallbackTimeout): void
|
|
|
|
|
|
2026-02-17 16:29:52 -05:00
|
|
|
export function createRuntimeFallbackHook(
|
2026-03-11 20:09:24 +09:00
|
|
|
ctx: RuntimeFallbackPluginInput,
|
2026-02-17 16:29:52 -05:00
|
|
|
options?: RuntimeFallbackOptions
|
|
|
|
|
): RuntimeFallbackHook {
|
|
|
|
|
const config = {
|
|
|
|
|
enabled: options?.config?.enabled ?? DEFAULT_CONFIG.enabled,
|
|
|
|
|
retry_on_errors: options?.config?.retry_on_errors ?? DEFAULT_CONFIG.retry_on_errors,
|
|
|
|
|
max_fallback_attempts: options?.config?.max_fallback_attempts ?? DEFAULT_CONFIG.max_fallback_attempts,
|
|
|
|
|
cooldown_seconds: options?.config?.cooldown_seconds ?? DEFAULT_CONFIG.cooldown_seconds,
|
|
|
|
|
timeout_seconds: options?.config?.timeout_seconds ?? DEFAULT_CONFIG.timeout_seconds,
|
|
|
|
|
notify_on_fallback: options?.config?.notify_on_fallback ?? DEFAULT_CONFIG.notify_on_fallback,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let pluginConfig = options?.pluginConfig
|
|
|
|
|
if (!pluginConfig) {
|
|
|
|
|
try {
|
|
|
|
|
pluginConfig = loadPluginConfig(ctx.directory, ctx)
|
|
|
|
|
} catch {
|
|
|
|
|
log(`[${HOOK_NAME}] Plugin config not available`)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const deps: HookDeps = {
|
|
|
|
|
ctx,
|
|
|
|
|
config,
|
|
|
|
|
options,
|
|
|
|
|
pluginConfig,
|
|
|
|
|
sessionStates: new Map(),
|
|
|
|
|
sessionLastAccess: new Map(),
|
|
|
|
|
sessionRetryInFlight: new Set(),
|
|
|
|
|
sessionAwaitingFallbackResult: new Set(),
|
|
|
|
|
sessionFallbackTimeouts: new Map(),
|
2026-03-12 11:07:14 +09:00
|
|
|
sessionStatusRetryKeys: new Map(),
|
2026-02-17 16:29:52 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const helpers = createAutoRetryHelpers(deps)
|
|
|
|
|
const baseEventHandler = createEventHandler(deps, helpers)
|
|
|
|
|
const messageUpdateHandler = createMessageUpdateHandler(deps, helpers)
|
|
|
|
|
const chatMessageHandler = createChatMessageHandler(deps)
|
|
|
|
|
|
|
|
|
|
const cleanupInterval = setInterval(helpers.cleanupStaleSessions, 5 * 60 * 1000)
|
|
|
|
|
cleanupInterval.unref()
|
|
|
|
|
|
|
|
|
|
const eventHandler = async ({ event }: { event: { type: string; properties?: unknown } }) => {
|
|
|
|
|
if (event.type === "message.updated") {
|
|
|
|
|
if (!config.enabled) return
|
|
|
|
|
const props = event.properties as Record<string, unknown> | undefined
|
|
|
|
|
await messageUpdateHandler(props)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
await baseEventHandler({ event })
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-11 20:09:24 +09:00
|
|
|
const dispose = () => {
|
|
|
|
|
clearInterval(cleanupInterval)
|
|
|
|
|
|
|
|
|
|
for (const fallbackTimeout of deps.sessionFallbackTimeouts.values()) {
|
|
|
|
|
clearTimeout(fallbackTimeout)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
deps.sessionStates.clear()
|
|
|
|
|
deps.sessionLastAccess.clear()
|
|
|
|
|
deps.sessionRetryInFlight.clear()
|
|
|
|
|
deps.sessionAwaitingFallbackResult.clear()
|
|
|
|
|
deps.sessionFallbackTimeouts.clear()
|
2026-03-13 10:54:47 +09:00
|
|
|
deps.sessionStatusRetryKeys.clear()
|
2026-03-11 20:09:24 +09:00
|
|
|
}
|
|
|
|
|
|
2026-02-17 16:29:52 -05:00
|
|
|
return {
|
|
|
|
|
event: eventHandler,
|
|
|
|
|
"chat.message": chatMessageHandler,
|
2026-03-11 20:09:24 +09:00
|
|
|
dispose,
|
2026-02-17 16:29:52 -05:00
|
|
|
} as RuntimeFallbackHook
|
|
|
|
|
}
|