mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-03 22:21:35 +00:00
84 lines
3.2 KiB
TypeScript
84 lines
3.2 KiB
TypeScript
// Msteams plugin module implements request deadline behavior.
|
|
import { resolveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
|
|
import {
|
|
createProviderOperationDeadline,
|
|
resolveProviderOperationTimeoutMs,
|
|
type ProviderOperationDeadline,
|
|
} from "openclaw/plugin-sdk/provider-http";
|
|
import { withTimeout } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
|
|
export const MSTEAMS_REQUEST_TIMEOUT_MS = 30_000;
|
|
// SharePoint PUTs are data-plane transfers: keep a base stall bound, then add
|
|
// slow-transfer budget so valid large uploads do not hit a fixed cutoff.
|
|
const MSTEAMS_SHAREPOINT_UPLOAD_BASE_TIMEOUT_MS = 5 * 60_000;
|
|
const MSTEAMS_SHAREPOINT_UPLOAD_MIN_BYTES_PER_SECOND = 256 * 1024;
|
|
|
|
// Cap optional enrichment before agent dispatch. The Teams SDK still holds the
|
|
// webhook open for the agent turn, so this budget alone cannot prevent retries.
|
|
const MSTEAMS_INBOUND_PREPROCESS_TIMEOUT_MS = 10_000;
|
|
|
|
export type MSTeamsRequestDeadline = ProviderOperationDeadline;
|
|
|
|
export function createMSTeamsInboundDeadline(): MSTeamsRequestDeadline {
|
|
return createProviderOperationDeadline({
|
|
label: "MS Teams inbound preprocessing",
|
|
timeoutMs: MSTEAMS_INBOUND_PREPROCESS_TIMEOUT_MS,
|
|
});
|
|
}
|
|
|
|
export function resolveMSTeamsRequestTimeoutMs(deadline?: MSTeamsRequestDeadline): number {
|
|
return deadline
|
|
? resolveProviderOperationTimeoutMs({
|
|
deadline,
|
|
defaultTimeoutMs: MSTEAMS_REQUEST_TIMEOUT_MS,
|
|
})
|
|
: MSTEAMS_REQUEST_TIMEOUT_MS;
|
|
}
|
|
|
|
/** Bound non-abortable SDK and credential work to the same operation deadline as fetches. */
|
|
export async function withMSTeamsRequestDeadline<T>(params: {
|
|
deadline?: MSTeamsRequestDeadline;
|
|
label: string;
|
|
work: () => Promise<T>;
|
|
}): Promise<T> {
|
|
const timeoutMs = resolveMSTeamsRequestTimeoutMs(params.deadline);
|
|
return await withTimeout(params.work(), timeoutMs, params.label);
|
|
}
|
|
|
|
export function resolveMSTeamsSharePointUploadTimeoutMs(sizeInBytes: number): number {
|
|
const bytes = Number.isFinite(sizeInBytes) && sizeInBytes > 0 ? Math.ceil(sizeInBytes) : 0;
|
|
const transferBudgetMs = Math.ceil(
|
|
(bytes / MSTEAMS_SHAREPOINT_UPLOAD_MIN_BYTES_PER_SECOND) * 1000,
|
|
);
|
|
return resolveTimerTimeoutMs(
|
|
MSTEAMS_SHAREPOINT_UPLOAD_BASE_TIMEOUT_MS + transferBudgetMs,
|
|
MSTEAMS_SHAREPOINT_UPLOAD_BASE_TIMEOUT_MS,
|
|
1,
|
|
);
|
|
}
|
|
function createMSTeamsRequestTimeoutError(label: string, timeoutMs: number): Error {
|
|
const error = new Error(`${label} timed out after ${timeoutMs}ms`);
|
|
error.name = "TimeoutError";
|
|
return error;
|
|
}
|
|
|
|
export async function withMSTeamsAbortableRequestTimeout<T>(params: {
|
|
label: string;
|
|
timeoutMs?: number;
|
|
work: (signal: AbortSignal) => Promise<T>;
|
|
}): Promise<T> {
|
|
const controller = new AbortController();
|
|
const timeoutMs = resolveTimerTimeoutMs(params.timeoutMs, MSTEAMS_REQUEST_TIMEOUT_MS, 1);
|
|
// Defer callback setup so withTimeout arms first; synchronous token-provider
|
|
// work must count against the request deadline.
|
|
const work = Promise.resolve().then(() => params.work(controller.signal));
|
|
try {
|
|
return await withTimeout(work, timeoutMs, {
|
|
createError: () => createMSTeamsRequestTimeoutError(params.label, timeoutMs),
|
|
});
|
|
} catch (error) {
|
|
controller.abort(error);
|
|
throw error;
|
|
}
|
|
}
|