mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 20:40:43 +00:00
msteams: add typingIndicator config and prevent duplicate DM typing indicator (#60771)
* msteams: add typingIndicator config and avoid duplicate DM typing * fix(msteams): validate typingIndicator config * fix(msteams): stop streaming before Teams timeout * fix(msteams): classify expired streams correctly * fix(msteams): handle link text from html attachments --------- Co-authored-by: Brad Groux <bradgroux@users.noreply.github.com>
This commit is contained in:
@@ -63,6 +63,32 @@ function extractStatusCode(err: unknown): number | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
function extractErrorCode(err: unknown): string | null {
|
||||
if (!isRecord(err)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const direct = err.code;
|
||||
if (typeof direct === "string" && direct.trim()) {
|
||||
return direct;
|
||||
}
|
||||
|
||||
const response = err.response;
|
||||
if (!isRecord(response)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const body = response.body;
|
||||
if (isRecord(body)) {
|
||||
const error = body.error;
|
||||
if (isRecord(error) && typeof error.code === "string" && error.code.trim()) {
|
||||
return error.code;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function extractRetryAfterMs(err: unknown): number | null {
|
||||
if (!isRecord(err)) {
|
||||
return null;
|
||||
@@ -129,6 +155,7 @@ export type MSTeamsSendErrorClassification = {
|
||||
kind: MSTeamsSendErrorKind;
|
||||
statusCode?: number;
|
||||
retryAfterMs?: number;
|
||||
errorCode?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -142,9 +169,17 @@ export type MSTeamsSendErrorClassification = {
|
||||
export function classifyMSTeamsSendError(err: unknown): MSTeamsSendErrorClassification {
|
||||
const statusCode = extractStatusCode(err);
|
||||
const retryAfterMs = extractRetryAfterMs(err);
|
||||
const errorCode = extractErrorCode(err) ?? undefined;
|
||||
|
||||
if (statusCode === 401 || statusCode === 403) {
|
||||
return { kind: "auth", statusCode };
|
||||
if (statusCode === 401) {
|
||||
return { kind: "auth", statusCode, errorCode };
|
||||
}
|
||||
|
||||
if (statusCode === 403) {
|
||||
if (errorCode === "ContentStreamNotAllowed") {
|
||||
return { kind: "permanent", statusCode, errorCode };
|
||||
}
|
||||
return { kind: "auth", statusCode, errorCode };
|
||||
}
|
||||
|
||||
if (statusCode === 429) {
|
||||
@@ -152,6 +187,7 @@ export function classifyMSTeamsSendError(err: unknown): MSTeamsSendErrorClassifi
|
||||
kind: "throttled",
|
||||
statusCode,
|
||||
retryAfterMs: retryAfterMs ?? undefined,
|
||||
errorCode,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -160,17 +196,19 @@ export function classifyMSTeamsSendError(err: unknown): MSTeamsSendErrorClassifi
|
||||
kind: "transient",
|
||||
statusCode,
|
||||
retryAfterMs: retryAfterMs ?? undefined,
|
||||
errorCode,
|
||||
};
|
||||
}
|
||||
|
||||
if (statusCode != null && statusCode >= 400) {
|
||||
return { kind: "permanent", statusCode };
|
||||
return { kind: "permanent", statusCode, errorCode };
|
||||
}
|
||||
|
||||
return {
|
||||
kind: "unknown",
|
||||
statusCode: statusCode ?? undefined,
|
||||
retryAfterMs: retryAfterMs ?? undefined,
|
||||
errorCode,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -195,6 +233,9 @@ export function formatMSTeamsSendErrorHint(
|
||||
if (classification.kind === "auth") {
|
||||
return "check msteams appId/appPassword/tenantId (or env vars MSTEAMS_APP_ID/MSTEAMS_APP_PASSWORD/MSTEAMS_TENANT_ID)";
|
||||
}
|
||||
if (classification.errorCode === "ContentStreamNotAllowed") {
|
||||
return "Teams expired the content stream; stop streaming earlier and fall back to normal message delivery";
|
||||
}
|
||||
if (classification.kind === "throttled") {
|
||||
return "Teams throttled the bot; backing off may help";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user