@nextclaw/ui 0.14.1-beta.1 → 0.14.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (179) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/dist/assets/{api-dQ6uQSZG.js → api-a14tR_z1.js} +7 -7
  3. package/dist/assets/channels-list-page-CFGkm4DT.js +8 -0
  4. package/dist/assets/chat-page-CEdavJXc.js +105 -0
  5. package/dist/assets/{config-split-page-CeFfbaqc.js → config-split-page-B5b9B0uE.js} +1 -1
  6. package/dist/assets/{confirm-dialog-C95Y4QPC.js → confirm-dialog-ClH_Ec7n.js} +1 -1
  7. package/dist/assets/{desktop-update-config-CcK6jiEb.js → desktop-update-config-DPNDnVpk.js} +1 -1
  8. package/dist/assets/{dist-DTGzeil6.js → dist-BtCS2Ucq.js} +1 -1
  9. package/dist/assets/{dist-fGogBmPA.js → dist-CLGGLm8b.js} +1 -1
  10. package/dist/assets/doc-browser-5nMWYKBD.js +1 -0
  11. package/dist/assets/doc-browser-BJRLhztv.js +1 -0
  12. package/dist/assets/doc-browser-context-D4JwMMxK.js +1 -0
  13. package/dist/assets/{ellipsis-D2F4KMiU.js → ellipsis-CtJXjIol.js} +1 -1
  14. package/dist/assets/{external-link-CcgtBK26.js → external-link-CdJiG13p.js} +1 -1
  15. package/dist/assets/index-BDN1zzMQ.js +105 -0
  16. package/dist/assets/index-g3uSZXoc.css +1 -0
  17. package/dist/assets/mcp-marketplace-page-BU0kIjhR.js +40 -0
  18. package/dist/assets/mcp-marketplace-page-sMNFSq_T.js +1 -0
  19. package/dist/assets/middleware-CkFT3R4v.js +1 -0
  20. package/dist/assets/model-config-page-D6hYXROd.js +1 -0
  21. package/dist/assets/plus-DPjb0piO.js +1 -0
  22. package/dist/assets/provider-scoped-model-input-DAX2HgmR.js +1 -0
  23. package/dist/assets/providers-config-page-BzAeaACA.js +1 -0
  24. package/dist/assets/{react-CTqdhFMk.js → react-C6cZgP44.js} +1 -1
  25. package/dist/assets/remote-B0G80uPr.js +1 -0
  26. package/dist/assets/rotate-cw-DnEB1Rju.js +1 -0
  27. package/dist/assets/runtime-config-page-C5xKaV3i.js +1 -0
  28. package/dist/assets/{save-C9fKWfVB.js → save-DKA0x4zk.js} +1 -1
  29. package/dist/assets/{search-D5FQ5q0X.js → search-BNlcoj5c.js} +1 -1
  30. package/dist/assets/{search-config-page-AMEJJNIS.js → search-config-page-Cq9uJ-N8.js} +1 -1
  31. package/dist/assets/{secrets-config-page-CcgJnvBO.js → secrets-config-page-CxSbZLBo.js} +2 -2
  32. package/dist/assets/{select-Cu5n0E-3.js → select-CvTlDZTQ.js} +1 -1
  33. package/dist/assets/{tag-chip-C5aOtjxu.js → tag-chip-8ffF2y2C.js} +1 -1
  34. package/dist/assets/use-config-DmT0o1gv.js +1 -0
  35. package/dist/assets/x-BiSSpgqB.js +1 -0
  36. package/dist/index.html +15 -14
  37. package/package.json +9 -9
  38. package/src/app/components/app-presenter-provider.tsx +11 -2
  39. package/src/app/components/layout/__tests__/app-layout.test.tsx +11 -2
  40. package/src/app/components/layout/__tests__/sidebar.layout.test.tsx +110 -79
  41. package/src/app/components/layout/app-layout.tsx +18 -4
  42. package/src/app/components/layout/sidebar-items.tsx +194 -71
  43. package/src/app/components/layout/sidebar-rail.styles.ts +15 -0
  44. package/src/app/components/layout/sidebar.tsx +340 -83
  45. package/src/app/managers/viewport-layout.manager.ts +10 -0
  46. package/src/app/stores/viewport-layout.store.ts +39 -3
  47. package/src/features/agents/components/__tests__/agents-page.test.tsx +62 -39
  48. package/src/features/agents/components/agents-page.tsx +10 -6
  49. package/src/features/chat/components/conversation/__tests__/chat-conversation-header-section.test.tsx +145 -0
  50. package/src/features/chat/components/conversation/__tests__/chat-conversation-panel.test.tsx +69 -762
  51. package/src/features/chat/components/conversation/__tests__/chat-conversation-workspace-section.test.tsx +132 -0
  52. package/src/features/chat/components/conversation/chat-conversation-content.tsx +22 -15
  53. package/src/features/chat/components/conversation/chat-conversation-header-section.tsx +14 -15
  54. package/src/features/chat/components/conversation/chat-conversation-panel.tsx +18 -18
  55. package/src/features/chat/components/conversation/chat-conversation-workspace-section.tsx +10 -4
  56. package/src/features/chat/components/layout/__tests__/chat-sidebar-read-state.test.tsx +52 -11
  57. package/src/features/chat/components/layout/__tests__/chat-sidebar.test.tsx +77 -12
  58. package/src/features/chat/components/layout/chat-sidebar-desktop-layout.tsx +247 -0
  59. package/src/features/chat/components/layout/chat-sidebar-toolbar.tsx +182 -21
  60. package/src/features/chat/components/layout/chat-sidebar-utility-menu.tsx +82 -25
  61. package/src/features/chat/components/layout/chat-sidebar.tsx +79 -93
  62. package/src/features/chat/components/providers/chat-presenter.provider.tsx +0 -6
  63. package/src/features/chat/features/conversation/components/session-conversation-area.tsx +289 -0
  64. package/src/features/chat/features/conversation/components/session-conversation-input.tsx +427 -0
  65. package/src/features/chat/features/conversation/hooks/use-session-conversation-controller.ts +204 -0
  66. package/src/features/chat/features/conversation/hooks/use-session-conversation-input-attachments.ts +66 -0
  67. package/src/features/chat/features/{input/hooks/use-chat-input-bar-query-state.ts → conversation/hooks/use-session-conversation-input-query.ts} +32 -17
  68. package/src/features/chat/features/conversation/hooks/use-session-conversation-input-state.ts +281 -0
  69. package/src/features/chat/features/conversation/utils/session-conversation-input-toolbar.utils.ts +158 -0
  70. package/src/features/chat/features/input/hooks/__tests__/use-chat-input-surface-state.test.tsx +56 -0
  71. package/src/features/chat/features/input/hooks/use-chat-input-surface-state.ts +117 -0
  72. package/src/features/chat/features/input/hooks/use-chat-model-favorites.ts +2 -1
  73. package/src/features/chat/features/input/input-surface-plugins/__tests__/panel-app-reference-plugin.test.ts +77 -0
  74. package/src/features/chat/features/input/input-surface-plugins/__tests__/slash-command-plugin.test.ts +108 -0
  75. package/src/features/chat/features/input/input-surface-plugins/chat-input-product-plugin-adapters.types.ts +10 -0
  76. package/src/features/chat/features/input/input-surface-plugins/input-surface-search.utils.ts +108 -0
  77. package/src/features/chat/features/input/input-surface-plugins/panel-app-reference-plugin.utils.ts +108 -0
  78. package/src/features/chat/features/input/input-surface-plugins/slash-command-plugin.utils.ts +161 -0
  79. package/src/features/chat/features/input/utils/__tests__/chat-composer-state.utils.test.ts +22 -1
  80. package/src/features/chat/features/input/utils/__tests__/chat-inline-token.utils.test.ts +26 -13
  81. package/src/features/chat/features/input/utils/__tests__/ncp-chat-input-availability.utils.test.ts +7 -28
  82. package/src/features/chat/features/input/utils/chat-composer-state.utils.ts +6 -0
  83. package/src/features/chat/features/input/utils/chat-inline-token.utils.ts +26 -51
  84. package/src/features/chat/features/input/utils/chat-input-bar.utils.ts +2 -0
  85. package/src/features/chat/features/input/utils/ncp-chat-input-availability.utils.ts +5 -6
  86. package/src/features/chat/features/message/components/__tests__/chat-message-list.container.test.tsx +47 -12
  87. package/src/features/chat/features/message/components/chat-message-list.container.tsx +93 -12
  88. package/src/features/chat/features/message/utils/__tests__/chat-message.utils.test.ts +31 -12
  89. package/src/features/chat/features/message/utils/chat-message-markdown-part.utils.ts +38 -0
  90. package/src/features/chat/features/message/utils/chat-message-part.utils.ts +1 -1
  91. package/src/features/chat/features/session/components/chat-sidebar-project-groups.tsx +5 -4
  92. package/src/features/chat/features/session/components/chat-sidebar-session-list.tsx +2 -2
  93. package/src/features/chat/features/session/hooks/__tests__/use-chat-session-project.test.tsx +3 -30
  94. package/src/features/chat/features/session/hooks/use-chat-session-project.ts +0 -5
  95. package/src/features/chat/features/session/utils/chat-run-metadata.utils.ts +8 -0
  96. package/src/features/chat/features/session-type/components/__tests__/{chat-sidebar-create-menu.test.tsx → chat-session-type-menu.test.tsx} +5 -5
  97. package/src/features/chat/features/session-type/components/__tests__/chat-session-type-option-item.test.tsx +29 -1
  98. package/src/features/chat/features/session-type/components/{chat-sidebar-create-menu.tsx → chat-session-type-menu.tsx} +13 -9
  99. package/src/features/chat/features/session-type/components/chat-session-type-option-item.tsx +17 -5
  100. package/src/features/chat/features/session-type/hooks/__tests__/use-chat-new-session-type-preference.test.tsx +152 -0
  101. package/src/features/chat/features/session-type/hooks/use-chat-new-session-type-preference.ts +159 -0
  102. package/src/features/chat/features/welcome/components/__tests__/chat-conversation-welcome.test.tsx +49 -31
  103. package/src/features/chat/features/welcome/components/__tests__/chat-welcome.test.tsx +2 -2
  104. package/src/features/chat/features/welcome/components/chat-conversation-welcome.tsx +21 -10
  105. package/src/features/chat/features/welcome/components/chat-welcome-session-type-picker.tsx +2 -2
  106. package/src/features/chat/features/welcome/components/chat-welcome.tsx +2 -2
  107. package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-panel-content.test.tsx +54 -0
  108. package/src/features/chat/features/workspace/components/chat-session-workspace-panel-content.tsx +44 -76
  109. package/src/features/chat/features/workspace/components/chat-session-workspace-panel-nav.tsx +5 -1
  110. package/src/features/chat/features/workspace/components/chat-session-workspace-panel.tsx +7 -1
  111. package/src/features/chat/features/workspace/hooks/use-chat-conversation-workspace-state.ts +40 -31
  112. package/src/features/chat/features/workspace/utils/__tests__/chat-workspace-panel-view-model.utils.test.ts +59 -1
  113. package/src/features/chat/features/workspace/utils/chat-thread-workspace-session.utils.ts +109 -0
  114. package/src/features/chat/features/workspace/utils/chat-workspace-panel-view-model.utils.ts +44 -4
  115. package/src/features/chat/index.ts +0 -1
  116. package/src/features/chat/managers/__tests__/chat-session-list.manager.test.ts +51 -99
  117. package/src/features/chat/managers/__tests__/chat-thread.manager.test.ts +135 -21
  118. package/src/features/chat/managers/chat-session-list.manager.ts +12 -43
  119. package/src/features/chat/managers/chat-thread.manager.ts +108 -34
  120. package/src/features/chat/pages/__tests__/ncp-chat-page.test.ts +48 -1
  121. package/src/features/chat/pages/__tests__/ncp-chat-page.test.tsx +72 -0
  122. package/src/features/chat/pages/ncp-chat-page.tsx +0 -122
  123. package/src/features/chat/presenters/chat.presenter.ts +2 -19
  124. package/src/features/chat/stores/__tests__/chat-thread.store.test.ts +31 -0
  125. package/src/features/chat/stores/chat-thread.store.ts +42 -26
  126. package/src/features/marketplace/components/__tests__/marketplace-page.test.tsx +24 -0
  127. package/src/features/marketplace/components/curated-shelves/marketplace-shelf-card.tsx +8 -3
  128. package/src/features/marketplace/components/marketplace-item-list-view.tsx +2 -2
  129. package/src/features/marketplace/components/marketplace-list-card.tsx +124 -98
  130. package/src/features/marketplace/components/marketplace-page-parts.tsx +11 -6
  131. package/src/features/panel-apps/hooks/use-panel-apps.ts +2 -1
  132. package/src/platforms/desktop/components/__tests__/desktop-app-shell.test.tsx +50 -10
  133. package/src/platforms/desktop/components/desktop-app-shell.tsx +34 -10
  134. package/src/platforms/desktop/components/desktop-window-chrome.tsx +41 -16
  135. package/src/shared/components/common/__tests__/agent-avatar.test.tsx +3 -1
  136. package/src/shared/components/common/agent-avatar.tsx +5 -2
  137. package/src/shared/components/ui/tab-strip/__tests__/compact-tab-strip.test.tsx +24 -1
  138. package/src/shared/components/ui/tab-strip/compact-tab-strip.tsx +8 -4
  139. package/src/shared/lib/api/index.ts +1 -0
  140. package/src/shared/lib/api/preferences/preference-keys.config.ts +9 -0
  141. package/src/shared/lib/i18n/locales/en-US/chat.json +20 -2
  142. package/src/shared/lib/i18n/locales/en-US/core.json +2 -0
  143. package/src/shared/lib/i18n/locales/en-US/marketplace.json +2 -0
  144. package/src/shared/lib/i18n/locales/zh-CN/chat.json +20 -2
  145. package/src/shared/lib/i18n/locales/zh-CN/core.json +2 -0
  146. package/src/shared/lib/i18n/locales/zh-CN/marketplace.json +2 -0
  147. package/src/shared/lib/ui-document-title/__tests__/ui-document-title.test.ts +49 -0
  148. package/src/shared/lib/ui-document-title/index.ts +50 -21
  149. package/dist/assets/channels-list-page-DfpjB8XB.js +0 -8
  150. package/dist/assets/chat-page-D3QaEqjs.js +0 -105
  151. package/dist/assets/doc-browser-CuBTcBEZ.js +0 -1
  152. package/dist/assets/doc-browser-DVHhEb96.js +0 -1
  153. package/dist/assets/doc-browser-context-BfMXwnrz.js +0 -1
  154. package/dist/assets/index-ByJCbQqr.css +0 -1
  155. package/dist/assets/index-DjXqiloY.js +0 -103
  156. package/dist/assets/mcp-marketplace-page-98-V__3u.js +0 -1
  157. package/dist/assets/mcp-marketplace-page-BNq_PNmO.js +0 -40
  158. package/dist/assets/model-config-page-aAUkZkSX.js +0 -1
  159. package/dist/assets/plus-1Rxl5FlV.js +0 -1
  160. package/dist/assets/provider-scoped-model-input-we4_Z4gP.js +0 -1
  161. package/dist/assets/providers-config-page-CtMkPSyu.js +0 -1
  162. package/dist/assets/remote-fQ7N_r8u.js +0 -1
  163. package/dist/assets/rotate-cw-CzfIeAJj.js +0 -1
  164. package/dist/assets/runtime-config-page-TD1UrTbG.js +0 -1
  165. package/dist/assets/use-config-D8TESeo6.js +0 -1
  166. package/dist/assets/x-1qETdQ70.js +0 -1
  167. package/src/features/chat/components/conversation/chat-conversation-alerts.tsx +0 -37
  168. package/src/features/chat/features/input/components/__tests__/chat-attachment-upload-limit.test.ts +0 -38
  169. package/src/features/chat/features/input/components/chat-input-bar.container.tsx +0 -496
  170. package/src/features/chat/features/message/utils/chat-message-inline-content.utils.ts +0 -95
  171. package/src/features/chat/managers/__tests__/chat-input.manager.test.ts +0 -448
  172. package/src/features/chat/managers/__tests__/chat-run-snapshot.manager.test.ts +0 -129
  173. package/src/features/chat/managers/__tests__/chat-run.manager.test.ts +0 -236
  174. package/src/features/chat/managers/__tests__/chat-session-preference-sync.manager.test.ts +0 -219
  175. package/src/features/chat/managers/chat-input.manager.ts +0 -430
  176. package/src/features/chat/managers/chat-run.manager.ts +0 -110
  177. package/src/features/chat/managers/chat-session-preference-sync.manager.ts +0 -142
  178. package/src/features/chat/stores/chat-input.store.ts +0 -104
  179. /package/dist/assets/{config-hints-CTqBnCDp.js → config-hints-BkYBc7z0.js} +0 -0
@@ -0,0 +1,289 @@
1
+ import { useCallback, useEffect, useMemo, useRef } from 'react';
2
+ import { useLocation } from 'react-router-dom';
3
+
4
+ import { useAppPresenter } from '@/app/components/app-presenter-provider';
5
+ import { ChatConversationContent } from '@/features/chat/components/conversation/chat-conversation-content';
6
+ import { usePresenter } from '@/features/chat/components/providers/chat-presenter.provider';
7
+ import {
8
+ isNcpAgentStartupUnavailableErrorMessage,
9
+ useNcpSessionConversation,
10
+ } from '@/features/chat/features/ncp/hooks/use-ncp-session-conversation';
11
+ import { isNcpChatRuntimeBlocked, resolveNcpChatSendErrorMessage } from '@/features/chat/features/runtime/utils/ncp-chat-runtime-availability.utils';
12
+ import { buildChatContextWindowIndicator } from '@/features/chat/features/session/utils/chat-context-window-indicator.utils';
13
+ import { readNcpContextWindowValue } from '@/features/chat/features/session/utils/ncp-session-context-metadata.utils';
14
+ import { ChatConversationWelcome } from '@/features/chat/features/welcome/components/chat-conversation-welcome';
15
+ import { useChatSessionListStore } from '@/features/chat/stores/chat-session-list.store';
16
+ import { useSystemStatus } from '@/features/system-status';
17
+ import { t } from '@/shared/lib/i18n';
18
+
19
+ import {
20
+ useSessionConversationController,
21
+ type SessionConversationMaterializationContext,
22
+ } from '@/features/chat/features/conversation/hooks/use-session-conversation-controller';
23
+ import { useSessionConversationInputQuery } from '@/features/chat/features/conversation/hooks/use-session-conversation-input-query';
24
+ import { useSessionConversationInputState } from '@/features/chat/features/conversation/hooks/use-session-conversation-input-state';
25
+ import { SessionConversationInput } from './session-conversation-input';
26
+
27
+ type SessionConversationAreaProps = {
28
+ readonly consumeDraftIntent?: boolean;
29
+ readonly materializationContext?: SessionConversationMaterializationContext | null;
30
+ readonly onSessionMaterialized?: (sessionKey: string) => void;
31
+ readonly sessionKey: string | null;
32
+ readonly showWelcomeForDraft?: boolean;
33
+ };
34
+
35
+ function useSessionConversationDraftIntent(params: {
36
+ readonly consumeDraftIntent: boolean;
37
+ readonly applyPromptSuggestion: (prompt: string) => void;
38
+ }) {
39
+ const { applyPromptSuggestion, consumeDraftIntent } = params;
40
+ const appPresenter = useAppPresenter();
41
+ const presenter = usePresenter();
42
+ useEffect(() => {
43
+ if (!consumeDraftIntent) {
44
+ return undefined;
45
+ }
46
+ const applyIntent = (intent: { id: number; prompt: string }) => {
47
+ presenter.chatSessionListManager.createSession();
48
+ presenter.chatSessionListManager.setSelectedAgentId('main');
49
+ applyPromptSuggestion(intent.prompt);
50
+ appPresenter.chatDraftIntentManager.markConsumed(intent.id);
51
+ };
52
+ const unsubscribe = appPresenter.chatDraftIntentManager.subscribe(applyIntent);
53
+ const pendingIntent = appPresenter.chatDraftIntentManager.consumePending();
54
+ if (pendingIntent) {
55
+ applyIntent(pendingIntent);
56
+ }
57
+ return unsubscribe;
58
+ }, [
59
+ appPresenter,
60
+ applyPromptSuggestion,
61
+ consumeDraftIntent,
62
+ presenter,
63
+ ]);
64
+ }
65
+
66
+ type ChatDraftRouteState = {
67
+ readonly sessionType?: unknown;
68
+ readonly projectRoot?: unknown;
69
+ };
70
+
71
+ function readChatDraftRouteState(value: unknown): ChatDraftRouteState | null {
72
+ if (!value || typeof value !== 'object') {
73
+ return null;
74
+ }
75
+ const draft = (value as { chatDraft?: unknown }).chatDraft;
76
+ if (!draft || typeof draft !== 'object') {
77
+ return null;
78
+ }
79
+ return draft as ChatDraftRouteState;
80
+ }
81
+
82
+ function useSessionConversationDraftRouteState(params: {
83
+ readonly sessionKey: string | null;
84
+ readonly setPendingProjectRoot: (projectRoot: string | null) => void;
85
+ readonly setPendingSessionType: (sessionType: string) => void;
86
+ }) {
87
+ const {
88
+ sessionKey,
89
+ setPendingProjectRoot,
90
+ setPendingSessionType,
91
+ } = params;
92
+ const location = useLocation();
93
+ const appliedRouteStateKeyRef = useRef<string | null>(null);
94
+ useEffect(() => {
95
+ if (sessionKey) {
96
+ return;
97
+ }
98
+ const draftState = readChatDraftRouteState(location.state);
99
+ if (!draftState) {
100
+ return;
101
+ }
102
+ const signature = [
103
+ location.key,
104
+ typeof draftState.sessionType === 'string' ? draftState.sessionType : '',
105
+ typeof draftState.projectRoot === 'string' ? draftState.projectRoot : '',
106
+ ].join(':');
107
+ if (appliedRouteStateKeyRef.current === signature) {
108
+ return;
109
+ }
110
+ appliedRouteStateKeyRef.current = signature;
111
+ if (typeof draftState.sessionType === 'string' && draftState.sessionType.trim()) {
112
+ setPendingSessionType(draftState.sessionType);
113
+ }
114
+ setPendingProjectRoot(
115
+ typeof draftState.projectRoot === 'string' && draftState.projectRoot.trim()
116
+ ? draftState.projectRoot
117
+ : null,
118
+ );
119
+ }, [
120
+ location.key,
121
+ location.state,
122
+ sessionKey,
123
+ setPendingProjectRoot,
124
+ setPendingSessionType,
125
+ ]);
126
+ }
127
+
128
+ function SessionConversationAlerts({
129
+ inputQuery,
130
+ }: {
131
+ readonly inputQuery: ReturnType<typeof useSessionConversationInputQuery>;
132
+ }) {
133
+ const presenter = usePresenter();
134
+ const shouldShowProviderHint =
135
+ inputQuery.isProviderStateResolved && inputQuery.modelOptions.length === 0;
136
+ const sessionTypeUnavailableMessage =
137
+ inputQuery.sessionTypeState.sessionTypeUnavailableMessage?.trim() || null;
138
+
139
+ return (
140
+ <>
141
+ {shouldShowProviderHint ? (
142
+ <div className="px-4 py-2.5 border-b border-amber-200/70 bg-amber-50/70 flex items-center justify-between gap-3 shrink-0 sm:px-5">
143
+ <span className="text-xs text-amber-800">
144
+ {t('chatModelNoOptions')}
145
+ </span>
146
+ <button
147
+ type="button"
148
+ onClick={presenter.chatUiManager.goToProviders}
149
+ className="text-xs font-semibold text-amber-900 underline-offset-2 hover:underline"
150
+ >
151
+ {t('chatGoConfigureProvider')}
152
+ </button>
153
+ </div>
154
+ ) : null}
155
+ {inputQuery.sessionTypeState.sessionTypeUnavailable && sessionTypeUnavailableMessage ? (
156
+ <div className="px-4 py-2.5 border-b border-amber-200/70 bg-amber-50/70 shrink-0 sm:px-5">
157
+ <span className="text-xs text-amber-800">
158
+ {sessionTypeUnavailableMessage}
159
+ </span>
160
+ </div>
161
+ ) : null}
162
+ </>
163
+ );
164
+ }
165
+
166
+ export function SessionConversationArea(props: SessionConversationAreaProps) {
167
+ const {
168
+ consumeDraftIntent = false,
169
+ materializationContext = null,
170
+ onSessionMaterialized,
171
+ sessionKey,
172
+ showWelcomeForDraft = true,
173
+ } = props;
174
+ const systemStatus = useSystemStatus();
175
+ const selectedAgentId = useChatSessionListStore(
176
+ (state) => state.snapshot.selectedAgentId,
177
+ );
178
+ const agent = useNcpSessionConversation(sessionKey ?? undefined);
179
+ const {
180
+ inputActions,
181
+ inputSnapshot,
182
+ } = useSessionConversationInputState();
183
+ const inputQuery = useSessionConversationInputQuery({
184
+ sessionKey,
185
+ inputSnapshot,
186
+ setPendingSessionType: inputActions.setPendingSessionType,
187
+ });
188
+ useSessionConversationDraftRouteState({
189
+ sessionKey,
190
+ setPendingProjectRoot: inputActions.setPendingProjectRoot,
191
+ setPendingSessionType: inputActions.setPendingSessionType,
192
+ });
193
+ const isRuntimeBlocked = isNcpChatRuntimeBlocked(systemStatus);
194
+ const currentSessionRunning = agent.isRunning || inputQuery.selectedSession?.status === 'running';
195
+ const rawLastSendError =
196
+ agent.hydrateError?.message ?? agent.snapshot.error?.message ?? null;
197
+ const filteredLastSendError =
198
+ systemStatus.phase === 'ready' &&
199
+ isNcpAgentStartupUnavailableErrorMessage(rawLastSendError)
200
+ ? null
201
+ : rawLastSendError;
202
+ const lastSendError =
203
+ isRuntimeBlocked
204
+ ? null
205
+ : systemStatus.phase === 'ready'
206
+ ? filteredLastSendError
207
+ : resolveNcpChatSendErrorMessage({
208
+ message: filteredLastSendError,
209
+ status: systemStatus,
210
+ });
211
+ const controllerAgent = useMemo(() => ({
212
+ ...agent,
213
+ isRunning: currentSessionRunning,
214
+ isSending: agent.isSending || currentSessionRunning,
215
+ }), [agent, currentSessionRunning]);
216
+ const controller = useSessionConversationController({
217
+ agent: controllerAgent,
218
+ inputSnapshot,
219
+ inputQuery,
220
+ isRuntimeBlocked,
221
+ materializationContext,
222
+ selectedAgentId,
223
+ sessionKey,
224
+ onSessionMaterialized,
225
+ resetComposer: inputActions.resetComposer,
226
+ restoreComposer: inputActions.restoreComposer,
227
+ setSendError: inputActions.setSendError,
228
+ });
229
+ const displayInputSnapshot = useMemo(() => ({
230
+ ...inputSnapshot,
231
+ sendError: lastSendError ?? inputSnapshot.sendError,
232
+ }), [inputSnapshot, lastSendError]);
233
+ const contextWindow = useMemo(
234
+ () => buildChatContextWindowIndicator(readNcpContextWindowValue(agent.snapshot.contextWindow)),
235
+ [agent.snapshot.contextWindow],
236
+ );
237
+ useSessionConversationDraftIntent({
238
+ consumeDraftIntent,
239
+ applyPromptSuggestion: inputActions.applyPromptSuggestion,
240
+ });
241
+ const renderInput = useCallback((surface: 'default' | 'embedded') => (
242
+ <SessionConversationInput
243
+ contextWindow={contextWindow}
244
+ controller={controller}
245
+ inputActions={inputActions}
246
+ inputQuery={inputQuery}
247
+ inputSnapshot={displayInputSnapshot}
248
+ surface={surface}
249
+ />
250
+ ), [
251
+ contextWindow,
252
+ controller,
253
+ displayInputSnapshot,
254
+ inputActions,
255
+ inputQuery,
256
+ ]);
257
+ const showWelcome =
258
+ showWelcomeForDraft &&
259
+ !sessionKey &&
260
+ agent.visibleMessages.length === 0 &&
261
+ !agent.isHydrating &&
262
+ !controller.isSending;
263
+
264
+ return (
265
+ <>
266
+ <SessionConversationAlerts inputQuery={inputQuery} />
267
+ <ChatConversationContent
268
+ isAwaitingAssistantOutput={controller.isSending && currentSessionRunning}
269
+ isHistoryLoading={agent.isHydrating}
270
+ isSending={controller.isSending}
271
+ messages={agent.visibleMessages}
272
+ sessionKey={sessionKey}
273
+ showWelcome={showWelcome}
274
+ welcomeSlot={
275
+ <ChatConversationWelcome
276
+ inputSlot={renderInput('embedded')}
277
+ pendingProjectRoot={inputSnapshot.pendingProjectRoot}
278
+ pendingSessionType={inputSnapshot.pendingSessionType}
279
+ selectedSessionTypeValue={inputSnapshot.selectedSessionType}
280
+ onSelectProjectRoot={inputActions.setPendingProjectRoot}
281
+ onSelectPrompt={inputActions.applyPromptSuggestion}
282
+ onSelectSessionType={inputActions.setPendingSessionType}
283
+ />
284
+ }
285
+ />
286
+ {showWelcome ? null : renderInput('default')}
287
+ </>
288
+ );
289
+ }