mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-04-28 11:41:04 +00:00
Some checks are pending
Qwen Code CI / Lint (push) Waiting to run
Qwen Code CI / Test (push) Blocked by required conditions
Qwen Code CI / Test-1 (push) Blocked by required conditions
Qwen Code CI / Test-2 (push) Blocked by required conditions
Qwen Code CI / Test-3 (push) Blocked by required conditions
Qwen Code CI / Test-4 (push) Blocked by required conditions
Qwen Code CI / Test-5 (push) Blocked by required conditions
Qwen Code CI / Test-6 (push) Blocked by required conditions
Qwen Code CI / Test-7 (push) Blocked by required conditions
Qwen Code CI / Test-8 (push) Blocked by required conditions
Qwen Code CI / Post Coverage Comment (push) Blocked by required conditions
Qwen Code CI / CodeQL (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none (push) Waiting to run
E2E Tests / E2E Test - macOS (push) Waiting to run
* feat(cli): combine elapsed + timeout in shell time indicator Render shell tools that have an explicit timeout as `(elapsed · timeout N)` inline with the Running… status from t=0, instead of splitting the information across the right-aligned elapsed indicator and the ShellStatsBar row. - formatters: add a `hideTrailingZeros` option so whole seconds render as `5s` rather than `5.0s` while fractional values like `5.5s` stay intact - ToolElapsedTime: accept optional `timeoutMs`; when set, skip the 3s quiet threshold and render the combined `(elapsed · timeout N)` label - ToolMessage: extract `timeoutMs` from AnsiOutputDisplay and feed it to ToolElapsedTime - ShellStatsBar: drop its `timeoutMs` field (now inline); keeps `+N lines` and memory usage only - Unify both modes on `formatDuration` so hour-range output is consistent (`1h 2m 6s` across timeout and no-timeout paths) * feat(cli): thread shell timeoutMs through compact tool group display The combined `(elapsed · timeout N)` format introduced in the previous commit was only wired through the expanded ToolMessage path. Compact tool groups kept rendering ToolElapsedTime without timeoutMs, so shell tools displayed in compact mode silently dropped the timeout budget. - CompactToolGroupDisplay: add getShellTimeoutMs() to pull timeoutMs off the active tool's AnsiOutputDisplay result (same shape used by ToolMessage) and feed it to ToolElapsedTime - add CompactToolGroupDisplay.test.tsx covering the three paths: ansi display with timeoutMs, ansi display without timeoutMs, and non-ansi resultDisplay (string)
93 lines
2.6 KiB
TypeScript
93 lines
2.6 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright 2025 Qwen
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
import { render } from 'ink-testing-library';
|
|
import { Text } from 'ink';
|
|
import { CompactToolGroupDisplay } from './CompactToolGroupDisplay.js';
|
|
import { ToolCallStatus } from '../../types.js';
|
|
import type { IndividualToolCallDisplay } from '../../types.js';
|
|
|
|
// ToolStatusIndicator pulls in GeminiRespondingSpinner which requires
|
|
// StreamingContext; stub it out so we can test the elapsed/timeout
|
|
// plumbing in isolation.
|
|
vi.mock('../shared/ToolStatusIndicator.js', () => ({
|
|
ToolStatusIndicator: () => <Text>•</Text>,
|
|
STATUS_INDICATOR_WIDTH: 2,
|
|
}));
|
|
|
|
const NOW = 1_700_000_000_000;
|
|
|
|
function shellTool(
|
|
overrides: Partial<IndividualToolCallDisplay> = {},
|
|
): IndividualToolCallDisplay {
|
|
return {
|
|
callId: 'c1',
|
|
name: 'Shell',
|
|
description: 'sleep 10',
|
|
status: ToolCallStatus.Executing,
|
|
executionStartTime: NOW,
|
|
resultDisplay: undefined,
|
|
confirmationDetails: undefined,
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
describe('<CompactToolGroupDisplay />', () => {
|
|
beforeEach(() => {
|
|
vi.useFakeTimers();
|
|
vi.setSystemTime(NOW);
|
|
});
|
|
|
|
afterEach(() => {
|
|
vi.useRealTimers();
|
|
});
|
|
|
|
it('surfaces shell timeoutMs inline via ToolElapsedTime', () => {
|
|
const tool = shellTool({
|
|
resultDisplay: {
|
|
ansiOutput: [],
|
|
totalLines: 0,
|
|
totalBytes: 0,
|
|
timeoutMs: 30_000,
|
|
},
|
|
});
|
|
const { lastFrame } = render(
|
|
<CompactToolGroupDisplay toolCalls={[tool]} contentWidth={80} />,
|
|
);
|
|
expect(lastFrame()).toContain('(0s · timeout 30s)');
|
|
});
|
|
|
|
it('falls back to quiet elapsed-only when no timeout is surfaced', () => {
|
|
const tool = shellTool({
|
|
resultDisplay: {
|
|
ansiOutput: [],
|
|
totalLines: 0,
|
|
totalBytes: 0,
|
|
},
|
|
});
|
|
const { lastFrame } = render(
|
|
<CompactToolGroupDisplay toolCalls={[tool]} contentWidth={80} />,
|
|
);
|
|
// Sub-3s without a timeout budget → indicator is quiet.
|
|
expect(lastFrame()).not.toContain('timeout');
|
|
expect(lastFrame()).not.toContain('0s');
|
|
});
|
|
|
|
it('ignores non-ansi resultDisplay shapes', () => {
|
|
const tool = shellTool({
|
|
resultDisplay: 'plain text output',
|
|
});
|
|
const { lastFrame, rerender } = render(
|
|
<CompactToolGroupDisplay toolCalls={[tool]} contentWidth={80} />,
|
|
);
|
|
vi.advanceTimersByTime(5_000);
|
|
rerender(<CompactToolGroupDisplay toolCalls={[tool]} contentWidth={80} />);
|
|
// No timeout in display → legacy 3s-threshold elapsed.
|
|
expect(lastFrame()).toContain('5s');
|
|
expect(lastFrame()).not.toContain('timeout');
|
|
});
|
|
});
|