feat(chat): add final answer only activity display mode (#5706, picker grid fixed)
Clean rebase of rodboev's #5746 (rebase-first). Co-authored-by: rodboev <rodboev@users.noreply.github.com>
This commit is contained in:
1 parent
c3ff9f41c7
commit
2717ea0ac5
11 files changed
+465
-43
No files matched your search
+2
-2
@@ -8198,7 +8198,7 @@ _SETTINGS_DEFAULTS = {
|
||||
"structured_code_default_view": "auto", # JSON/YAML fenced-block default render: auto | on | off (#484 follow-up). auto => Tree when line count >= structured_code_auto_tree_lines, else Raw.
|
||||
"structured_code_auto_tree_lines": 10, # in 'auto' mode, minimum line count to default a JSON/YAML block to Tree view (preserves the original hardcoded >=10 behavior)
|
||||
"session_endless_scroll": False, # auto-load older transcript pages while scrolling upward
|
||||
"chat_activity_display_mode": "compact_worklog", # compact_worklog | transparent_stream
|
||||
"chat_activity_display_mode": "compact_worklog", # compact_worklog | transparent_stream | hide_all_activity
|
||||
"auto_scroll_follow": True, # follow new output to the bottom while streaming (Codex/Claude-Code-style sticky bottom); the user scrolling up unpins and is respected
|
||||
"worklog_details_expanded_default": False, # opt-in: expand Worklog details by default; default remains folded
|
||||
"hide_composer_attach": False, # hide attach button in composer footer
|
||||
@@ -8459,7 +8459,7 @@ _SETTINGS_ENUM_VALUES = {
|
||||
"font_size": {"small", "default", "large", "xlarge"},
|
||||
"auto_title_refresh_every": {"0", "5", "10", "20"},
|
||||
"default_message_mode": {"queue", "interrupt", "steer"},
|
||||
"chat_activity_display_mode": {"compact_worklog", "transparent_stream"},
|
||||
"chat_activity_display_mode": {"compact_worklog", "transparent_stream", "hide_all_activity"},
|
||||
"structured_code_default_view": {"auto", "on", "off"},
|
||||
}
|
||||
_SETTINGS_INT_RANGES = {
|
||||
|
||||
@@ -178,6 +178,12 @@
|
||||
return typeof value==='string'?value.trim():'';
|
||||
}
|
||||
|
||||
function _activityDisplayMode(value){
|
||||
return value==='transparent_stream'||value==='compact_worklog'||value==='hide_all_activity'
|
||||
? value
|
||||
: 'compact_worklog';
|
||||
}
|
||||
|
||||
function _terminalStateKey(value){
|
||||
return _cleanString(value).toLowerCase().replace(/[\s-]+/g,'_');
|
||||
}
|
||||
@@ -1013,7 +1019,7 @@
|
||||
const anchor=_anchorFromProjectionInput(input);
|
||||
const opts=(options&&typeof options==='object')?options:{};
|
||||
const requestedMode=_cleanString(_own(opts,'mode'));
|
||||
const mode=requestedMode==='transparent_stream'?'transparent_stream':'compact_worklog';
|
||||
const mode=_activityDisplayMode(requestedMode);
|
||||
if(!anchor){
|
||||
return Object.freeze({
|
||||
version:'activity_scene_v1',
|
||||
@@ -1319,7 +1325,7 @@
|
||||
const item=(input&&typeof input==='object')?input:{};
|
||||
const opts=(options&&typeof options==='object')?options:{};
|
||||
const requested=_cleanString(_own(item,'mode'))||_cleanString(_own(opts,'mode'));
|
||||
return requested==='transparent_stream'?'transparent_stream':'compact_worklog';
|
||||
return _activityDisplayMode(requested);
|
||||
}
|
||||
|
||||
function _rendererSnapshotRowsInput(input, options){
|
||||
|
||||
+3
-1
@@ -2901,7 +2901,9 @@ window._mirrorSpeechSettingsFromServer=_mirrorSpeechSettingsFromServer;
|
||||
window._whatsNewSummaryEnabled=!!s.whats_new_summary_enabled;
|
||||
window._showThinking=s.show_thinking!==false;
|
||||
window._simplifiedToolCalling=true;
|
||||
window._chatActivityDisplayMode=s.chat_activity_display_mode==='transparent_stream'?'transparent_stream':'compact_worklog';
|
||||
window._chatActivityDisplayMode=s.chat_activity_display_mode==='transparent_stream'||s.chat_activity_display_mode==='hide_all_activity'
|
||||
? s.chat_activity_display_mode
|
||||
: 'compact_worklog';
|
||||
window._transparentStream=window._chatActivityDisplayMode==='transparent_stream';
|
||||
window._terminalAutoExpandOnOutput=!!s.terminal_auto_expand_on_output;
|
||||
window._worklogDetailsExpandedByDefault=!!(
|
||||
|
||||
+30
-15
@@ -635,7 +635,7 @@ const LOCALES = {
|
||||
settings_label_worklog_details_expanded_default: 'Open Worklog details automatically',
|
||||
settings_desc_worklog_details_expanded_default: 'When enabled, new Worklog details start expanded so tool, thinking, and progress cards are visible without an extra click. When off, Worklog details stay folded by default; per-turn manual collapse/expand choices still win.',
|
||||
settings_label_chat_activity_display_mode: 'Activity display',
|
||||
settings_desc_chat_activity_display_mode: 'Compact Worklog groups supporting activity into a quiet summary. Transparent Stream keeps each thinking/tool event as its own chronological expandable row.',
|
||||
settings_desc_chat_activity_display_mode: 'Compact Worklog groups supporting activity into a quiet summary. Transparent Stream keeps each thinking/tool event as its own chronological expandable row. Final answer only hides activity rows while keeping the final answer visible.',
|
||||
first_token_time: 'Time to first token',
|
||||
processed_elapsed: _i18nProcessedElapsedEn,
|
||||
worklog_thinking: 'Thinking',
|
||||
@@ -646,6 +646,7 @@ const LOCALES = {
|
||||
done: 'Done',
|
||||
settings_option_compact_worklog: 'Compact Worklog',
|
||||
settings_option_transparent_stream: 'Transparent Stream',
|
||||
settings_option_final_answer_only: 'Final answer only',
|
||||
|
||||
settings_label_tab_visibility: 'Sidebar tabs',
|
||||
settings_desc_tab_visibility: 'Choose which tabs appear in the sidebar and rail. Drag chips to reorder them. Chat and Settings are always visible.',
|
||||
@@ -2330,7 +2331,7 @@ const LOCALES = {
|
||||
settings_label_worklog_details_expanded_default: 'Open Worklog details automatically',
|
||||
settings_desc_worklog_details_expanded_default: 'When enabled, new Worklog details start expanded so tool, thinking, and progress cards are visible without an extra click. When off, Worklog details stay folded by default; per-turn manual collapse/expand choices still win.',
|
||||
settings_label_chat_activity_display_mode: 'Activity display',
|
||||
settings_desc_chat_activity_display_mode: 'Compact Worklog groups supporting activity into a quiet summary. Transparent Stream keeps each thinking/tool event as its own chronological expandable row.',
|
||||
settings_desc_chat_activity_display_mode: 'Compact Worklog groups supporting activity into a quiet summary. Transparent Stream keeps each thinking/tool event as its own chronological expandable row. Final answer only hides activity rows while keeping the final answer visible.',
|
||||
first_token_time: 'Time to first token',
|
||||
processed_elapsed: _i18nProcessedElapsedEn,
|
||||
worklog_thinking: 'Thinking',
|
||||
@@ -2341,6 +2342,7 @@ const LOCALES = {
|
||||
done: 'Done',
|
||||
settings_option_compact_worklog: 'Compact Worklog',
|
||||
settings_option_transparent_stream: 'Transparent Stream',
|
||||
settings_option_final_answer_only: 'Final answer only',
|
||||
|
||||
settings_label_tab_visibility: 'Schede della barra laterale',
|
||||
settings_desc_tab_visibility: 'Scegli quali schede mostrare nella barra laterale e nel rail. Chat e Impostazioni sono sempre visibili.',
|
||||
@@ -4016,7 +4018,7 @@ const LOCALES = {
|
||||
settings_label_worklog_details_expanded_default: 'Worklog の詳細を自動的に開く',
|
||||
settings_desc_worklog_details_expanded_default: '有効にすると、新しい Worklog の詳細が展開された状態で始まり、ツール、Thinking、進捗カードをクリックなしで確認できます。無効の場合、Worklog の詳細はデフォルトで折りたたまれます。ターンごとの手動折りたたみ/展開は優先されます。',
|
||||
settings_label_chat_activity_display_mode: 'アクティビティ表示',
|
||||
settings_desc_chat_activity_display_mode: '「コンパクトワークログ」はバックグラウンドアクティビティを簡潔なサマリーにまとめます。「トランスペアレントストリーム」は思考プロセスやツールの呼び出しイベントを、時系列順に展開可能な個別の行として表示し続けます。',
|
||||
settings_desc_chat_activity_display_mode: '「コンパクトワークログ」はバックグラウンドアクティビティを簡潔なサマリーにまとめます。「トランスペアレントストリーム」は思考プロセスやツールの呼び出しイベントを、時系列順に展開可能な個別の行として表示し続けます。 Final answer only hides activity rows while keeping the final answer visible.',
|
||||
first_token_time: '最初のトークン出力までの時間',
|
||||
processed_elapsed: _i18nProcessedElapsedEn,
|
||||
worklog_thinking: 'Thinking',
|
||||
@@ -4027,6 +4029,7 @@ const LOCALES = {
|
||||
done: '完了',
|
||||
settings_option_compact_worklog: 'コンパクトワークログ',
|
||||
settings_option_transparent_stream: 'トランスペアレントストリーム',
|
||||
settings_option_final_answer_only: 'Final answer only',
|
||||
|
||||
settings_label_tab_visibility: 'サイドバータブ',
|
||||
settings_desc_tab_visibility: 'サイドバーとレールに表示するタブを選択します。チャットと設定は常に表示されます。',
|
||||
@@ -6458,7 +6461,7 @@ const LOCALES = {
|
||||
settings_label_worklog_details_expanded_default: 'Open Worklog details automatically',
|
||||
settings_desc_worklog_details_expanded_default: 'When enabled, new Worklog details start expanded so tool, thinking, and progress cards are visible without an extra click. When off, Worklog details stay folded by default; per-turn manual collapse/expand choices still win.',
|
||||
settings_label_chat_activity_display_mode: 'Activity display',
|
||||
settings_desc_chat_activity_display_mode: 'Compact Worklog groups supporting activity into a quiet summary. Transparent Stream keeps each thinking/tool event as its own chronological expandable row.',
|
||||
settings_desc_chat_activity_display_mode: 'Compact Worklog groups supporting activity into a quiet summary. Transparent Stream keeps each thinking/tool event as its own chronological expandable row. Final answer only hides activity rows while keeping the final answer visible.',
|
||||
first_token_time: 'Time to first token',
|
||||
processed_elapsed: _i18nProcessedElapsedEn,
|
||||
worklog_thinking: 'Thinking',
|
||||
@@ -6469,6 +6472,7 @@ const LOCALES = {
|
||||
done: 'Done',
|
||||
settings_option_compact_worklog: 'Compact Worklog',
|
||||
settings_option_transparent_stream: 'Transparent Stream',
|
||||
settings_option_final_answer_only: 'Final answer only',
|
||||
|
||||
settings_label_tab_visibility: 'Вкладки боковой панели',
|
||||
settings_desc_tab_visibility: 'Выберите, какие вкладки отображаются на боковой панели и в рейле. Чат и настройки всегда видны.',
|
||||
@@ -8069,7 +8073,7 @@ const LOCALES = {
|
||||
settings_label_worklog_details_expanded_default: 'Open Worklog details automatically',
|
||||
settings_desc_worklog_details_expanded_default: 'When enabled, new Worklog details start expanded so tool, thinking, and progress cards are visible without an extra click. When off, Worklog details stay folded by default; per-turn manual collapse/expand choices still win.',
|
||||
settings_label_chat_activity_display_mode: 'Activity display',
|
||||
settings_desc_chat_activity_display_mode: 'Compact Worklog groups supporting activity into a quiet summary. Transparent Stream keeps each thinking/tool event as its own chronological expandable row.',
|
||||
settings_desc_chat_activity_display_mode: 'Compact Worklog groups supporting activity into a quiet summary. Transparent Stream keeps each thinking/tool event as its own chronological expandable row. Final answer only hides activity rows while keeping the final answer visible.',
|
||||
first_token_time: 'Time to first token',
|
||||
processed_elapsed: _i18nProcessedElapsedEn,
|
||||
worklog_thinking: 'Thinking',
|
||||
@@ -8080,6 +8084,7 @@ const LOCALES = {
|
||||
done: 'Done',
|
||||
settings_option_compact_worklog: 'Compact Worklog',
|
||||
settings_option_transparent_stream: 'Transparent Stream',
|
||||
settings_option_final_answer_only: 'Final answer only',
|
||||
|
||||
settings_label_tab_visibility: 'Pestañas de la barra lateral',
|
||||
settings_desc_tab_visibility: 'Elige qué pestañas aparecen en la barra lateral y el rail. Chat y Configuración siempre están visibles.',
|
||||
@@ -9361,7 +9366,7 @@ const LOCALES = {
|
||||
settings_label_worklog_details_expanded_default: 'Open Worklog details automatically',
|
||||
settings_desc_worklog_details_expanded_default: 'When enabled, new Worklog details start expanded so tool, thinking, and progress cards are visible without an extra click. When off, Worklog details stay folded by default; per-turn manual collapse/expand choices still win.',
|
||||
settings_label_chat_activity_display_mode: 'Activity display',
|
||||
settings_desc_chat_activity_display_mode: 'Compact Worklog groups supporting activity into a quiet summary. Transparent Stream keeps each thinking/tool event as its own chronological expandable row.',
|
||||
settings_desc_chat_activity_display_mode: 'Compact Worklog groups supporting activity into a quiet summary. Transparent Stream keeps each thinking/tool event as its own chronological expandable row. Final answer only hides activity rows while keeping the final answer visible.',
|
||||
first_token_time: 'Time to first token',
|
||||
processed_elapsed: _i18nProcessedElapsedEn,
|
||||
worklog_thinking: 'Thinking',
|
||||
@@ -9372,6 +9377,7 @@ const LOCALES = {
|
||||
done: 'Done',
|
||||
settings_option_compact_worklog: 'Compact Worklog',
|
||||
settings_option_transparent_stream: 'Transparent Stream',
|
||||
settings_option_final_answer_only: 'Final answer only',
|
||||
|
||||
settings_label_tab_visibility: 'Seitenleiste-Tabs',
|
||||
settings_desc_tab_visibility: 'Wähle, welche Tabs in der Seitenleiste und im Rail angezeigt werden. Ziehe die Chips, um die Reihenfolge zu ändern. Chat und Einstellungen sind immer sichtbar.',
|
||||
@@ -11326,7 +11332,7 @@ const LOCALES = {
|
||||
settings_label_worklog_details_expanded_default: '自动打开工作日志详情',
|
||||
settings_desc_worklog_details_expanded_default: '当启用此功能时,新的工作日志详情会自动展开,因此无需额外点击即可查看工具、思路和进度卡片。当禁用此功能时,工作日志详情默认保持折叠状态;不过每次仍可手动选择折叠或展开。',
|
||||
settings_label_chat_activity_display_mode: '活动显示',
|
||||
settings_desc_chat_activity_display_mode: '紧凑的工作日志将支持活动归纳为简洁摘要。透明流模式则将每个思考/工具使用事件按时间顺序单独列为可展开的行。',
|
||||
settings_desc_chat_activity_display_mode: '紧凑的工作日志将支持活动归纳为简洁摘要。透明流模式则将每个思考/工具使用事件按时间顺序单独列为可展开的行。 Final answer only hides activity rows while keeping the final answer visible.',
|
||||
first_token_time: '首个令牌生成时间',
|
||||
processed_elapsed: _i18nProcessedElapsedZh,
|
||||
worklog_thinking: '正在思考',
|
||||
@@ -11337,6 +11343,7 @@ const LOCALES = {
|
||||
done: '完成',
|
||||
settings_option_compact_worklog: '紧凑工作日志',
|
||||
settings_option_transparent_stream: '透明流模式',
|
||||
settings_option_final_answer_only: 'Final answer only',
|
||||
|
||||
settings_label_tab_visibility: '侧边栏标签',
|
||||
settings_desc_tab_visibility: '选择在侧边栏和导航栏中显示哪些标签。聊天和设置始终可见。',
|
||||
@@ -12195,7 +12202,7 @@ const LOCALES = {
|
||||
settings_label_worklog_details_expanded_default: 'Open Worklog details automatically',
|
||||
settings_desc_worklog_details_expanded_default: 'When enabled, new Worklog details start expanded so tool, thinking, and progress cards are visible without an extra click. When off, Worklog details stay folded by default; per-turn manual collapse/expand choices still win.',
|
||||
settings_label_chat_activity_display_mode: 'Activity display',
|
||||
settings_desc_chat_activity_display_mode: 'Compact Worklog groups supporting activity into a quiet summary. Transparent Stream keeps each thinking/tool event as its own chronological expandable row.',
|
||||
settings_desc_chat_activity_display_mode: 'Compact Worklog groups supporting activity into a quiet summary. Transparent Stream keeps each thinking/tool event as its own chronological expandable row. Final answer only hides activity rows while keeping the final answer visible.',
|
||||
first_token_time: 'Time to first token',
|
||||
processed_elapsed: _i18nProcessedElapsedZhHant,
|
||||
worklog_thinking: '正在思考',
|
||||
@@ -12206,6 +12213,7 @@ const LOCALES = {
|
||||
done: 'Done',
|
||||
settings_option_compact_worklog: 'Compact Worklog',
|
||||
settings_option_transparent_stream: 'Transparent Stream',
|
||||
settings_option_final_answer_only: 'Final answer only',
|
||||
|
||||
settings_label_tab_visibility: '側邊欄標籤',
|
||||
settings_desc_tab_visibility: '選擇在側邊欄和導覽列中顯示哪些標籤。聊天和設定始終可見。',
|
||||
@@ -13778,7 +13786,7 @@ const LOCALES = {
|
||||
settings_label_worklog_details_expanded_default: 'Open Worklog details automatically',
|
||||
settings_desc_worklog_details_expanded_default: 'When enabled, new Worklog details start expanded so tool, thinking, and progress cards are visible without an extra click. When off, Worklog details stay folded by default; per-turn manual collapse/expand choices still win.',
|
||||
settings_label_chat_activity_display_mode: 'Activity display',
|
||||
settings_desc_chat_activity_display_mode: 'Compact Worklog groups supporting activity into a quiet summary. Transparent Stream keeps each thinking/tool event as its own chronological expandable row.',
|
||||
settings_desc_chat_activity_display_mode: 'Compact Worklog groups supporting activity into a quiet summary. Transparent Stream keeps each thinking/tool event as its own chronological expandable row. Final answer only hides activity rows while keeping the final answer visible.',
|
||||
first_token_time: 'Time to first token',
|
||||
processed_elapsed: _i18nProcessedElapsedEn,
|
||||
worklog_thinking: 'Thinking',
|
||||
@@ -13789,6 +13797,7 @@ const LOCALES = {
|
||||
done: 'Done',
|
||||
settings_option_compact_worklog: 'Compact Worklog',
|
||||
settings_option_transparent_stream: 'Transparent Stream',
|
||||
settings_option_final_answer_only: 'Final answer only',
|
||||
|
||||
settings_label_tab_visibility: 'Abas da barra lateral',
|
||||
settings_desc_tab_visibility: 'Escolha quais abas aparecem na barra lateral e no rail. Chat e Configurações estão sempre visíveis.',
|
||||
@@ -15363,7 +15372,7 @@ const LOCALES = {
|
||||
settings_label_worklog_details_expanded_default: 'Open Worklog details automatically',
|
||||
settings_desc_worklog_details_expanded_default: 'When enabled, new Worklog details start expanded so tool, thinking, and progress cards are visible without an extra click. When off, Worklog details stay folded by default; per-turn manual collapse/expand choices still win.',
|
||||
settings_label_chat_activity_display_mode: 'Activity display',
|
||||
settings_desc_chat_activity_display_mode: 'Compact Worklog groups supporting activity into a quiet summary. Transparent Stream keeps each thinking/tool event as its own chronological expandable row.',
|
||||
settings_desc_chat_activity_display_mode: 'Compact Worklog groups supporting activity into a quiet summary. Transparent Stream keeps each thinking/tool event as its own chronological expandable row. Final answer only hides activity rows while keeping the final answer visible.',
|
||||
first_token_time: 'Time to first token',
|
||||
processed_elapsed: _i18nProcessedElapsedEn,
|
||||
worklog_thinking: 'Thinking',
|
||||
@@ -15374,6 +15383,7 @@ const LOCALES = {
|
||||
done: 'Done',
|
||||
settings_option_compact_worklog: 'Compact Worklog',
|
||||
settings_option_transparent_stream: 'Transparent Stream',
|
||||
settings_option_final_answer_only: 'Final answer only',
|
||||
|
||||
settings_label_tab_visibility: '사이드바 탭',
|
||||
settings_desc_tab_visibility: '사이드바와 레일에 표시할 탭을 선택하세요. 채팅과 설정은 항상 표시됩니다.',
|
||||
@@ -17061,7 +17071,7 @@ const LOCALES = {
|
||||
settings_label_worklog_details_expanded_default: 'Ouvrir automatiquement les détails du journal de travail',
|
||||
settings_desc_worklog_details_expanded_default: 'Lorsqu\'il est activé, les nouveaux détails du journal de travail commencent développés, de sorte que les cartes d\'outils, de réflexion et de progression soient visibles sans clic supplémentaire. Lorsqu\'il est désactivé, les détails du journal de travail restent repliés par défaut ; les choix manuels de réduction/développement par tour prévalent.',
|
||||
settings_label_chat_activity_display_mode: 'Affichage des activités',
|
||||
settings_desc_chat_activity_display_mode: 'Journal de travail compact regroupe les activités de support dans un résumé discret. Flux transparent conserve chaque événement de réflexion/outil comme une ligne extensible chronologique.',
|
||||
settings_desc_chat_activity_display_mode: 'Journal de travail compact regroupe les activités de support dans un résumé discret. Flux transparent conserve chaque événement de réflexion/outil comme une ligne extensible chronologique. Final answer only hides activity rows while keeping the final answer visible.',
|
||||
first_token_time: 'Délai jusqu\'au premier jeton',
|
||||
processed_elapsed: _i18nProcessedElapsedEn,
|
||||
worklog_thinking: 'Réflexion',
|
||||
@@ -17072,6 +17082,7 @@ const LOCALES = {
|
||||
done: 'Terminé',
|
||||
settings_option_compact_worklog: 'Journal de travail compact',
|
||||
settings_option_transparent_stream: 'Flux transparent',
|
||||
settings_option_final_answer_only: 'Final answer only',
|
||||
|
||||
settings_label_tab_visibility: 'Onglets de la barre latérale',
|
||||
settings_desc_tab_visibility: 'Choisir quels onglets apparaissent dans la barre latérale et le rail. Chat et Paramètres sont toujours visibles. Faites glisser les puces pour les réorganiser.',
|
||||
@@ -18984,7 +18995,7 @@ const LOCALES = {
|
||||
settings_desc_auto_title_refresh: 'Automaticky regeneruje název relace na základě poslední výměny, udržuje ho relevantní jak konverzace pokračuje. Vyžaduje aby byl nakonfigurován LLM model pro generování názvů.',
|
||||
settings_desc_auxiliary_models: 'Směrování vedlejších úloh pro vision, kompresi, generování názvů atd. "Auto" používá váš hlavní chatovací model.',
|
||||
settings_desc_bot_name: 'Použito pouze pro výchozí profil. Ostatní profily používají vlastní názvy profilů.',
|
||||
settings_desc_chat_activity_display_mode: 'Kompaktní Worklog seskupuje podpůrnou aktivitu do tichého souhrnu. Transparentní Stream zachovává každou událost přemýšlení/nástroje jako vlastní chronologicky rozbalitelný řádek.',
|
||||
settings_desc_chat_activity_display_mode: 'Kompaktní Worklog seskupuje podpůrnou aktivitu do tichého souhrnu. Transparentní Stream zachovává každou událost přemýšlení/nástroje jako vlastní chronologicky rozbalitelný řádek. Final answer only hides activity rows while keeping the final answer visible.',
|
||||
settings_desc_check_updates: 'Zobrazit banner když jsou dostupné novější verze WebUI nebo Agenta. Spouští periodické git fetch na pozadí.',
|
||||
settings_desc_claude_code_sessions: 'Zobrazit importované relace Claude Code v bočním panelu, nebo je skrýt při zachování ostatních externích relací viditelných.',
|
||||
settings_desc_composer_controls: 'Přepínat které ovládací prvky jsou zobrazeny v zápatí chatu. Přetáhněte čipy pro změnu pořadí každé skupiny zápatí.',
|
||||
@@ -19121,6 +19132,7 @@ const LOCALES = {
|
||||
settings_option_structured_code_off: 'Zdroj standardně',
|
||||
settings_option_structured_code_on: 'Strom standardně',
|
||||
settings_option_transparent_stream: 'Transparentní Stream',
|
||||
settings_option_final_answer_only: 'Final answer only',
|
||||
settings_plugins_empty: 'Žádné Hermes pluginy nejsou aktuálně viditelné. Nainstalujte nebo povolte pluginy z Hermes CLI/config pro jejich zobrazení zde.',
|
||||
settings_plugins_meta: 'Zobrazit nainstalované Hermes pluginy a háčky životního cyklu, které registrují. Tento panel je pouze pro čtení.',
|
||||
settings_plugins_title: 'Pluginy',
|
||||
@@ -20360,7 +20372,7 @@ const LOCALES = {
|
||||
settings_label_worklog_details_expanded_default: 'Open Worklog details automatically',
|
||||
settings_desc_worklog_details_expanded_default: 'When enabled, new Worklog details start expanded so tool, thinking, and progress cards are visible without an extra click. When off, Worklog details stay folded by default; per-turn manual collapse/expand choices still win.',
|
||||
settings_label_chat_activity_display_mode: 'Activity display',
|
||||
settings_desc_chat_activity_display_mode: 'Compact Worklog groups supporting activity into a quiet summary. Transparent Stream keeps each thinking/tool event as its own chronological expandable row.',
|
||||
settings_desc_chat_activity_display_mode: 'Compact Worklog groups supporting activity into a quiet summary. Transparent Stream keeps each thinking/tool event as its own chronological expandable row. Final answer only hides activity rows while keeping the final answer visible.',
|
||||
first_token_time: 'Time to first token',
|
||||
processed_elapsed: _i18nProcessedElapsedEn,
|
||||
worklog_thinking: 'Thinking',
|
||||
@@ -20371,6 +20383,7 @@ const LOCALES = {
|
||||
done: 'Done',
|
||||
settings_option_compact_worklog: 'Compact Worklog',
|
||||
settings_option_transparent_stream: 'Transparent Stream',
|
||||
settings_option_final_answer_only: 'Final answer only',
|
||||
|
||||
settings_label_tab_visibility: 'Kenar çubuğu sekmeleri',
|
||||
settings_desc_tab_visibility: 'Kenar çubuğunda ve rayda hangi sekmelerin görüneceğini seçin. Sohbet ve Ayarlar her zaman görünür durumdadır.',
|
||||
@@ -22060,7 +22073,7 @@ const LOCALES = {
|
||||
settings_label_worklog_details_expanded_default: 'Otwieraj szczegóły Worklog automatycznie',
|
||||
settings_desc_worklog_details_expanded_default: 'Gdy ta opcja jest włączona, nowe szczegóły Worklog zaczynają rozwinięte, dzięki czemu karty narzędzi, Thinking i postępu są widoczne bez dodatkowego kliknięcia. Gdy jest wyłączona, szczegóły Worklog pozostają domyślnie zwinięte. Ręczne decyzje o zwinięciu/rozwinięciu w danej turze mają pierwszeństwo.',
|
||||
settings_label_chat_activity_display_mode: 'Wyświetlanie aktywności',
|
||||
settings_desc_chat_activity_display_mode: 'Kompaktowy dziennik pracy grupuje aktywność wspierającą w dyskretne podsumowanie. Transparentny strumień zachowuje każde zdarzenie myślenia/narzędzia jako osobny chronologiczny wiersz z możliwością rozwinięcia.',
|
||||
settings_desc_chat_activity_display_mode: 'Kompaktowy dziennik pracy grupuje aktywność wspierającą w dyskretne podsumowanie. Transparentny strumień zachowuje każde zdarzenie myślenia/narzędzia jako osobny chronologiczny wiersz z możliwością rozwinięcia. Final answer only hides activity rows while keeping the final answer visible.',
|
||||
first_token_time: 'Czas do pierwszego tokenu',
|
||||
processed_elapsed: _i18nProcessedElapsedPl,
|
||||
worklog_thinking: 'Myślenie',
|
||||
@@ -22071,6 +22084,7 @@ const LOCALES = {
|
||||
done: 'Gotowe',
|
||||
settings_option_compact_worklog: 'Kompaktowy dziennik pracy',
|
||||
settings_option_transparent_stream: 'Transparentny strumień',
|
||||
settings_option_final_answer_only: 'Final answer only',
|
||||
|
||||
settings_label_tab_visibility: 'Karty paska bocznego',
|
||||
settings_desc_tab_visibility: 'Wybierz, które karty pojawiają się na pasku bocznym i szynie. Przeciągnij elementy, aby zmienić ich kolejność. Czat i Ustawienia są zawsze widoczne.',
|
||||
@@ -23648,7 +23662,7 @@ const LOCALES = {
|
||||
settings_label_worklog_details_expanded_default: 'Tự động mở chi tiết Worklog',
|
||||
settings_desc_worklog_details_expanded_default: 'Khi bật, chi tiết Worklog mới sẽ được mở sẵn để hiển thị tool, suy nghĩ và thẻ tiến trình mà không cần bấm thêm. Khi tắt, Worklog sẽ mặc định thu gọn; các lựa chọn mở/thu gọn thủ công theo từng lượt vẫn được ưu tiên.',
|
||||
settings_label_chat_activity_display_mode: 'Hiển thị hoạt động',
|
||||
settings_desc_chat_activity_display_mode: 'Compact Worklog gom nhóm hoạt động thành bản tóm tắt gọn. Transparent Stream giữ mỗi sự kiện thinking/tool thành một dòng theo thứ tự thời gian có thể mở rộng.',
|
||||
settings_desc_chat_activity_display_mode: 'Compact Worklog gom nhóm hoạt động thành bản tóm tắt gọn. Transparent Stream giữ mỗi sự kiện thinking/tool thành một dòng theo thứ tự thời gian có thể mở rộng. Final answer only hides activity rows while keeping the final answer visible.',
|
||||
first_token_time: 'Thời gian tới token đầu tiên',
|
||||
processed_elapsed: _i18nProcessedElapsedVi,
|
||||
worklog_thinking: 'Đang suy nghĩ',
|
||||
@@ -23659,6 +23673,7 @@ const LOCALES = {
|
||||
done: 'Hoàn tất',
|
||||
settings_option_compact_worklog: 'Nhật ký công việc rút gọn',
|
||||
settings_option_transparent_stream: 'Luồng trong suốt',
|
||||
settings_option_final_answer_only: 'Final answer only',
|
||||
|
||||
settings_label_tab_visibility: 'Tab sidebar',
|
||||
settings_desc_tab_visibility: 'Chọn tab nào xuất hiện trong sidebar và thanh rail. Kéo các chip để đổi thứ tự. Chat và Settings luôn hiển thị.',
|
||||
|
||||
+5
-1
@@ -1048,12 +1048,16 @@
|
||||
<button type="button" class="chat-activity-mode-btn" data-chat-activity-mode="transparent_stream" onclick="_pickChatActivityDisplayMode('transparent_stream')">
|
||||
<span data-i18n="settings_option_transparent_stream">Transparent Stream</span>
|
||||
</button>
|
||||
<button type="button" class="chat-activity-mode-btn" data-chat-activity-mode="hide_all_activity" onclick="_pickChatActivityDisplayMode('hide_all_activity')">
|
||||
<span data-i18n="settings_option_final_answer_only">Final answer only</span>
|
||||
</button>
|
||||
</div>
|
||||
<select id="settingsChatActivityDisplayMode" style="display:none">
|
||||
<option value="compact_worklog" data-i18n="settings_option_compact_worklog">Compact Worklog</option>
|
||||
<option value="transparent_stream" data-i18n="settings_option_transparent_stream">Transparent Stream</option>
|
||||
<option value="hide_all_activity" data-i18n="settings_option_final_answer_only">Final answer only</option>
|
||||
</select>
|
||||
<div style="font-size:11px;color:var(--muted);margin-top:4px" data-i18n="settings_desc_chat_activity_display_mode">Compact Worklog groups supporting activity into a quiet summary. Transparent Stream keeps each thinking/tool event as its own chronological expandable row.</div>
|
||||
<div style="font-size:11px;color:var(--muted);margin-top:4px" data-i18n="settings_desc_chat_activity_display_mode">Compact Worklog groups supporting activity into a quiet summary. Transparent Stream keeps each thinking/tool event as its own chronological expandable row. Final answer only hides activity rows while keeping the final answer visible.</div>
|
||||
</div>
|
||||
<div class="settings-field" style="margin-top:8px">
|
||||
<label style="display:flex;align-items:center;gap:8px;cursor:pointer">
|
||||
|
||||
+10
-5
@@ -2708,7 +2708,7 @@ function attachLiveStream(activeSid, streamId, uploaded=[], options={}){
|
||||
return Number.isFinite(seq)&&seq>0?seq:1;
|
||||
}
|
||||
function _anchorSceneActiveMode(){
|
||||
const normalize=value=>value==='transparent_stream'||value==='compact_worklog'?value:'';
|
||||
const normalize=value=>value==='transparent_stream'||value==='compact_worklog'||value==='hide_all_activity'?value:'';
|
||||
if(typeof window!=='undefined'){
|
||||
if(typeof window.chatActivityMode==='function'){
|
||||
try{
|
||||
@@ -2728,6 +2728,7 @@ function attachLiveStream(activeSid, streamId, uploaded=[], options={}){
|
||||
: null;
|
||||
if(sceneMode==='transparent_stream') return (hints&&hints.transparent_stream)||'chronological_activity';
|
||||
if(sceneMode==='compact_worklog') return (hints&&hints.compact_worklog)||row.display_hint||'activity_row';
|
||||
if(sceneMode==='hide_all_activity') return (hints&&hints.hidden_activity)||'hidden_activity';
|
||||
return row&&row.display_hint||'activity_row';
|
||||
}
|
||||
function _renderAnchorLiveScene(){
|
||||
@@ -3482,7 +3483,7 @@ function attachLiveStream(activeSid, streamId, uploaded=[], options={}){
|
||||
}
|
||||
}
|
||||
const base=(projectedScene&&typeof projectedScene==='object')?projectedScene:{};
|
||||
const sceneMode=base.mode==='transparent_stream'?'transparent_stream':_anchorSceneActiveMode();
|
||||
const sceneMode=base.mode==='transparent_stream'||base.mode==='hide_all_activity' ? base.mode : _anchorSceneActiveMode();
|
||||
const messageFinalAnswer=_anchorSceneFinalAnswerText(lastAsst);
|
||||
const finalAnswer=_anchorSceneCleanText(messageFinalAnswer)
|
||||
? messageFinalAnswer
|
||||
@@ -3586,6 +3587,8 @@ function attachLiveStream(activeSid, streamId, uploaded=[], options={}){
|
||||
}
|
||||
}
|
||||
function _anchorSceneHasWorklogWorthyRows(scene){
|
||||
if(scene&&scene.mode==='hide_all_activity') return false;
|
||||
if(typeof window!=='undefined'&&typeof window.isFinalAnswerOnlyMode==='function'&&window.isFinalAnswerOnlyMode()) return false;
|
||||
// A worklog (the collapsible "已处理 …" rail) is only meaningful when the turn
|
||||
// actually DID worklog-worthy work — a tool call, a thinking/reasoning pass, or
|
||||
// a compression lifecycle card. A turn that only streamed prose (e.g. a long
|
||||
@@ -3623,12 +3626,14 @@ function attachLiveStream(activeSid, streamId, uploaded=[], options={}){
|
||||
if(!lastAsst) return false;
|
||||
const projectedScene=_projectLiveAnchorActivityScene();
|
||||
const scene=_completeSettledAnchorSceneForTurn(messages,lastAsstIndex,projectedScene);
|
||||
if(scene&&Array.isArray(scene.activity_rows)&&scene.activity_rows.length
|
||||
&&_anchorSceneHasWorklogWorthyRows(scene)){
|
||||
if(scene&&Array.isArray(scene.activity_rows)&&scene.activity_rows.length){
|
||||
const hasWorklogRows=_anchorSceneHasWorklogWorthyRows(scene);
|
||||
const shouldPersistScene=hasWorklogRows||scene.mode==='hide_all_activity';
|
||||
if(!shouldPersistScene) return false;
|
||||
lastAsst._anchor_stream_id=streamId;
|
||||
lastAsst._anchor_activity_scene=scene;
|
||||
_persistSettledAnchorScene(lastAsst, scene, lastAsstIndex);
|
||||
return true;
|
||||
return hasWorklogRows;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
+9
-3
@@ -8306,7 +8306,9 @@ function _appearancePayloadFromUi(){
|
||||
theme: ($('settingsTheme')||{}).value || localStorage.getItem('hermes-theme') || 'dark',
|
||||
skin: ($('settingsSkin')||{}).value || localStorage.getItem('hermes-skin') || 'default',
|
||||
font_size: ($('settingsFontSize')||{}).value || localStorage.getItem('hermes-font-size') || 'default',
|
||||
chat_activity_display_mode: chatActivityModeSel&&chatActivityModeSel.value==='transparent_stream'?'transparent_stream':'compact_worklog',
|
||||
chat_activity_display_mode: chatActivityModeSel&&(chatActivityModeSel.value==='transparent_stream'||chatActivityModeSel.value==='hide_all_activity')
|
||||
? chatActivityModeSel.value
|
||||
: 'compact_worklog',
|
||||
session_jump_buttons: !!($('settingsSessionJumpButtons')||{}).checked,
|
||||
session_endless_scroll: !!($('settingsSessionEndlessScroll')||{}).checked,
|
||||
auto_scroll_follow: !!($('settingsAutoScrollFollow')||{}).checked,
|
||||
@@ -8325,7 +8327,7 @@ function _appearancePayloadFromUi(){
|
||||
}
|
||||
|
||||
function _syncChatActivityDisplayModeControl(mode){
|
||||
const next=mode==='transparent_stream'?'transparent_stream':'compact_worklog';
|
||||
const next=mode==='transparent_stream'||mode==='hide_all_activity' ? mode : 'compact_worklog';
|
||||
const select=$('settingsChatActivityDisplayMode');
|
||||
if(select) select.value=next;
|
||||
document.querySelectorAll('[data-chat-activity-mode]').forEach(btn=>{
|
||||
@@ -8335,6 +8337,7 @@ function _syncChatActivityDisplayModeControl(mode){
|
||||
});
|
||||
window._chatActivityDisplayMode=next;
|
||||
window._transparentStream=next==='transparent_stream';
|
||||
if(next==='hide_all_activity'&&typeof window._hideLiveActivityForFinalAnswerOnly==='function') window._hideLiveActivityForFinalAnswerOnly();
|
||||
}
|
||||
|
||||
function _pickChatActivityDisplayMode(mode){
|
||||
@@ -12231,7 +12234,10 @@ async function saveSettings(andClose){
|
||||
body.font_size=fontSize;
|
||||
body.session_jump_buttons=!!($('settingsSessionJumpButtons')||{}).checked;
|
||||
body.session_endless_scroll=!!($('settingsSessionEndlessScroll')||{}).checked;
|
||||
body.chat_activity_display_mode=(($('settingsChatActivityDisplayMode')||{}).value==='transparent_stream')?'transparent_stream':'compact_worklog';
|
||||
body.chat_activity_display_mode=((($('settingsChatActivityDisplayMode')||{}).value==='transparent_stream')
|
||||
||(($('settingsChatActivityDisplayMode')||{}).value==='hide_all_activity'))
|
||||
? ($('settingsChatActivityDisplayMode')||{}).value
|
||||
: 'compact_worklog';
|
||||
body.auto_scroll_follow=!!($('settingsAutoScrollFollow')||{}).checked;
|
||||
body.render_user_markdown=!!($('settingsRenderUserMarkdown')||{}).checked;
|
||||
body.large_text_paste_as_attachment=!!($('settingsLargeTextPasteAsAttachment')||{}).checked;
|
||||
|
||||
+1
-1
@@ -5108,7 +5108,7 @@ main.main > #mainPlugin{display:none;}
|
||||
#mainSettings .theme-pick-btn.active,
|
||||
#mainSettings .skin-pick-btn.active,
|
||||
#mainSettings .font-size-pick-btn.active{border-color:var(--accent)!important;box-shadow:0 0 0 1px var(--accent-bg-strong)!important;background:var(--surface)!important;}
|
||||
#mainSettings .chat-activity-mode-toggle{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:6px;margin-top:4px;}
|
||||
#mainSettings .chat-activity-mode-toggle{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:6px;margin-top:4px;}
|
||||
#mainSettings .chat-activity-mode-btn{min-height:34px;padding:7px 10px;border:1px solid var(--border2);border-radius:8px;background:var(--surface);color:var(--muted);font-size:12px;font-weight:600;cursor:pointer;}
|
||||
#mainSettings .chat-activity-mode-btn:hover{border-color:var(--accent-bg-strong);color:var(--text);background:var(--hover-bg);}
|
||||
#mainSettings .chat-activity-mode-btn.active{border-color:var(--accent);color:var(--accent-text);background:var(--accent-bg);box-shadow:0 0 0 1px var(--accent-bg-strong);}
|
||||
|
||||
+42
-7
@@ -10240,17 +10240,23 @@ function _thinkingActivityNode(text, open, disclosureKey){
|
||||
}
|
||||
function chatActivityMode(){
|
||||
if(typeof window==='undefined') return 'compact_worklog';
|
||||
return window._chatActivityDisplayMode || (window._transparentStream ? 'transparent_stream' : 'compact_worklog') || 'compact_worklog';
|
||||
const mode=window._chatActivityDisplayMode;
|
||||
if(mode==='compact_worklog'||mode==='transparent_stream'||mode==='hide_all_activity') return mode;
|
||||
return window._transparentStream ? 'transparent_stream' : 'compact_worklog';
|
||||
}
|
||||
function isTransparentStream(){
|
||||
return chatActivityMode()==='transparent_stream';
|
||||
}
|
||||
function isFinalAnswerOnlyMode(){
|
||||
return chatActivityMode()==='hide_all_activity';
|
||||
}
|
||||
function isCompactWorklogMode(){
|
||||
return isSimplifiedToolCalling()&&!isTransparentStream();
|
||||
return isSimplifiedToolCalling()&&chatActivityMode()==='compact_worklog';
|
||||
}
|
||||
if(typeof window!=='undefined'){
|
||||
window.chatActivityMode=chatActivityMode;
|
||||
window.isTransparentStream=isTransparentStream;
|
||||
window.isFinalAnswerOnlyMode=isFinalAnswerOnlyMode;
|
||||
window.isCompactWorklogMode=isCompactWorklogMode;
|
||||
}
|
||||
function _toolShortName(name){
|
||||
@@ -11607,10 +11613,19 @@ function _prepareLiveAnchorScrollRebuildGuard(scrollSnapshot){
|
||||
}
|
||||
function renderLiveAnchorActivityScene(streamId, scene, opts){
|
||||
opts=opts||{};
|
||||
if(typeof isTransparentStream==='function'&&isTransparentStream()){
|
||||
const requestedMode=opts.mode;
|
||||
const activeMode=chatActivityMode();
|
||||
const sceneMode=activeMode==='hide_all_activity'
|
||||
? 'hide_all_activity'
|
||||
: (requestedMode==='compact_worklog'||requestedMode==='transparent_stream'||requestedMode==='hide_all_activity'
|
||||
? requestedMode
|
||||
: activeMode);
|
||||
if(sceneMode==='hide_all_activity') return false;
|
||||
if(sceneMode==='transparent_stream'){
|
||||
return _renderLiveAnchorActivitySceneTransparent(streamId,scene,opts);
|
||||
}
|
||||
if(typeof isCompactWorklogMode==='function'&&!isCompactWorklogMode()) return false;
|
||||
if(typeof isSimplifiedToolCalling==='function'&&!isSimplifiedToolCalling()) return false;
|
||||
if(sceneMode!=='compact_worklog') return false;
|
||||
if(!S.session||!S.activeStreamId) return false;
|
||||
if(opts.sessionId&&S.session.session_id!==opts.sessionId) return false;
|
||||
if(streamId&&S.activeStreamId!==streamId) return false;
|
||||
@@ -11980,9 +11995,13 @@ function _refreshTransparentLiveRow(existing, node){
|
||||
return existing;
|
||||
}
|
||||
function _renderLiveAnchorActivitySceneForStream(streamId, sessionId, opts){
|
||||
const mode=(typeof isTransparentStream==='function'&&isTransparentStream())
|
||||
? 'transparent_stream'
|
||||
: ((opts&&opts.mode)||'compact_worklog');
|
||||
const requestedMode=opts&&opts.mode;
|
||||
const activeMode=chatActivityMode();
|
||||
const mode=activeMode==='hide_all_activity'
|
||||
? 'hide_all_activity'
|
||||
: (requestedMode==='compact_worklog'||requestedMode==='transparent_stream'||requestedMode==='hide_all_activity'
|
||||
? requestedMode
|
||||
: activeMode);
|
||||
const scene=_projectLiveAnchorActivitySceneForStream(streamId,mode);
|
||||
if(!scene) return false;
|
||||
return renderLiveAnchorActivityScene(streamId,scene,{...(opts||{}),sessionId});
|
||||
@@ -16082,6 +16101,7 @@ function appendLiveToolCard(tc){
|
||||
const opts=arguments[1]||{};
|
||||
if(opts.sessionId&&S.session.session_id!==opts.sessionId) return;
|
||||
if(opts.streamId&&S.activeStreamId!==opts.streamId) return;
|
||||
if(typeof isFinalAnswerOnlyMode==='function'&&isFinalAnswerOnlyMode()) return;
|
||||
if(isLiveAnchorActivitySceneOwner(opts.streamId||S.activeStreamId)){
|
||||
_renderLiveAnchorActivitySceneForStream(opts.streamId||S.activeStreamId, opts.sessionId||S.session.session_id, {mode:'compact_worklog'});
|
||||
return;
|
||||
@@ -16253,6 +16273,19 @@ function clearLiveToolCards(){
|
||||
const container=$('liveToolCards');
|
||||
if(container){container.innerHTML='';container.style.display='none';}
|
||||
}
|
||||
function _hideLiveActivityForFinalAnswerOnly(){
|
||||
clearLiveToolCards();
|
||||
if(typeof removeThinking==='function') removeThinking();
|
||||
const turn=$('liveAssistantTurn');
|
||||
const inner=_assistantTurnBlocks(turn);
|
||||
if(inner){
|
||||
inner.querySelectorAll('.transparent-event-row,.agent-activity-thinking,.wl-reason,#liveRunStatus,.live-worklog[data-live-worklog-shell],.tool-worklog-group[data-live-tool-call-group],.tool-call-group[data-live-tool-call-group],.tool-card-row[data-live-tid],[data-anchor-scene-owner="1"],[data-anchor-scene-row="1"]').forEach(el=>el.remove());
|
||||
}
|
||||
const legacyThinking=$('thinkingRow');
|
||||
if(legacyThinking) legacyThinking.remove();
|
||||
if(turn&&inner&&!inner.children.length) turn.remove();
|
||||
}
|
||||
if(typeof window!=='undefined') window._hideLiveActivityForFinalAnswerOnly=_hideLiveActivityForFinalAnswerOnly;
|
||||
function _removeEmptyLiveWorklogShells(inner){
|
||||
if(!inner) return;
|
||||
inner.querySelectorAll('.live-worklog[data-live-worklog-shell="1"],.tool-worklog-group[data-live-worklog-shell="1"],.tool-call-group[data-live-worklog-shell="1"]').forEach(group=>{
|
||||
@@ -16278,6 +16311,7 @@ function _setLiveWorklogThinkingPlaceholder(group){
|
||||
}
|
||||
function ensureLiveWorklogShell(){
|
||||
if(!S.session) return null;
|
||||
if(typeof isFinalAnswerOnlyMode==='function'&&isFinalAnswerOnlyMode()) return null;
|
||||
const activeStreamId=S.activeStreamId||'';
|
||||
if(activeStreamId&&typeof _renderLiveAnchorActivitySceneForStream==='function'&&_renderLiveAnchorActivitySceneForStream(activeStreamId, S.session.session_id, {mode:'compact_worklog'})){
|
||||
_dedupeLiveProcessedWorklogAnchors($('liveAssistantTurn'));
|
||||
@@ -17206,6 +17240,7 @@ function appendThinking(text='', options){
|
||||
// without this check they would pollute the new session's DOM.
|
||||
options=options||{};
|
||||
const allowPendingPlaceholder=!!(options&&options.pending===true);
|
||||
if(typeof isFinalAnswerOnlyMode==='function'&&isFinalAnswerOnlyMode()) return;
|
||||
if(!S.session||(!S.activeStreamId&&!allowPendingPlaceholder)) return;
|
||||
if(!allowPendingPlaceholder&&isLiveAnchorActivitySceneOwner(S.activeStreamId)){
|
||||
_renderLiveAnchorActivitySceneForStream(S.activeStreamId, S.session.session_id, {mode:'compact_worklog'});
|
||||
|
||||
@@ -1,16 +1,46 @@
|
||||
"""Regression tests for issue #3820 chat activity display mode."""
|
||||
|
||||
import json
|
||||
import shutil
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
UI_JS = (ROOT / "static" / "ui.js").read_text(encoding="utf-8")
|
||||
MESSAGES_JS = (ROOT / "static" / "messages.js").read_text(encoding="utf-8")
|
||||
BOOT_JS = (ROOT / "static" / "boot.js").read_text(encoding="utf-8")
|
||||
PANELS_JS = (ROOT / "static" / "panels.js").read_text(encoding="utf-8")
|
||||
INDEX_HTML = (ROOT / "static" / "index.html").read_text(encoding="utf-8")
|
||||
I18N_JS = (ROOT / "static" / "i18n.js").read_text(encoding="utf-8")
|
||||
STYLE_CSS = (ROOT / "static" / "style.css").read_text(encoding="utf-8")
|
||||
NODE = shutil.which("node")
|
||||
|
||||
_EXTRACT_FUNC_JS = """
|
||||
function extractFunc(name){
|
||||
const start = src.indexOf('function ' + name);
|
||||
if(start === -1) throw new Error(name + ' not found');
|
||||
const params = src.indexOf('(', start);
|
||||
let depth = 0, close = -1;
|
||||
for(let i=params; i<src.length; i++){
|
||||
if(src[i] === '(') depth++;
|
||||
else if(src[i] === ')'){
|
||||
depth--;
|
||||
if(depth === 0){ close = i; break; }
|
||||
}
|
||||
}
|
||||
const brace = src.indexOf('{', close);
|
||||
depth = 0;
|
||||
for(let i=brace; i<src.length; i++){
|
||||
if(src[i] === '{') depth++;
|
||||
else if(src[i] === '}'){
|
||||
depth--;
|
||||
if(depth === 0) return src.slice(start, i + 1);
|
||||
}
|
||||
}
|
||||
throw new Error(name + ' body did not close');
|
||||
}
|
||||
""".strip()
|
||||
|
||||
|
||||
def _transparentEventCountLabelBlock(ui_js):
|
||||
@@ -20,6 +50,13 @@ def _transparentEventCountLabelBlock(ui_js):
|
||||
return ui_js[start:end]
|
||||
|
||||
|
||||
def _run_node_script(script):
|
||||
assert NODE, "node is required for chat activity display mode behavior tests"
|
||||
result = subprocess.run([NODE, "-e", script], text=True, capture_output=True, check=False)
|
||||
assert result.returncode == 0, result.stderr
|
||||
return json.loads(result.stdout)
|
||||
|
||||
|
||||
def test_chat_activity_display_mode_defaults_to_compact_worklog(monkeypatch, tmp_path):
|
||||
import api.config as config
|
||||
|
||||
@@ -31,7 +68,7 @@ def test_chat_activity_display_mode_defaults_to_compact_worklog(monkeypatch, tmp
|
||||
assert loaded["chat_activity_display_mode"] == "compact_worklog"
|
||||
|
||||
|
||||
def test_chat_activity_display_mode_persists_transparent_stream_and_rejects_invalid(monkeypatch, tmp_path):
|
||||
def test_chat_activity_display_mode_persists_transparent_stream_hide_all_activity_and_rejects_invalid(monkeypatch, tmp_path):
|
||||
import api.config as config
|
||||
|
||||
settings_path = tmp_path / "settings.json"
|
||||
@@ -41,22 +78,286 @@ def test_chat_activity_display_mode_persists_transparent_stream_and_rejects_inva
|
||||
assert saved["chat_activity_display_mode"] == "transparent_stream"
|
||||
assert json.loads(settings_path.read_text(encoding="utf-8"))["chat_activity_display_mode"] == "transparent_stream"
|
||||
|
||||
saved = config.save_settings({"chat_activity_display_mode": "hide_all_activity"})
|
||||
assert saved["chat_activity_display_mode"] == "hide_all_activity"
|
||||
assert json.loads(settings_path.read_text(encoding="utf-8"))["chat_activity_display_mode"] == "hide_all_activity"
|
||||
|
||||
saved = config.save_settings({"chat_activity_display_mode": "invalid_mode"})
|
||||
assert saved["chat_activity_display_mode"] == "transparent_stream"
|
||||
assert json.loads(settings_path.read_text(encoding="utf-8"))["chat_activity_display_mode"] == "transparent_stream"
|
||||
assert saved["chat_activity_display_mode"] == "hide_all_activity"
|
||||
assert json.loads(settings_path.read_text(encoding="utf-8"))["chat_activity_display_mode"] == "hide_all_activity"
|
||||
|
||||
|
||||
def test_transparent_stream_uses_dedicated_mode_not_simplified_tool_calling():
|
||||
def test_chat_activity_display_mode_supports_three_values():
|
||||
assert "function chatActivityMode()" in UI_JS
|
||||
assert "function isTransparentStream()" in UI_JS
|
||||
assert "function isFinalAnswerOnlyMode()" in UI_JS
|
||||
assert "function isCompactWorklogMode()" in UI_JS
|
||||
assert "chatActivityMode()==='transparent_stream'" in UI_JS
|
||||
assert "chatActivityMode()==='hide_all_activity'" in UI_JS
|
||||
assert "window._chatActivityDisplayMode" in BOOT_JS
|
||||
assert "window._chatActivityDisplayMode" in PANELS_JS
|
||||
assert "window._simplifiedToolCalling=true" in BOOT_JS
|
||||
assert "window._simplifiedToolCalling=true" in PANELS_JS
|
||||
|
||||
|
||||
def test_chat_activity_display_mode_picker_uses_three_desktop_columns():
|
||||
assert INDEX_HTML.count('class="chat-activity-mode-btn') == 3
|
||||
assert "#mainSettings .chat-activity-mode-toggle{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));" in STYLE_CSS
|
||||
assert "#mainSettings .chat-activity-mode-toggle{grid-template-columns:1fr;}" in STYLE_CSS
|
||||
|
||||
|
||||
def test_chat_activity_display_mode_resolver_and_live_early_out():
|
||||
script = f"""
|
||||
const fs = require('fs');
|
||||
const src = fs.readFileSync({json.dumps(str(ROOT / "static" / "ui.js"))}, 'utf8');
|
||||
{_EXTRACT_FUNC_JS}
|
||||
global.window = {{
|
||||
_chatActivityDisplayMode: 'hide_all_activity',
|
||||
_transparentStream: false,
|
||||
}};
|
||||
global.isSimplifiedToolCalling = () => true;
|
||||
eval(extractFunc('chatActivityMode'));
|
||||
eval(extractFunc('isTransparentStream'));
|
||||
eval(extractFunc('isFinalAnswerOnlyMode'));
|
||||
eval(extractFunc('isCompactWorklogMode'));
|
||||
const resolverResults = [
|
||||
chatActivityMode(),
|
||||
isTransparentStream(),
|
||||
isFinalAnswerOnlyMode(),
|
||||
isCompactWorklogMode(),
|
||||
];
|
||||
window._chatActivityDisplayMode = 'transparent_stream';
|
||||
window._transparentStream = false;
|
||||
resolverResults.push(
|
||||
chatActivityMode(),
|
||||
isTransparentStream(),
|
||||
isFinalAnswerOnlyMode(),
|
||||
isCompactWorklogMode(),
|
||||
);
|
||||
window._chatActivityDisplayMode = 'bogus';
|
||||
window._transparentStream = true;
|
||||
resolverResults.push(
|
||||
chatActivityMode(),
|
||||
isTransparentStream(),
|
||||
isFinalAnswerOnlyMode(),
|
||||
isCompactWorklogMode(),
|
||||
);
|
||||
process.stdout.write(JSON.stringify({{resolverResults}}));
|
||||
"""
|
||||
result = _run_node_script(script)
|
||||
|
||||
assert result["resolverResults"] == [
|
||||
"hide_all_activity",
|
||||
False,
|
||||
True,
|
||||
False,
|
||||
"transparent_stream",
|
||||
True,
|
||||
False,
|
||||
False,
|
||||
"transparent_stream",
|
||||
True,
|
||||
False,
|
||||
False,
|
||||
]
|
||||
|
||||
|
||||
def test_chat_activity_display_mode_explicit_modes_are_preserved_by_render_helpers():
|
||||
script = f"""
|
||||
const fs = require('fs');
|
||||
const src = fs.readFileSync({json.dumps(str(ROOT / "static" / "ui.js"))}, 'utf8');
|
||||
{_EXTRACT_FUNC_JS}
|
||||
let captured = [];
|
||||
function _projectLiveAnchorActivitySceneForStream(streamId, mode){{
|
||||
return {{version:'activity_scene_v1', mode, activity_rows:[]}};
|
||||
}}
|
||||
function renderLiveAnchorActivityScene(streamId, scene, opts){{
|
||||
captured.push({{streamId, sceneMode: scene.mode, optMode: opts.mode, sessionId: opts.sessionId}});
|
||||
return false;
|
||||
}}
|
||||
let activeMode = 'compact_worklog';
|
||||
global.chatActivityMode = () => activeMode;
|
||||
eval(extractFunc('_renderLiveAnchorActivitySceneForStream'));
|
||||
eval(extractFunc('_renderLiveAnchorActivitySceneSnapshotForStream'));
|
||||
const helperResult = _renderLiveAnchorActivitySceneForStream('stream-1', 'sid-1', {{mode:'hide_all_activity'}});
|
||||
const snapshotResult = _renderLiveAnchorActivitySceneSnapshotForStream(
|
||||
'stream-2',
|
||||
{{version:'activity_scene_v1', activity_rows:[]}},
|
||||
'sid-2',
|
||||
{{mode:'transparent_stream'}},
|
||||
);
|
||||
activeMode = 'hide_all_activity';
|
||||
const compactOverrideResult = _renderLiveAnchorActivitySceneForStream(
|
||||
'stream-3',
|
||||
'sid-3',
|
||||
{{mode:'compact_worklog'}},
|
||||
);
|
||||
process.stdout.write(JSON.stringify({{helperResult, snapshotResult, compactOverrideResult, captured}}));
|
||||
"""
|
||||
result = _run_node_script(script)
|
||||
|
||||
assert result["helperResult"] is False
|
||||
assert result["snapshotResult"] is False
|
||||
assert result["compactOverrideResult"] is False
|
||||
assert result["captured"] == [
|
||||
{"streamId": "stream-1", "sceneMode": "hide_all_activity", "optMode": "hide_all_activity", "sessionId": "sid-1"},
|
||||
{"streamId": "stream-2", "optMode": "transparent_stream", "sessionId": "sid-2"},
|
||||
{"streamId": "stream-3", "sceneMode": "hide_all_activity", "optMode": "compact_worklog", "sessionId": "sid-3"},
|
||||
]
|
||||
|
||||
|
||||
def test_chat_activity_display_mode_live_renderer_early_outs_in_hide_all_mode():
|
||||
script = f"""
|
||||
const fs = require('fs');
|
||||
const src = fs.readFileSync({json.dumps(str(ROOT / "static" / "ui.js"))}, 'utf8');
|
||||
{_EXTRACT_FUNC_JS}
|
||||
global.window = {{
|
||||
_chatActivityDisplayMode: 'hide_all_activity',
|
||||
_transparentStream: false,
|
||||
}};
|
||||
global.S = {{ session: {{ session_id: 'sid-1' }}, activeStreamId: 'stream-1' }};
|
||||
global.isSimplifiedToolCalling = () => true;
|
||||
global.$ = () => {{ throw new Error('unexpected DOM access'); }};
|
||||
eval(extractFunc('chatActivityMode'));
|
||||
eval(extractFunc('isTransparentStream'));
|
||||
eval(extractFunc('isFinalAnswerOnlyMode'));
|
||||
eval(extractFunc('isCompactWorklogMode'));
|
||||
eval(extractFunc('renderLiveAnchorActivityScene'));
|
||||
const result = renderLiveAnchorActivityScene(
|
||||
'stream-1',
|
||||
{{version:'activity_scene_v1', activity_rows:[{{role:'tool'}}]}},
|
||||
{{sessionId:'sid-1', mode:'hide_all_activity'}},
|
||||
);
|
||||
process.stdout.write(JSON.stringify({{result, mode: chatActivityMode(), finalOnly: isFinalAnswerOnlyMode(), compact: isCompactWorklogMode()}}));
|
||||
"""
|
||||
result = _run_node_script(script)
|
||||
|
||||
assert result == {"result": False, "mode": "hide_all_activity", "finalOnly": True, "compact": False}
|
||||
|
||||
|
||||
def test_chat_activity_display_mode_anchor_scene_preserves_hide_all_mode():
|
||||
script = f"""
|
||||
const fs = require('fs');
|
||||
const vm = require('vm');
|
||||
const src = fs.readFileSync({json.dumps(str(ROOT / "static" / "assistant_turn_anchors.js"))}, 'utf8');
|
||||
const sandbox = {{window:{{}}}};
|
||||
vm.createContext(sandbox);
|
||||
vm.runInContext(src, sandbox, {{filename:'assistant_turn_anchors.js'}});
|
||||
const api = sandbox.window.HermesAssistantTurnAnchors;
|
||||
const empty = api.projectAssistantTurnAnchorActivityScene(null, {{mode:'hide_all_activity'}});
|
||||
const registry = api.createAssistantTurnAnchorRegistry({{session_id:'sid-1', turn_id:'turn-1'}});
|
||||
api.applyAssistantTurnAnchorSourceEvents(registry, [
|
||||
{{event:'tool', payload:{{tool_call_id:'tool-1', name:'terminal'}}, event_id:'run-1:1', seq:1}},
|
||||
{{source_type:'settled_message', payload:{{role:'assistant', id:'message-final', content:'final answer'}}}},
|
||||
], {{run_id:'run-1', stream_id:'stream-1'}});
|
||||
const scene = api.projectAssistantTurnAnchorActivityScene(registry, {{mode:'hide_all_activity'}});
|
||||
const snapshot = api.createAssistantTurnAnchorRendererSnapshot({{mode:'hide_all_activity', rows:[]}});
|
||||
process.stdout.write(JSON.stringify({{emptyMode:empty.mode, sceneMode:scene.mode, snapshotMode:snapshot.mode}}));
|
||||
"""
|
||||
result = _run_node_script(script)
|
||||
|
||||
assert result == {
|
||||
"emptyMode": "hide_all_activity",
|
||||
"sceneMode": "hide_all_activity",
|
||||
"snapshotMode": "hide_all_activity",
|
||||
}
|
||||
|
||||
|
||||
def test_chat_activity_display_mode_legacy_live_fallbacks_do_not_render_activity():
|
||||
script = f"""
|
||||
const fs = require('fs');
|
||||
const src = fs.readFileSync({json.dumps(str(ROOT / "static" / "ui.js"))}, 'utf8');
|
||||
{_EXTRACT_FUNC_JS}
|
||||
global.S = {{ session: {{ session_id: 'sid-1' }}, activeStreamId: 'stream-1' }};
|
||||
global.isFinalAnswerOnlyMode = () => true;
|
||||
global.$ = () => {{ throw new Error('unexpected DOM access'); }};
|
||||
eval(extractFunc('appendLiveToolCard'));
|
||||
eval(extractFunc('ensureLiveWorklogShell'));
|
||||
const appendResult = appendLiveToolCard({{tid:'tool-1'}}, {{sessionId:'sid-1', streamId:'stream-1'}});
|
||||
const shellResult = ensureLiveWorklogShell();
|
||||
process.stdout.write(JSON.stringify({{appendResult: appendResult === undefined, shellResult}}));
|
||||
"""
|
||||
result = _run_node_script(script)
|
||||
|
||||
assert result == {"appendResult": True, "shellResult": None}
|
||||
|
||||
|
||||
def test_chat_activity_display_mode_legacy_thinking_fallback_does_not_render_activity():
|
||||
script = f"""
|
||||
const fs = require('fs');
|
||||
const src = fs.readFileSync({json.dumps(str(ROOT / "static" / "ui.js"))}, 'utf8');
|
||||
{_EXTRACT_FUNC_JS}
|
||||
global.isFinalAnswerOnlyMode = () => true;
|
||||
global.$ = () => {{ throw new Error('unexpected DOM access'); }};
|
||||
eval(extractFunc('appendThinking'));
|
||||
eval(extractFunc('updateThinking'));
|
||||
const appendResult = appendThinking('reasoning text', {{pending:true}});
|
||||
const updateResult = updateThinking('reasoning text', {{pending:true}});
|
||||
process.stdout.write(JSON.stringify({{appendResult: appendResult === undefined, updateResult: updateResult === undefined}}));
|
||||
"""
|
||||
result = _run_node_script(script)
|
||||
|
||||
assert result == {"appendResult": True, "updateResult": True}
|
||||
|
||||
|
||||
def test_chat_activity_display_mode_settled_hide_all_scene_persists_without_worklog():
|
||||
start = MESSAGES_JS.index("function _attachProjectedAnchorSceneToLastAssistant(messages){")
|
||||
end = MESSAGES_JS.index("function _upsertAnchorProcessProse", start)
|
||||
block = MESSAGES_JS[start:end]
|
||||
persist_index = block.index("_persistSettledAnchorScene(lastAsst, scene, lastAsstIndex);")
|
||||
return_index = block.index("return hasWorklogRows;")
|
||||
|
||||
assert "const hasWorklogRows=_anchorSceneHasWorklogWorthyRows(scene);" in block
|
||||
assert "const shouldPersistScene=hasWorklogRows||scene.mode==='hide_all_activity';" in block
|
||||
assert persist_index < return_index
|
||||
assert "return true;" not in block
|
||||
|
||||
|
||||
def test_chat_activity_display_mode_switch_to_final_only_clears_existing_live_activity():
|
||||
script = f"""
|
||||
const fs = require('fs');
|
||||
const src = fs.readFileSync({json.dumps(str(ROOT / "static" / "panels.js"))}, 'utf8');
|
||||
{_EXTRACT_FUNC_JS}
|
||||
let cleanupCalls = 0;
|
||||
const select = {{value:''}};
|
||||
const buttons = [
|
||||
{{mode:'compact_worklog'}},
|
||||
{{mode:'transparent_stream'}},
|
||||
{{mode:'hide_all_activity'}},
|
||||
].map(({{mode}}) => ({{
|
||||
getAttribute: (name) => name === 'data-chat-activity-mode' ? mode : null,
|
||||
classList: {{toggle(){{}}}},
|
||||
setAttribute(){{}},
|
||||
}}));
|
||||
global.window = {{_hideLiveActivityForFinalAnswerOnly(){{ cleanupCalls += 1; }}}};
|
||||
global.document = {{querySelectorAll: () => buttons}};
|
||||
global.$ = (id) => id === 'settingsChatActivityDisplayMode' ? select : null;
|
||||
eval(extractFunc('_syncChatActivityDisplayModeControl'));
|
||||
_syncChatActivityDisplayModeControl('transparent_stream');
|
||||
const afterTransparent = {{mode: window._chatActivityDisplayMode, transparent: window._transparentStream, cleanupCalls}};
|
||||
_syncChatActivityDisplayModeControl('hide_all_activity');
|
||||
const afterHide = {{mode: window._chatActivityDisplayMode, transparent: window._transparentStream, cleanupCalls, selectValue: select.value}};
|
||||
process.stdout.write(JSON.stringify({{afterTransparent, afterHide}}));
|
||||
"""
|
||||
result = _run_node_script(script)
|
||||
|
||||
assert result == {
|
||||
"afterTransparent": {"mode": "transparent_stream", "transparent": True, "cleanupCalls": 0},
|
||||
"afterHide": {"mode": "hide_all_activity", "transparent": False, "cleanupCalls": 1, "selectValue": "hide_all_activity"},
|
||||
}
|
||||
|
||||
|
||||
def test_chat_activity_display_mode_live_cleanup_removes_existing_activity_rows():
|
||||
start = UI_JS.index("function _hideLiveActivityForFinalAnswerOnly(){")
|
||||
end = UI_JS.index("function _removeEmptyLiveWorklogShells", start)
|
||||
block = UI_JS[start:end]
|
||||
|
||||
assert "clearLiveToolCards();" in block
|
||||
assert "removeThinking" in block
|
||||
assert ".transparent-event-row" in block
|
||||
assert "#liveRunStatus" in block
|
||||
assert "window._hideLiveActivityForFinalAnswerOnly=_hideLiveActivityForFinalAnswerOnly" in UI_JS
|
||||
|
||||
|
||||
def test_transparent_stream_live_branch_uses_direct_rows():
|
||||
decorator_start = UI_JS.index("function _decorateTransparentEventRow(row, opts){")
|
||||
decorator_end = UI_JS.index("function _setTransparentRowsExpanded", decorator_start)
|
||||
@@ -119,9 +420,12 @@ def test_settings_ui_exposes_chat_activity_display_mode_selector():
|
||||
assert 'id="settingsChatActivityDisplayMode"' in INDEX_HTML
|
||||
assert 'data-chat-activity-mode="compact_worklog"' in INDEX_HTML
|
||||
assert 'data-chat-activity-mode="transparent_stream"' in INDEX_HTML
|
||||
assert 'data-chat-activity-mode="hide_all_activity"' in INDEX_HTML
|
||||
assert 'value="compact_worklog"' in INDEX_HTML
|
||||
assert 'value="transparent_stream"' in INDEX_HTML
|
||||
assert 'value="hide_all_activity"' in INDEX_HTML
|
||||
assert 'data-i18n="settings_label_chat_activity_display_mode"' in INDEX_HTML
|
||||
assert 'settings_option_final_answer_only' in INDEX_HTML
|
||||
assert "chat_activity_display_mode" in PANELS_JS
|
||||
assert "settingsChatActivityDisplayMode" in PANELS_JS
|
||||
assert "function _syncChatActivityDisplayModeControl" in PANELS_JS
|
||||
@@ -130,6 +434,50 @@ def test_settings_ui_exposes_chat_activity_display_mode_selector():
|
||||
assert "renderMessages({preserveScroll:true})" in PANELS_JS
|
||||
assert "settings_label_chat_activity_display_mode" in I18N_JS
|
||||
assert "settings_desc_chat_activity_display_mode" in I18N_JS
|
||||
assert I18N_JS.count("settings_option_final_answer_only") == I18N_JS.count("settings_option_transparent_stream")
|
||||
|
||||
|
||||
def test_chat_activity_display_mode_plumbing_preserves_hide_all_activity():
|
||||
assert "s.chat_activity_display_mode==='transparent_stream'||s.chat_activity_display_mode==='hide_all_activity'" in BOOT_JS
|
||||
assert "chatActivityModeSel&&(chatActivityModeSel.value==='transparent_stream'||chatActivityModeSel.value==='hide_all_activity')" in PANELS_JS
|
||||
assert "const next=mode==='transparent_stream'||mode==='hide_all_activity' ? mode : 'compact_worklog';" in PANELS_JS
|
||||
assert "hide_all_activity" in PANELS_JS
|
||||
|
||||
|
||||
def test_chat_activity_display_mode_settled_worklog_suppression():
|
||||
script = f"""
|
||||
const fs = require('fs');
|
||||
const src = fs.readFileSync({json.dumps(str(ROOT / "static" / "messages.js"))}, 'utf8');
|
||||
{_EXTRACT_FUNC_JS}
|
||||
eval(extractFunc('_anchorSceneActiveMode'));
|
||||
eval(extractFunc('_anchorSceneRowDisplayHintForMode'));
|
||||
eval(extractFunc('_anchorSceneHasWorklogWorthyRows'));
|
||||
global.window = {{
|
||||
chatActivityMode() {{ return 'hide_all_activity'; }},
|
||||
_chatActivityDisplayMode: 'compact_worklog',
|
||||
_transparentStream: false,
|
||||
isFinalAnswerOnlyMode() {{ return false; }},
|
||||
}};
|
||||
const activeMode = _anchorSceneActiveMode();
|
||||
const hiddenHint = _anchorSceneRowDisplayHintForMode({{display_hints:{{}}}}, 'hide_all_activity');
|
||||
const compactHint = _anchorSceneRowDisplayHintForMode({{display_hints:{{compact_worklog:'activity_row'}}}}, 'compact_worklog');
|
||||
const hiddenScene = _anchorSceneHasWorklogWorthyRows({{mode:'hide_all_activity', activity_rows:[{{role:'tool'}},{{role:'thinking'}}]}});
|
||||
window.isFinalAnswerOnlyMode = () => true;
|
||||
const activeFinalOnly = _anchorSceneHasWorklogWorthyRows({{mode:'compact_worklog', activity_rows:[{{role:'tool'}}]}});
|
||||
window.isFinalAnswerOnlyMode = () => false;
|
||||
const compactScene = _anchorSceneHasWorklogWorthyRows({{mode:'compact_worklog', activity_rows:[{{role:'tool'}}]}});
|
||||
process.stdout.write(JSON.stringify({{activeMode, hiddenHint, compactHint, hiddenScene, activeFinalOnly, compactScene}}));
|
||||
"""
|
||||
result = _run_node_script(script)
|
||||
|
||||
assert result == {
|
||||
"activeMode": "hide_all_activity",
|
||||
"hiddenHint": "hidden_activity",
|
||||
"compactHint": "activity_row",
|
||||
"hiddenScene": False,
|
||||
"activeFinalOnly": False,
|
||||
"compactScene": True,
|
||||
}
|
||||
|
||||
|
||||
def test_appearance_autosave_rerenders_only_when_activity_mode_changes():
|
||||
|
||||
@@ -1009,7 +1009,7 @@ def test_live_anchor_scene_snapshot_renders_transparent_rows_before_compact_gate
|
||||
row = _function_body(UI_JS, "_anchorSceneTransparentNodeForRow")
|
||||
|
||||
transparent_gate = "return _renderLiveAnchorActivitySceneTransparent(streamId,scene,opts);"
|
||||
compact_gate = "if(typeof isCompactWorklogMode==='function'&&!isCompactWorklogMode()) return false;"
|
||||
compact_gate = "if(sceneMode!=='compact_worklog') return false;"
|
||||
assert transparent_gate in live
|
||||
assert compact_gate in live
|
||||
assert live.index(transparent_gate) < live.index(compact_gate), (
|
||||
@@ -1181,6 +1181,7 @@ global.$=(id)=>{{
|
||||
return findById(msgInner,id);
|
||||
}};
|
||||
let transparentMode=true;
|
||||
global.chatActivityMode=()=>transparentMode?'transparent_stream':'compact_worklog';
|
||||
global.isTransparentStream=()=>transparentMode;
|
||||
global.isCompactWorklogMode=()=>!transparentMode;
|
||||
global._anchorSceneRowsForRendering=(scene)=>scene.activity_rows||[];
|
||||
|
||||
Reference in new issue
Block a user