fix(model): land #30932 auth-profile @ parsing for /model (@haosenwang1018)

Landed from contributor PR #30932 by @haosenwang1018.

Co-authored-by: haosenwang1018 <haosenwang1018@users.noreply.github.com>
This commit is contained in:
Peter Steinberger
2026-03-02 03:04:16 +00:00
parent 15c1c93a95
commit e4e5d9c98c
5 changed files with 19 additions and 7 deletions

View File

@@ -21,6 +21,7 @@ Docs: https://docs.openclaw.ai
### Fixes
- Model directives/Auth profiles: split `/model` profile suffixes at the first `@` after the last slash so email-based auth profile IDs (for example OAuth profile IDs) resolve correctly. Landed from contributor PR #30932 by @haosenwang1018. Thanks @haosenwang1018.
- Windows/Plugin install: avoid `spawn EINVAL` on Windows npm/npx invocations by resolving to `node` + npm CLI scripts instead of spawning `.cmd` directly. Landed from contributor PR #31147 by @codertony. Thanks @codertony.
- LINE/Voice transcription: classify M4A voice media as `audio/mp4` (not `video/mp4`) by checking the MPEG-4 `ftyp` major brand (`M4A ` / `M4B `), restoring voice transcription for LINE voice messages. Landed from contributor PR #31151 by @scoootscooob. Thanks @scoootscooob.
- Cron/Delivery mode none: send explicit `delivery: { mode: "none" }` from cron editor for both add and update flows so previous announce delivery is actually cleared. Landed from contributor PR #31145 by @byungsker. Thanks @byungsker.

View File

@@ -46,4 +46,11 @@ describe("splitTrailingAuthProfile", () => {
model: "provider/foo@bar/baz",
});
});
it("uses first @ after last slash for email-based auth profiles", () => {
expect(splitTrailingAuthProfile("flash@google-gemini-cli:test@gmail.com")).toEqual({
model: "flash",
profile: "google-gemini-cli:test@gmail.com",
});
});
});

View File

@@ -7,9 +7,9 @@ export function splitTrailingAuthProfile(raw: string): {
return { model: "" };
}
const profileDelimiter = trimmed.lastIndexOf("@");
const lastSlash = trimmed.lastIndexOf("/");
if (profileDelimiter <= 0 || profileDelimiter <= lastSlash) {
const profileDelimiter = trimmed.indexOf("@", lastSlash + 1);
if (profileDelimiter <= 0) {
return { model: trimmed };
}

View File

@@ -1775,10 +1775,14 @@ describe("createTelegramBot", () => {
});
expect(sendMessageSpy.mock.calls.length).toBeGreaterThan(1);
for (const call of sendMessageSpy.mock.calls) {
expect((call[2] as { reply_to_message_id?: number } | undefined)?.reply_to_message_id).toBe(
messageId,
);
for (const [index, call] of sendMessageSpy.mock.calls.entries()) {
const actual = (call[2] as { reply_to_message_id?: number } | undefined)
?.reply_to_message_id;
if (mode === "all" || index === 0) {
expect(actual).toBe(messageId);
} else {
expect(actual).toBeUndefined();
}
}
}
});

View File

@@ -294,7 +294,7 @@ export async function deliverReplies(params: {
replyMarkup,
});
}
if (replyToMessageIdForPayload && !hasReplied) {
if (replyToMessageId && !hasReplied) {
hasReplied = true;
}
continue;