Compare commits

..

No commits in common. "5823fbfa7297ee8505b448547da1f97b39debbc3" and "1166a65505166a6010a6ed6b596667ef794a2f3b" have entirely different histories.

3 changed files with 1 additions and 52 deletions

View File

@ -883,32 +883,7 @@ export const PromptInputTextarea = ({
if (!submitOnEnter) { if (!submitOnEnter) {
return; return;
} }
if (e.shiftKey || e.ctrlKey || e.metaKey) { if (e.shiftKey || e.ctrlKey || e.metaKey) {
// Keep newline behavior explicit for modified-Enter combos.
// This avoids accidental submit shortcuts swallowing Ctrl/Cmd+Enter.
if (e.ctrlKey || e.metaKey) {
e.preventDefault();
const target = e.currentTarget;
const start = target.selectionStart ?? target.value.length;
const end = target.selectionEnd ?? target.value.length;
const nextValue =
target.value.slice(0, start) + "\n" + target.value.slice(end);
if (controller) {
controller.textInput.setInput(nextValue);
} else {
target.value = nextValue;
const inputEvent = new Event("input", { bubbles: true });
target.dispatchEvent(inputEvent);
}
// Place caret right after the inserted newline.
requestAnimationFrame(() => {
target.selectionStart = start + 1;
target.selectionEnd = start + 1;
});
}
return; return;
} }
e.preventDefault(); e.preventDefault();

View File

@ -43,7 +43,7 @@ export function WorkspaceHeader({ className }: { className?: string }) {
) : ( ) : (
<div className="text-primary ml-2 cursor-default font-serif"> <div className="text-primary ml-2 cursor-default font-serif">
{/* TODO: 测试标识 */} {/* TODO: 测试标识 */}
XClaw <span className="text-sm text-[#000000c5]">v3.2.4</span> XClaw <span className="text-sm text-[#000000c5]">v3.2.3</span>
</div> </div>
)} )}
<SidebarTrigger /> <SidebarTrigger />

View File

@ -49,12 +49,6 @@ export type LegacyThreadStreamOptions = {
const STREAM_ERROR_FALLBACK_MESSAGE = "Request failed."; const STREAM_ERROR_FALLBACK_MESSAGE = "Request failed.";
const STREAM_ERROR_TOAST_MESSAGE = "出现了某些错误。"; const STREAM_ERROR_TOAST_MESSAGE = "出现了某些错误。";
const STREAM_ERROR_TOAST_DEDUPE_WINDOW_MS = 2000; const STREAM_ERROR_TOAST_DEDUPE_WINDOW_MS = 2000;
const STREAM_CANCEL_PATTERNS = [
/\bcancellederror\b/i,
/\bcancelled\b/i,
/\bcanceled\b/i,
/\babort(?:ed|error)?\b/i,
];
function readMessageCandidate(value: unknown): string | null { function readMessageCandidate(value: unknown): string | null {
if (typeof value === "string" && value.trim()) { if (typeof value === "string" && value.trim()) {
@ -122,21 +116,6 @@ function getStreamErrorMessage(error: unknown): string {
return STREAM_ERROR_FALLBACK_MESSAGE; return STREAM_ERROR_FALLBACK_MESSAGE;
} }
function isStreamCancellation(error: unknown, message: string): boolean {
const direct =
typeof error === "object" &&
error !== null &&
"name" in error &&
typeof Reflect.get(error, "name") === "string"
? String(Reflect.get(error, "name"))
: "";
const candidates = [message, direct];
return candidates.some((value) =>
STREAM_CANCEL_PATTERNS.some((pattern) => pattern.test(value)),
);
}
function normalizeThreadId( function normalizeThreadId(
value: string | null | undefined, value: string | null | undefined,
): string | undefined { ): string | undefined {
@ -255,11 +234,6 @@ export function useThreadStream({
const showStreamErrorToast = useCallback((error: unknown) => { const showStreamErrorToast = useCallback((error: unknown) => {
const message = getStreamErrorMessage(error); const message = getStreamErrorMessage(error);
if (isStreamCancellation(error, message)) {
// Cancellation is expected when user presses "Stop" or stream disconnects.
console.info("[useThreadStream] stream cancelled:", message);
return;
}
const now = Date.now(); const now = Date.now();
const lastToast = lastErrorToastRef.current; const lastToast = lastErrorToastRef.current;
if ( if (