mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-05-05 15:31:27 +00:00
feat(cli): add Ctrl+Y shortcut to retry failed requests (#2011)
* feat: add Ctrl+Y shortcut to retry failed requests
- Add Ctrl+Y keyboard shortcut for retrying the last failed request
- Add isNetworkError() to detect transient network failures (ECONNREFUSED, ETIMEDOUT, etc.)
- Add DashScope 1305 error code to rate limit detection
- Add error hint \"Press Ctrl+Y to retry\" in error messages
- Support user-defined error codes for retry via config
- Add retryLastPrompt() hook in useGeminiStream
- Update keyboard shortcuts documentation
* feat: improve Ctrl+Y retry feature with tests, docs, and rate limit config
- Add comprehensive tests for Ctrl+Y retry shortcut in InputPrompt
- Add unit tests for retryLastPrompt in useGeminiStream hook
- Add detailed JSDoc comments for retryLastPrompt function and Ctrl+Y shortcut
- Extend isRateLimitError to support custom error codes via retryErrorCodes config
- Fix rate limit retry log variable reference (RATE_LIMIT_RETRY_OPTIONS → maxRateLimitRetries)
- Add Eclipse IDE files to .gitignore
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* refactor(ui): consolidate retry countdown as inline hint in error messages
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* feat(cli): enhance error handling with improved retry mechanism
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
- Modify ErrorMessage component to remove dim color from hint text
- Update useGeminiStream hook to improve retry countdown behavior with option to preserve or clear hints
- Adjust tests to match new error handling implementation
* feat: add Ctrl+Y shortcut to retry the last failed request
When a request errors out, the error message shows an inline hint
"(Press Ctrl+Y to retry.)" in secondary color. Pressing Ctrl+Y
re-submits the same prompt, commits the error text to history
(without the hint), and clears the hint from the UI.
- Add retryLastPrompt action wired to Ctrl+Y via keyBindings and InputPrompt
- Track last submitted prompt and error state in useGeminiStream refs
- Show retry hint inline with error text in ErrorMessage component,
wrapping naturally on narrow terminals while preserving hint color
- Expose retryLastPrompt through UIActionsContext
- Add keyboard shortcut entry in KeyboardShortcuts display
- Add i18n strings for hint and no-retry-available message
- Document Ctrl+Y in keyboard-shortcuts.md
* docs(configuration): Update model provider configuration document
* chore: remove YOLO mode code from core
* fix: prevent Ctrl+Y hint from overriding auto-retry countdown
When an auto-retry countdown is active (retryCountdownTimerRef is set),
handleErrorEvent should not overwrite it with the Ctrl+Y hint. The auto-retry
hint ("retrying in Xs...") and manual retry hint ("Press Ctrl+Y to retry.")
are mutually exclusive:
- Auto-retry errors (e.g., rate limits): show countdown hint
- Other errors: show Ctrl+Y hint
Also removed retryErrorCodes from ContentGeneratorConfig as it's not part
of the minimal Ctrl+Y feature scope.
* simplify: remove complex options from clearRetryCountdown
Revert clearRetryCountdown to simplest form without options parameter.
The function now just clears the timer and pending item without any
automatic history commit logic.
* fix: restore pendingRetryCountdownItem as separate state from pendingRetryErrorItem
Auto-retry countdown and manual retry hint are now independent:
- pendingRetryErrorItem: displays error message with optional hint
- pendingRetryCountdownItem: displays separate countdown line for auto-retry
This ensures both can be shown simultaneously without overriding each other.
* fix: restore RetryCountdownMessage rendering in HistoryItemDisplay
The retry_countdown type should be rendered as a separate message,
not inline in ErrorMessage. This allows auto-retry countdown and
manual retry hint to coexist properly.
* fix(cli): properly commit retry error item to history before clearing
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* fix(cli): remove trailing period from retry hint translations
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Remove unnecessary period from 'Press Ctrl+Y to retry' translation strings in both en.js and zh.js locales. Also update the corresponding usage in useGeminiStream hook.
* chore(sdk-java): add Eclipse project configuration files
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Add .project configuration files for client and qwencode modules to support Eclipse IDE development environment.
* feat(cli): add retry countdown hint to error message
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
* Revert "chore(sdk-java): add Eclipse project configuration files"
This reverts commit da83b5e571.
---------
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
parent
6fdd715458
commit
c353fbbfa3
18 changed files with 355 additions and 76 deletions
|
|
@ -2304,40 +2304,30 @@ describe('useGeminiStream', () => {
|
|||
result.current.pendingHistoryItems.find(
|
||||
(item) => item.type === MessageType.ERROR,
|
||||
);
|
||||
const findCountdownItem = () =>
|
||||
result.current.pendingHistoryItems.find(
|
||||
(item) => item.type === 'retry_countdown',
|
||||
);
|
||||
|
||||
let errorItem = findErrorItem();
|
||||
let countdownItem = findCountdownItem();
|
||||
for (
|
||||
let attempts = 0;
|
||||
attempts < 5 && (!errorItem || !countdownItem);
|
||||
attempts++
|
||||
) {
|
||||
for (let attempts = 0; attempts < 5 && !errorItem; attempts++) {
|
||||
await act(async () => {
|
||||
await Promise.resolve();
|
||||
});
|
||||
errorItem = findErrorItem();
|
||||
countdownItem = findCountdownItem();
|
||||
}
|
||||
|
||||
// Error line should be rendered as ERROR type (wrapped by parseAndFormatApiError)
|
||||
// Error item should contain the error text and a retry hint
|
||||
expect(errorItem?.text).toContain('Rate limit exceeded');
|
||||
|
||||
// Countdown line should be rendered as retry_countdown type
|
||||
expect(countdownItem?.text).toContain('Retrying in 3 seconds');
|
||||
// Countdown hint should be inline on the error item (not a separate item)
|
||||
expect((errorItem as { hint?: string })?.hint).toContain('3s');
|
||||
expect((errorItem as { hint?: string })?.hint).toContain('attempt 1/3');
|
||||
|
||||
await act(async () => {
|
||||
await vi.advanceTimersByTimeAsync(1000);
|
||||
});
|
||||
|
||||
const countdownAfterOneSecond = result.current.pendingHistoryItems.find(
|
||||
(item) => item.type === 'retry_countdown',
|
||||
const errorAfterOneSecond = result.current.pendingHistoryItems.find(
|
||||
(item) => item.type === MessageType.ERROR,
|
||||
);
|
||||
expect(countdownAfterOneSecond?.text).toContain(
|
||||
'Retrying in 2 seconds',
|
||||
expect((errorAfterOneSecond as { hint?: string })?.hint).toContain(
|
||||
'2s',
|
||||
);
|
||||
|
||||
resolveStream?.();
|
||||
|
|
@ -2347,15 +2337,11 @@ describe('useGeminiStream', () => {
|
|||
await vi.runAllTimersAsync();
|
||||
});
|
||||
|
||||
// Both error and countdown should be cleared after retry succeeds
|
||||
// Error item (with hint) should be cleared after retry succeeds
|
||||
const remainingError = result.current.pendingHistoryItems.find(
|
||||
(item) => item.type === MessageType.ERROR,
|
||||
);
|
||||
const remainingCountdown = result.current.pendingHistoryItems.find(
|
||||
(item) => item.type === 'retry_countdown',
|
||||
);
|
||||
expect(remainingError).toBeUndefined();
|
||||
expect(remainingCountdown).toBeUndefined();
|
||||
} finally {
|
||||
vi.useRealTimers();
|
||||
}
|
||||
|
|
@ -2525,14 +2511,13 @@ describe('useGeminiStream', () => {
|
|||
await result.current.submitQuery('Test query');
|
||||
});
|
||||
|
||||
// Verify error message was added
|
||||
// Verify error message appears in pending history items (not via addItem,
|
||||
// since errors with retry hints are now stored as pending items)
|
||||
await waitFor(() => {
|
||||
expect(mockAddItem).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
type: 'error',
|
||||
}),
|
||||
expect.any(Number),
|
||||
const errorItem = result.current.pendingHistoryItems.find(
|
||||
(item) => item.type === 'error',
|
||||
);
|
||||
expect(errorItem).toBeDefined();
|
||||
});
|
||||
|
||||
// Verify parseAndFormatApiError was called
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue