mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-05-05 07:10:55 +00:00
fix(cli): pin /recap above input and align defaults with fastModel (#3478)
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
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
* fix(cli): pin /recap above input box and align defaults with fastModel The recap rendered as a regular history item, so as soon as the model streamed a new reply the "where you left off" reminder scrolled out of view. Move it to a sticky banner anchored just above the Composer (matching how btwItem is rendered) so it stays visible across turns. While reworking the surface, also: - Replace the chevron prefix with `※ recap:` so it reads as a labeled recap line instead of a generic dim message. - Mirror the placement in ScreenReaderAppLayout so screen-reader users see it in the same logical position. - Drop HistoryItemAwayRecap from the HistoryItemWithoutId union — it is no longer addItem-able, and leaving it in invited silent no-op bugs where addItem(awayRecap) would compile but render nothing. - Clear the banner on /clear, /reset, /new and on /resume into a different session, so a recap from a previous context doesn't bleed into a freshly started one. - Re-measure the controls box when the banner appears or disappears (its height changes by a couple of lines) so the main content area recomputes availableTerminalHeight and stays laid out correctly. Auto-trigger now defaults to "on iff fastModel is configured" rather than unconditionally on. Running an ambient background recap on the main coding model is too costly and slow to be a sane default; tying it to fastModel means the feature is silently opt-in for users who have set up a cheap fast model. An explicit `general.showSessionRecap` override still wins either way, and `/recap` itself is unaffected. Sharpen the slash-command description to match the new behavior. * fix(core): silence AbortSignal listener-leak warning in OpenAI pipeline Every chat.completions.create call wires up an abort listener on the incoming AbortSignal, and several layers — retryWithBackoff, the LoggingContentGenerator wrapper, the SDK's own internal stream/fetch plumbing — register their own listeners against the same signal. Five retry attempts plus those layers comfortably exceed Node's default 10-listener cap and produce a MaxListenersExceededWarning. With features that share or compose signals (e.g., recap + followup speculation firing on the same response cycle), even a higher cap gets blown past. The signals here are per-request and short-lived, so the accumulation is structural rather than a real memory leak — they get GC'd as soon as the request settles. setMaxListeners(0, signal) at the SDK boundary disables the warning for these specific signals only, without masking any genuine leak elsewhere in the process. Idempotent and confined to the one place where retry-bound API calls cross into the SDK. * fix(core): tighten recap to a single sentence within 80 chars The 1-3 sentence budget reliably wrapped onto two lines in the sticky banner above the input box, which made it visually heavy for what is supposed to be a glanceable reminder. Constrain the prompt to exactly one sentence with a hard 80-char cap, and merge the "high-level task + next step" rule into a single sentence instead of two adjacent ones. Also sweep the docs (settings, commands, design) so the user-facing copy and the internal design notes match the new format. * fix(cli): apply review feedback for recap PR Two issues from review: - The schema description for `general.showSessionRecap` still said "1-3 sentence summary" while the prompt, docs, and slash-command copy already say "one-line". Aligns the text in settingsSchema.ts and the regenerated VSCode JSON schema. - The /resume wrapper cleared the sticky recap synchronously, before the inner handler had a chance to discover that no session data was available. On a no-op resume the user would still lose the current recap. Make `useResumeCommand.handleResume` return Promise<boolean> reporting whether a session actually loaded, and only clear the recap on a confirmed switch. * fix(cli): default showSessionRecap to false and drop fastModel heuristic The earlier "enabled iff fastModel is configured" default made it hard for users to answer the simple question "is auto-recap on for me right now?" — the answer depended on a setting from a different category, and setting/unsetting fastModel silently changed recap behavior. Revert to a plain boolean with a conservative off-by-default: - Auto-trigger fires only when the user explicitly sets `general.showSessionRecap: true`. - Manual `/recap` keeps working regardless (that's a user-initiated call, not an ambient one). - Users never get ambient LLM calls billed to their main coding model without having opted in. Aligns settings.md, design doc, and the regenerated JSON schema.
This commit is contained in:
parent
4d1d430390
commit
52c7a3d0ed
21 changed files with 152 additions and 66 deletions
|
|
@ -329,9 +329,13 @@ const SETTINGS_SCHEMA = {
|
|||
label: 'Show Session Recap',
|
||||
category: 'General',
|
||||
requiresRestart: false,
|
||||
default: true,
|
||||
// Off by default — an ambient background LLM call isn't something
|
||||
// users should be opted into silently, especially when `fastModel`
|
||||
// is unset and the call would land on the main coding model.
|
||||
// Manual `/recap` works regardless.
|
||||
default: false,
|
||||
description:
|
||||
'Show a 1-3 sentence summary of where you left off when returning to the terminal after being away for 5+ minutes. Use /recap to trigger manually.',
|
||||
'Auto-show a one-line "where you left off" recap when returning to the terminal after being away for 5+ minutes. Off by default. Use /recap to trigger manually regardless of this setting.',
|
||||
showInDialog: true,
|
||||
},
|
||||
gitCoAuthor: {
|
||||
|
|
|
|||
|
|
@ -59,6 +59,8 @@ export const createMockCommandContext = (
|
|||
setBtwItem: vi.fn(),
|
||||
cancelBtw: vi.fn(),
|
||||
btwAbortControllerRef: { current: null },
|
||||
awayRecapItem: null,
|
||||
setAwayRecapItem: vi.fn(),
|
||||
isIdleRef: { current: true },
|
||||
loadHistory: vi.fn(),
|
||||
toggleVimEnabled: vi.fn(),
|
||||
|
|
|
|||
|
|
@ -570,7 +570,7 @@ export const AppContainer = (props: AppContainerProps) => {
|
|||
isResumeDialogOpen,
|
||||
openResumeDialog,
|
||||
closeResumeDialog,
|
||||
handleResume,
|
||||
handleResume: handleResumeInner,
|
||||
} = useResumeCommand({
|
||||
config,
|
||||
historyManager,
|
||||
|
|
@ -658,6 +658,8 @@ export const AppContainer = (props: AppContainerProps) => {
|
|||
btwItem,
|
||||
setBtwItem,
|
||||
cancelBtw,
|
||||
awayRecapItem,
|
||||
setAwayRecapItem,
|
||||
commandContext,
|
||||
shellConfirmationRequest,
|
||||
confirmationRequest,
|
||||
|
|
@ -679,6 +681,22 @@ export const AppContainer = (props: AppContainerProps) => {
|
|||
logger,
|
||||
);
|
||||
|
||||
// Wrap handleResume so the sticky recap from the previous session
|
||||
// doesn't carry over into the new one. Only clear after the inner
|
||||
// handler confirms a session was actually loaded — otherwise (no
|
||||
// session data, missing deps) we'd drop the current session's recap
|
||||
// for no reason.
|
||||
const handleResume = useCallback(
|
||||
async (sessionId: string): Promise<boolean> => {
|
||||
const switched = await handleResumeInner(sessionId);
|
||||
if (switched) {
|
||||
setAwayRecapItem(null);
|
||||
}
|
||||
return switched;
|
||||
},
|
||||
[handleResumeInner, setAwayRecapItem],
|
||||
);
|
||||
|
||||
// onDebugMessage should log to debug logfile, not update footer debugMessage
|
||||
const onDebugMessage = useCallback(
|
||||
(message: string) => {
|
||||
|
|
@ -1230,7 +1248,7 @@ export const AppContainer = (props: AppContainerProps) => {
|
|||
setControlsHeight(fullFooterMeasurement.height);
|
||||
}
|
||||
}
|
||||
}, [buffer, terminalWidth, terminalHeight]);
|
||||
}, [buffer, terminalWidth, terminalHeight, awayRecapItem, btwItem]);
|
||||
|
||||
// agentViewState is declared earlier (before handleFinalSubmit) so it
|
||||
// is available for input routing. Referenced here for layout computation.
|
||||
|
|
@ -1259,11 +1277,11 @@ export const AppContainer = (props: AppContainerProps) => {
|
|||
useBracketedPaste();
|
||||
|
||||
useAwaySummary({
|
||||
enabled: settings.merged.general?.showSessionRecap ?? true,
|
||||
enabled: settings.merged.general?.showSessionRecap ?? false,
|
||||
config,
|
||||
isFocused,
|
||||
isIdle: streamingState === StreamingState.Idle,
|
||||
addItem: historyManager.addItem,
|
||||
setAwayRecapItem,
|
||||
});
|
||||
|
||||
// Context file names computation
|
||||
|
|
@ -2083,6 +2101,8 @@ export const AppContainer = (props: AppContainerProps) => {
|
|||
btwItem,
|
||||
setBtwItem,
|
||||
cancelBtw,
|
||||
awayRecapItem,
|
||||
setAwayRecapItem,
|
||||
nightly,
|
||||
branchName,
|
||||
sessionStats,
|
||||
|
|
@ -2189,6 +2209,8 @@ export const AppContainer = (props: AppContainerProps) => {
|
|||
btwItem,
|
||||
setBtwItem,
|
||||
cancelBtw,
|
||||
awayRecapItem,
|
||||
setAwayRecapItem,
|
||||
nightly,
|
||||
branchName,
|
||||
sessionStats,
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ export const recapCommand: SlashCommand = {
|
|||
name: 'recap',
|
||||
kind: CommandKind.BUILT_IN,
|
||||
get description() {
|
||||
return t('Show a 1-3 sentence summary of where you left off');
|
||||
return t('Generate a one-line session recap now');
|
||||
},
|
||||
action: async (
|
||||
context: CommandContext,
|
||||
|
|
@ -65,7 +65,7 @@ export const recapCommand: SlashCommand = {
|
|||
type: 'away_recap',
|
||||
text: recap.text,
|
||||
};
|
||||
context.ui.addItem(item, Date.now());
|
||||
context.ui.setAwayRecapItem(item);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import type {
|
|||
HistoryItemWithoutId,
|
||||
HistoryItem,
|
||||
HistoryItemBtw,
|
||||
HistoryItemAwayRecap,
|
||||
ConfirmationRequest,
|
||||
} from '../types.js';
|
||||
import type { LoadedSettings } from '../../config/settings.js';
|
||||
|
|
@ -75,6 +76,10 @@ export interface CommandContext {
|
|||
cancelBtw: () => void;
|
||||
/** Ref to the btw AbortController, set by btwCommand so cancelBtw can abort it. */
|
||||
btwAbortControllerRef: MutableRefObject<AbortController | null>;
|
||||
/** The current away-recap item rendered as a sticky banner above the input box. */
|
||||
awayRecapItem: HistoryItemAwayRecap | null;
|
||||
/** Sets the away-recap item independently of the main history. */
|
||||
setAwayRecapItem: (item: HistoryItemAwayRecap | null) => void;
|
||||
/** Ref to whether the agent stream is currently idle (no model turn in flight). */
|
||||
isIdleRef: MutableRefObject<boolean>;
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ import {
|
|||
ErrorMessage,
|
||||
RetryCountdownMessage,
|
||||
SuccessMessage,
|
||||
AwayRecapMessage,
|
||||
} from './messages/StatusMessages.js';
|
||||
import { Box, Text } from 'ink';
|
||||
import { theme } from '../semantic-colors.js';
|
||||
|
|
@ -286,9 +285,6 @@ const HistoryItemDisplayComponent: React.FC<HistoryItemDisplayProps> = ({
|
|||
{itemForDisplay.type === 'memory_saved' && (
|
||||
<MemorySavedMessage item={itemForDisplay} />
|
||||
)}
|
||||
{itemForDisplay.type === 'away_recap' && (
|
||||
<AwayRecapMessage text={itemForDisplay.text} />
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ export const RetryCountdownMessage: React.FC<StatusTextProps> = ({ text }) => (
|
|||
export const AwayRecapMessage: React.FC<StatusTextProps> = ({ text }) => (
|
||||
<StatusMessage
|
||||
text={text}
|
||||
prefix="❯"
|
||||
prefix="※ recap:"
|
||||
prefixColor={theme.text.secondary}
|
||||
textColor={theme.text.secondary}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import { createContext, useContext } from 'react';
|
|||
import type {
|
||||
HistoryItem,
|
||||
HistoryItemBtw,
|
||||
HistoryItemAwayRecap,
|
||||
ThoughtSummary,
|
||||
ShellConfirmationRequest,
|
||||
ConfirmationRequest,
|
||||
|
|
@ -110,6 +111,8 @@ export interface UIState {
|
|||
btwItem: HistoryItemBtw | null;
|
||||
setBtwItem: (item: HistoryItemBtw | null) => void;
|
||||
cancelBtw: () => void;
|
||||
awayRecapItem: HistoryItemAwayRecap | null;
|
||||
setAwayRecapItem: (item: HistoryItemAwayRecap | null) => void;
|
||||
nightly: boolean;
|
||||
branchName: string | undefined;
|
||||
sessionStats: SessionStatsState;
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import type {
|
|||
Message,
|
||||
HistoryItemWithoutId,
|
||||
HistoryItemBtw,
|
||||
HistoryItemAwayRecap,
|
||||
SlashCommandProcessorResult,
|
||||
HistoryItem,
|
||||
ConfirmationRequest,
|
||||
|
|
@ -155,6 +156,9 @@ export const useSlashCommandProcessor = (
|
|||
const [btwItem, setBtwItem] = useState<HistoryItemBtw | null>(null);
|
||||
const btwAbortControllerRef = useRef<AbortController | null>(null);
|
||||
|
||||
const [awayRecapItem, setAwayRecapItem] =
|
||||
useState<HistoryItemAwayRecap | null>(null);
|
||||
|
||||
const cancelBtw = useCallback(() => {
|
||||
btwAbortControllerRef.current?.abort();
|
||||
btwAbortControllerRef.current = null;
|
||||
|
|
@ -268,6 +272,7 @@ export const useSlashCommandProcessor = (
|
|||
addItem,
|
||||
clear: () => {
|
||||
cancelBtw();
|
||||
setAwayRecapItem(null);
|
||||
clearItems();
|
||||
clearScreen();
|
||||
refreshStatic();
|
||||
|
|
@ -280,6 +285,8 @@ export const useSlashCommandProcessor = (
|
|||
setBtwItem,
|
||||
cancelBtw,
|
||||
btwAbortControllerRef,
|
||||
awayRecapItem,
|
||||
setAwayRecapItem,
|
||||
isIdleRef,
|
||||
toggleVimEnabled,
|
||||
setGeminiMdFileCount,
|
||||
|
|
@ -312,6 +319,8 @@ export const useSlashCommandProcessor = (
|
|||
btwItem,
|
||||
setBtwItem,
|
||||
cancelBtw,
|
||||
awayRecapItem,
|
||||
setAwayRecapItem,
|
||||
toggleVimEnabled,
|
||||
sessionShellAllowlist,
|
||||
setGeminiMdFileCount,
|
||||
|
|
@ -785,6 +794,8 @@ export const useSlashCommandProcessor = (
|
|||
btwItem,
|
||||
setBtwItem,
|
||||
cancelBtw,
|
||||
awayRecapItem,
|
||||
setAwayRecapItem,
|
||||
commandContext,
|
||||
shellConfirmationRequest,
|
||||
confirmationRequest,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { generateSessionRecap, type Config } from '@qwen-code/qwen-code-core';
|
||||
import type { HistoryItemAwayRecap, HistoryItemWithoutId } from '../types.js';
|
||||
import type { HistoryItemAwayRecap } from '../types.js';
|
||||
|
||||
const AWAY_THRESHOLD_MS = 5 * 60 * 1000;
|
||||
|
||||
|
|
@ -15,7 +15,7 @@ export interface UseAwaySummaryOptions {
|
|||
config: Config | null;
|
||||
isFocused: boolean;
|
||||
isIdle: boolean;
|
||||
addItem: (item: HistoryItemWithoutId, baseTimestamp: number) => number;
|
||||
setAwayRecapItem: (item: HistoryItemAwayRecap | null) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -27,7 +27,7 @@ export interface UseAwaySummaryOptions {
|
|||
* a single back-and-forth produces at most one recap.
|
||||
*/
|
||||
export function useAwaySummary(options: UseAwaySummaryOptions): void {
|
||||
const { enabled, config, isFocused, isIdle, addItem } = options;
|
||||
const { enabled, config, isFocused, isIdle, setAwayRecapItem } = options;
|
||||
|
||||
const blurredAtRef = useRef<number | null>(null);
|
||||
const recapPendingRef = useRef(false);
|
||||
|
|
@ -78,7 +78,7 @@ export function useAwaySummary(options: UseAwaySummaryOptions): void {
|
|||
type: 'away_recap',
|
||||
text: recap.text,
|
||||
};
|
||||
addItem(item, Date.now());
|
||||
setAwayRecapItem(item);
|
||||
})
|
||||
.finally(() => {
|
||||
if (inFlightRef.current === controller) {
|
||||
|
|
@ -86,7 +86,7 @@ export function useAwaySummary(options: UseAwaySummaryOptions): void {
|
|||
}
|
||||
recapPendingRef.current = false;
|
||||
});
|
||||
}, [enabled, config, isFocused, isIdle, addItem]);
|
||||
}, [enabled, config, isFocused, isIdle, setAwayRecapItem]);
|
||||
|
||||
useEffect(
|
||||
() => () => {
|
||||
|
|
|
|||
|
|
@ -25,7 +25,13 @@ export interface UseResumeCommandResult {
|
|||
isResumeDialogOpen: boolean;
|
||||
openResumeDialog: () => void;
|
||||
closeResumeDialog: () => void;
|
||||
handleResume: (sessionId: string) => void;
|
||||
/**
|
||||
* Resolves to `true` when the target session was actually loaded, or
|
||||
* `false` when the call short-circuited (missing dependencies or no
|
||||
* session data found). Callers can use the boolean to gate cleanup
|
||||
* that should only happen on a successful session switch.
|
||||
*/
|
||||
handleResume: (sessionId: string) => Promise<boolean>;
|
||||
}
|
||||
|
||||
export function useResumeCommand(
|
||||
|
|
@ -44,9 +50,9 @@ export function useResumeCommand(
|
|||
const { config, historyManager, startNewSession, remount } = options ?? {};
|
||||
|
||||
const handleResume = useCallback(
|
||||
async (sessionId: string) => {
|
||||
async (sessionId: string): Promise<boolean> => {
|
||||
if (!config || !historyManager || !startNewSession) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Close dialog immediately to prevent input capture during async operations.
|
||||
|
|
@ -57,7 +63,7 @@ export function useResumeCommand(
|
|||
const sessionData = await sessionService.loadSession(sessionId);
|
||||
|
||||
if (!sessionData) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Start new session in UI context.
|
||||
|
|
@ -87,6 +93,7 @@ export function useResumeCommand(
|
|||
|
||||
// Refresh terminal UI.
|
||||
remount?.();
|
||||
return true;
|
||||
},
|
||||
[closeResumeDialog, config, historyManager, startNewSession, remount],
|
||||
);
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import { DialogManager } from '../components/DialogManager.js';
|
|||
import { Composer } from '../components/Composer.js';
|
||||
import { ExitWarning } from '../components/ExitWarning.js';
|
||||
import { BtwMessage } from '../components/messages/BtwMessage.js';
|
||||
import { AwayRecapMessage } from '../components/messages/StatusMessages.js';
|
||||
import { AgentTabBar } from '../components/agent-view/AgentTabBar.js';
|
||||
import { AgentChatView } from '../components/agent-view/AgentChatView.js';
|
||||
import { AgentComposer } from '../components/agent-view/AgentComposer.js';
|
||||
|
|
@ -69,6 +70,11 @@ export const DefaultAppLayout: React.FC = () => {
|
|||
</Box>
|
||||
) : (
|
||||
<>
|
||||
{uiState.awayRecapItem && (
|
||||
<Box marginX={2} width={uiState.mainAreaWidth}>
|
||||
<AwayRecapMessage text={uiState.awayRecapItem.text} />
|
||||
</Box>
|
||||
)}
|
||||
{uiState.btwItem && (
|
||||
<Box marginX={2} width={uiState.mainAreaWidth}>
|
||||
<BtwMessage
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import { Composer } from '../components/Composer.js';
|
|||
import { Footer } from '../components/Footer.js';
|
||||
import { ExitWarning } from '../components/ExitWarning.js';
|
||||
import { BtwMessage } from '../components/messages/BtwMessage.js';
|
||||
import { AwayRecapMessage } from '../components/messages/StatusMessages.js';
|
||||
import { useUIState } from '../contexts/UIStateContext.js';
|
||||
|
||||
export const ScreenReaderAppLayout: React.FC = () => {
|
||||
|
|
@ -35,6 +36,11 @@ export const ScreenReaderAppLayout: React.FC = () => {
|
|||
</Box>
|
||||
) : (
|
||||
<>
|
||||
{uiState.awayRecapItem && (
|
||||
<Box marginX={2} width={uiState.mainAreaWidth}>
|
||||
<AwayRecapMessage text={uiState.awayRecapItem.text} />
|
||||
</Box>
|
||||
)}
|
||||
{uiState.btwItem && (
|
||||
<Box marginX={2} width={uiState.mainAreaWidth}>
|
||||
<BtwMessage
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ export function createNonInteractiveUI(): CommandContext['ui'] {
|
|||
setBtwItem: (_item) => {},
|
||||
cancelBtw: () => {},
|
||||
btwAbortControllerRef: { current: null },
|
||||
awayRecapItem: null,
|
||||
setAwayRecapItem: (_item) => {},
|
||||
isIdleRef: { current: true },
|
||||
toggleVimEnabled: async () => false,
|
||||
setGeminiMdFileCount: (_count) => {},
|
||||
|
|
|
|||
|
|
@ -390,8 +390,9 @@ export type HistoryItemBtw = HistoryItemBase & {
|
|||
|
||||
/**
|
||||
* Away-summary recap shown when the user returns to the session after a
|
||||
* period of inactivity (or via /recap). Rendered in dim color so it is
|
||||
* visually distinct from real assistant replies.
|
||||
* period of inactivity (or via /recap). Rendered as a sticky banner above
|
||||
* the input box (NOT part of the scrolling history), so it is intentionally
|
||||
* excluded from the HistoryItemWithoutId union.
|
||||
*/
|
||||
export type HistoryItemAwayRecap = HistoryItemBase & {
|
||||
type: 'away_recap';
|
||||
|
|
@ -483,7 +484,6 @@ export type HistoryItemWithoutId =
|
|||
| HistoryItemInsightProgress
|
||||
| HistoryItemBtw
|
||||
| HistoryItemMemorySaved
|
||||
| HistoryItemAwayRecap
|
||||
| HistoryItemUserPromptSubmitBlocked
|
||||
| HistoryItemStopHookLoop
|
||||
| HistoryItemStopHookSystemMessage
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue