mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-09 22:34:32 +00:00
refactor: eliminate remaining duplicate blocks across draft streams and tests
This commit is contained in:
@@ -148,6 +148,19 @@ function resolveCaseInsensitiveAccount<T>(
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
function resolveDefaultToCaseInsensitiveAccount(params: {
|
||||
channel?:
|
||||
| {
|
||||
accounts?: Record<string, { defaultTo?: string }>;
|
||||
defaultTo?: string;
|
||||
}
|
||||
| undefined;
|
||||
accountId?: string | null;
|
||||
}): string | undefined {
|
||||
const account = resolveCaseInsensitiveAccount(params.channel?.accounts, params.accountId);
|
||||
return (account?.defaultTo ?? params.channel?.defaultTo)?.trim() || undefined;
|
||||
}
|
||||
// Channel docks: lightweight channel metadata/behavior for shared code paths.
|
||||
//
|
||||
// Rules:
|
||||
@@ -331,15 +344,7 @@ const DOCKS: Record<ChatChannelId, ChannelDock> = {
|
||||
const channel = cfg.channels?.irc as
|
||||
| { accounts?: Record<string, { defaultTo?: string }>; defaultTo?: string }
|
||||
| undefined;
|
||||
const normalized = normalizeAccountId(accountId);
|
||||
const account =
|
||||
channel?.accounts?.[normalized] ??
|
||||
channel?.accounts?.[
|
||||
Object.keys(channel?.accounts ?? {}).find(
|
||||
(key) => key.toLowerCase() === normalized.toLowerCase(),
|
||||
) ?? ""
|
||||
];
|
||||
return (account?.defaultTo ?? channel?.defaultTo)?.trim() || undefined;
|
||||
return resolveDefaultToCaseInsensitiveAccount({ channel, accountId });
|
||||
},
|
||||
},
|
||||
groups: {
|
||||
@@ -412,15 +417,7 @@ const DOCKS: Record<ChatChannelId, ChannelDock> = {
|
||||
const channel = cfg.channels?.googlechat as
|
||||
| { accounts?: Record<string, { defaultTo?: string }>; defaultTo?: string }
|
||||
| undefined;
|
||||
const normalized = normalizeAccountId(accountId);
|
||||
const account =
|
||||
channel?.accounts?.[normalized] ??
|
||||
channel?.accounts?.[
|
||||
Object.keys(channel?.accounts ?? {}).find(
|
||||
(key) => key.toLowerCase() === normalized.toLowerCase(),
|
||||
) ?? ""
|
||||
];
|
||||
return (account?.defaultTo ?? channel?.defaultTo)?.trim() || undefined;
|
||||
return resolveDefaultToCaseInsensitiveAccount({ channel, accountId });
|
||||
},
|
||||
},
|
||||
groups: {
|
||||
|
||||
139
src/channels/draft-stream-controls.ts
Normal file
139
src/channels/draft-stream-controls.ts
Normal file
@@ -0,0 +1,139 @@
|
||||
import { createDraftStreamLoop } from "./draft-stream-loop.js";
|
||||
|
||||
export type FinalizableDraftStreamState = {
|
||||
stopped: boolean;
|
||||
final: boolean;
|
||||
};
|
||||
|
||||
export function createFinalizableDraftStreamControls(params: {
|
||||
throttleMs: number;
|
||||
isStopped: () => boolean;
|
||||
isFinal: () => boolean;
|
||||
markStopped: () => void;
|
||||
markFinal: () => void;
|
||||
sendOrEditStreamMessage: (text: string) => Promise<boolean>;
|
||||
}) {
|
||||
const loop = createDraftStreamLoop({
|
||||
throttleMs: params.throttleMs,
|
||||
isStopped: params.isStopped,
|
||||
sendOrEditStreamMessage: params.sendOrEditStreamMessage,
|
||||
});
|
||||
|
||||
const update = (text: string) => {
|
||||
if (params.isStopped() || params.isFinal()) {
|
||||
return;
|
||||
}
|
||||
loop.update(text);
|
||||
};
|
||||
|
||||
const stop = async (): Promise<void> => {
|
||||
params.markFinal();
|
||||
await loop.flush();
|
||||
};
|
||||
|
||||
const stopForClear = async (): Promise<void> => {
|
||||
params.markStopped();
|
||||
loop.stop();
|
||||
await loop.waitForInFlight();
|
||||
};
|
||||
|
||||
return {
|
||||
loop,
|
||||
update,
|
||||
stop,
|
||||
stopForClear,
|
||||
};
|
||||
}
|
||||
|
||||
export function createFinalizableDraftStreamControlsForState(params: {
|
||||
throttleMs: number;
|
||||
state: FinalizableDraftStreamState;
|
||||
sendOrEditStreamMessage: (text: string) => Promise<boolean>;
|
||||
}) {
|
||||
return createFinalizableDraftStreamControls({
|
||||
throttleMs: params.throttleMs,
|
||||
isStopped: () => params.state.stopped,
|
||||
isFinal: () => params.state.final,
|
||||
markStopped: () => {
|
||||
params.state.stopped = true;
|
||||
},
|
||||
markFinal: () => {
|
||||
params.state.final = true;
|
||||
},
|
||||
sendOrEditStreamMessage: params.sendOrEditStreamMessage,
|
||||
});
|
||||
}
|
||||
|
||||
export async function takeMessageIdAfterStop<T>(params: {
|
||||
stopForClear: () => Promise<void>;
|
||||
readMessageId: () => T | undefined;
|
||||
clearMessageId: () => void;
|
||||
}): Promise<T | undefined> {
|
||||
await params.stopForClear();
|
||||
const messageId = params.readMessageId();
|
||||
params.clearMessageId();
|
||||
return messageId;
|
||||
}
|
||||
|
||||
export async function clearFinalizableDraftMessage<T>(params: {
|
||||
stopForClear: () => Promise<void>;
|
||||
readMessageId: () => T | undefined;
|
||||
clearMessageId: () => void;
|
||||
isValidMessageId: (value: unknown) => value is T;
|
||||
deleteMessage: (messageId: T) => Promise<void>;
|
||||
onDeleteSuccess?: (messageId: T) => void;
|
||||
warn?: (message: string) => void;
|
||||
warnPrefix: string;
|
||||
}): Promise<void> {
|
||||
const messageId = await takeMessageIdAfterStop({
|
||||
stopForClear: params.stopForClear,
|
||||
readMessageId: params.readMessageId,
|
||||
clearMessageId: params.clearMessageId,
|
||||
});
|
||||
if (!params.isValidMessageId(messageId)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await params.deleteMessage(messageId);
|
||||
params.onDeleteSuccess?.(messageId);
|
||||
} catch (err) {
|
||||
params.warn?.(`${params.warnPrefix}: ${err instanceof Error ? err.message : String(err)}`);
|
||||
}
|
||||
}
|
||||
|
||||
export function createFinalizableDraftLifecycle<T>(params: {
|
||||
throttleMs: number;
|
||||
state: FinalizableDraftStreamState;
|
||||
sendOrEditStreamMessage: (text: string) => Promise<boolean>;
|
||||
readMessageId: () => T | undefined;
|
||||
clearMessageId: () => void;
|
||||
isValidMessageId: (value: unknown) => value is T;
|
||||
deleteMessage: (messageId: T) => Promise<void>;
|
||||
onDeleteSuccess?: (messageId: T) => void;
|
||||
warn?: (message: string) => void;
|
||||
warnPrefix: string;
|
||||
}) {
|
||||
const controls = createFinalizableDraftStreamControlsForState({
|
||||
throttleMs: params.throttleMs,
|
||||
state: params.state,
|
||||
sendOrEditStreamMessage: params.sendOrEditStreamMessage,
|
||||
});
|
||||
|
||||
const clear = async () => {
|
||||
await clearFinalizableDraftMessage({
|
||||
stopForClear: controls.stopForClear,
|
||||
readMessageId: params.readMessageId,
|
||||
clearMessageId: params.clearMessageId,
|
||||
isValidMessageId: params.isValidMessageId,
|
||||
deleteMessage: params.deleteMessage,
|
||||
onDeleteSuccess: params.onDeleteSuccess,
|
||||
warn: params.warn,
|
||||
warnPrefix: params.warnPrefix,
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
...controls,
|
||||
clear,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user