diff --git a/extensions/discord/src/monitor/message-handler.process.test.ts b/extensions/discord/src/monitor/message-handler.process.test.ts index 017270464f1..07c7daea7f8 100644 --- a/extensions/discord/src/monitor/message-handler.process.test.ts +++ b/extensions/discord/src/monitor/message-handler.process.test.ts @@ -175,15 +175,15 @@ vi.spyOn(conversationRuntimeModule, "recordInboundSession").mockImplementation( recordInboundSession(params) as never) as never, ); -const configRuntimeModule = await import("openclaw/plugin-sdk/config-runtime"); -vi.spyOn(configRuntimeModule, "readSessionUpdatedAt").mockImplementation( - ((params: Parameters[0]) => +const sessionStoreRuntimeModule = await import("openclaw/plugin-sdk/session-store-runtime"); +vi.spyOn(sessionStoreRuntimeModule, "readSessionUpdatedAt").mockImplementation( + ((params: Parameters[0]) => configSessionsMocks.readSessionUpdatedAt(params) as never) as never, ); -vi.spyOn(configRuntimeModule, "resolveStorePath").mockImplementation( +vi.spyOn(sessionStoreRuntimeModule, "resolveStorePath").mockImplementation( (( - path: Parameters[0], - opts: Parameters[1], + path: Parameters[0], + opts: Parameters[1], ) => configSessionsMocks.resolveStorePath(path, opts) as never) as never, ); diff --git a/extensions/discord/src/monitor/message-handler.process.ts b/extensions/discord/src/monitor/message-handler.process.ts index 7eb35b20e14..3308a8c7003 100644 --- a/extensions/discord/src/monitor/message-handler.process.ts +++ b/extensions/discord/src/monitor/message-handler.process.ts @@ -21,14 +21,10 @@ import { resolveChannelStreamingBlockEnabled, resolveChannelStreamingPreviewToolProgress, } from "openclaw/plugin-sdk/channel-streaming"; -import { - isDangerousNameMatchingEnabled, - readSessionUpdatedAt, - resolveChannelContextVisibilityMode, - resolveMarkdownTableMode, - resolveStorePath, -} from "openclaw/plugin-sdk/config-runtime"; +import { resolveChannelContextVisibilityMode } from "openclaw/plugin-sdk/context-visibility-runtime"; import { recordInboundSession } from "openclaw/plugin-sdk/conversation-runtime"; +import { isDangerousNameMatchingEnabled } from "openclaw/plugin-sdk/dangerous-name-runtime"; +import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime"; import { getAgentScopedMediaLocalRoots } from "openclaw/plugin-sdk/media-runtime"; import { resolveChunkMode } from "openclaw/plugin-sdk/reply-chunking"; import type { ReplyPayload } from "openclaw/plugin-sdk/reply-dispatch-runtime"; @@ -41,6 +37,7 @@ import { resolveSendableOutboundReplyParts } from "openclaw/plugin-sdk/reply-pay import { buildAgentSessionKey, resolveThreadSessionKeys } from "openclaw/plugin-sdk/routing"; import { danger, logVerbose, shouldLogVerbose } from "openclaw/plugin-sdk/runtime-env"; import { evaluateSupplementalContextVisibility } from "openclaw/plugin-sdk/security-runtime"; +import { readSessionUpdatedAt, resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime"; import { convertMarkdownTables, stripInlineDirectiveTagsForDelivery, diff --git a/extensions/discord/src/monitor/message-handler.ts b/extensions/discord/src/monitor/message-handler.ts index c8735f50ec5..56c6dbc7d1e 100644 --- a/extensions/discord/src/monitor/message-handler.ts +++ b/extensions/discord/src/monitor/message-handler.ts @@ -3,8 +3,8 @@ import { createChannelInboundDebouncer, shouldDebounceTextInbound, } from "openclaw/plugin-sdk/channel-inbound"; -import { resolveOpenProviderRuntimeGroupPolicy } from "openclaw/plugin-sdk/config-runtime"; import { danger } from "openclaw/plugin-sdk/runtime-env"; +import { resolveOpenProviderRuntimeGroupPolicy } from "openclaw/plugin-sdk/runtime-group-policy"; import { buildDiscordInboundReplayKey, claimDiscordInboundReplay, diff --git a/extensions/discord/src/monitor/thread-bindings.lifecycle.test.ts b/extensions/discord/src/monitor/thread-bindings.lifecycle.test.ts index a63c82d7158..64dbd5fbafe 100644 --- a/extensions/discord/src/monitor/thread-bindings.lifecycle.test.ts +++ b/extensions/discord/src/monitor/thread-bindings.lifecycle.test.ts @@ -2,12 +2,12 @@ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; import { ChannelType } from "discord-api-types/v10"; +import { getSessionBindingService } from "openclaw/plugin-sdk/conversation-runtime"; import { clearRuntimeConfigSnapshot, setRuntimeConfigSnapshot, type OpenClawConfig, -} from "openclaw/plugin-sdk/config-runtime"; -import { getSessionBindingService } from "openclaw/plugin-sdk/conversation-runtime"; +} from "openclaw/plugin-sdk/runtime-config-snapshot"; import { beforeEach, describe, expect, it, vi } from "vitest"; const hoisted = vi.hoisted(() => { diff --git a/extensions/voice-call/src/manager/events.test.ts b/extensions/voice-call/src/manager/events.test.ts index 46cbe744d18..0518ee4ece3 100644 --- a/extensions/voice-call/src/manager/events.test.ts +++ b/extensions/voice-call/src/manager/events.test.ts @@ -7,10 +7,11 @@ import type { VoiceCallProvider } from "../providers/base.js"; import type { HangupCallInput, NormalizedEvent } from "../types.js"; import type { CallManagerContext } from "./context.js"; import { processEvent } from "./events.js"; +import { flushPendingCallRecordWritesForTest } from "./store.js"; const contexts: CallManagerContext[] = []; -afterEach(() => { +afterEach(async () => { for (const ctx of contexts.splice(0)) { for (const timer of ctx.maxDurationTimers.values()) { clearTimeout(timer); @@ -20,6 +21,7 @@ afterEach(() => { clearTimeout(waiter.timeout); } ctx.transcriptWaiters.clear(); + await flushPendingCallRecordWritesForTest(); fs.rmSync(ctx.storePath, { recursive: true, force: true }); } }); diff --git a/extensions/voice-call/src/manager/store.ts b/extensions/voice-call/src/manager/store.ts index f412efd0be0..37b9f6976f0 100644 --- a/extensions/voice-call/src/manager/store.ts +++ b/extensions/voice-call/src/manager/store.ts @@ -3,13 +3,25 @@ import fsp from "node:fs/promises"; import path from "node:path"; import { CallRecordSchema, TerminalStates, type CallId, type CallRecord } from "../types.js"; +const pendingPersistWrites = new Set>(); + export function persistCallRecord(storePath: string, call: CallRecord): void { const logPath = path.join(storePath, "calls.jsonl"); const line = `${JSON.stringify(call)}\n`; // Fire-and-forget async write to avoid blocking event loop. - fsp.appendFile(logPath, line).catch((err) => { - console.error("[voice-call] Failed to persist call record:", err); - }); + const write = fsp + .appendFile(logPath, line) + .catch((err) => { + console.error("[voice-call] Failed to persist call record:", err); + }) + .finally(() => { + pendingPersistWrites.delete(write); + }); + pendingPersistWrites.add(write); +} + +export async function flushPendingCallRecordWritesForTest(): Promise { + await Promise.allSettled(pendingPersistWrites); } export function loadActiveCallsFromStore(storePath: string): { diff --git a/src/plugin-sdk/runtime-config-snapshot.ts b/src/plugin-sdk/runtime-config-snapshot.ts index 6016f0ffe7e..776dde41201 100644 --- a/src/plugin-sdk/runtime-config-snapshot.ts +++ b/src/plugin-sdk/runtime-config-snapshot.ts @@ -1,2 +1,6 @@ -export { getRuntimeConfigSnapshot } from "../config/runtime-snapshot.js"; +export { + clearRuntimeConfigSnapshot, + getRuntimeConfigSnapshot, + setRuntimeConfigSnapshot, +} from "../config/runtime-snapshot.js"; export type { OpenClawConfig } from "../config/types.js";