@nextclaw/ui 0.11.13 → 0.11.14
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.
- package/CHANGELOG.md +6 -0
- package/dist/assets/{ChannelsList-BlQD1VuM.js → ChannelsList-CvK4qHfg.js} +1 -1
- package/dist/assets/{ChatPage-DBvm558n.js → ChatPage-Co3GqIVP.js} +15 -15
- package/dist/assets/{DocBrowser-DTww3NZc.js → DocBrowser-BFmW6e-4.js} +1 -1
- package/dist/assets/{LogoBadge-D0ogG1ut.js → LogoBadge-DZL-zQTr.js} +1 -1
- package/dist/assets/{MarketplacePage-DTHw6n0X.js → MarketplacePage-B__MZRrD.js} +1 -1
- package/dist/assets/{McpMarketplacePage-BikE0mBl.js → McpMarketplacePage-C_VKm1uq.js} +1 -1
- package/dist/assets/{ModelConfig-CvM__Pz1.js → ModelConfig-CqJubuwU.js} +1 -1
- package/dist/assets/{ProvidersList-DtZWZlL0.js → ProvidersList-BoSsFBk5.js} +1 -1
- package/dist/assets/{RemoteAccessPage-E5fT1pem.js → RemoteAccessPage-S1ChRWMX.js} +1 -1
- package/dist/assets/{RuntimeConfig-DyZNiqYT.js → RuntimeConfig-WnFUsayT.js} +1 -1
- package/dist/assets/{SearchConfig-C1bhOCNX.js → SearchConfig-D9V07oqj.js} +1 -1
- package/dist/assets/{SecretsConfig-CYmy1Sqy.js → SecretsConfig-Ci8sEzaV.js} +1 -1
- package/dist/assets/{SessionsConfig-DSlhPpIE.js → SessionsConfig-5Nznhx9P.js} +1 -1
- package/dist/assets/{chat-session-display-D9YuDGe3.js → chat-session-display-D0ZcEkUq.js} +1 -1
- package/dist/assets/index-BvCYcN48.js +8 -0
- package/dist/assets/{label-C7Xd_hqz.js → label-AurG3ZpO.js} +1 -1
- package/dist/assets/{page-layout-VxCaUcrD.js → page-layout-Q2hHkfJy.js} +1 -1
- package/dist/assets/{popover-CC4znqAM.js → popover-BKInm43u.js} +1 -1
- package/dist/assets/{security-config-7eVxJq8b.js → security-config-BbPGNJAB.js} +1 -1
- package/dist/assets/{skeleton-DhZRDdHm.js → skeleton-CuKw6-Ww.js} +1 -1
- package/dist/assets/{status-dot-Bi7Ze-LS.js → status-dot-DLk8UxLB.js} +1 -1
- package/dist/assets/{switch-COBEivEX.js → switch-BxMSKsQS.js} +1 -1
- package/dist/assets/{tabs-custom-B9j40wuu.js → tabs-custom-B6gK-RY6.js} +1 -1
- package/dist/assets/{useConfirmDialog-N8nuxOq-.js → useConfirmDialog-Dth62a0a.js} +1 -1
- package/dist/index.html +1 -1
- package/package.json +3 -3
- package/src/components/chat/adapters/chat-input-bar.adapter.test.ts +39 -0
- package/src/components/chat/adapters/chat-input-bar.adapter.ts +4 -1
- package/src/components/chat/containers/chat-input-bar.container.tsx +8 -10
- package/src/components/chat/ncp/NcpChatPage.tsx +11 -1
- package/src/components/chat/ncp/ncp-chat-realtime-reload.test.ts +44 -0
- package/src/components/chat/ncp/ncp-chat-realtime-reload.ts +20 -0
- package/src/lib/i18n.ts +0 -2
- package/dist/assets/index-BBz4mi7g.js +0 -8
package/dist/index.html
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<link rel="icon" type="image/svg+xml" href="/logo.svg" />
|
|
7
7
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
8
8
|
<title>NextClaw</title>
|
|
9
|
-
<script type="module" crossorigin src="/assets/index-
|
|
9
|
+
<script type="module" crossorigin src="/assets/index-BvCYcN48.js"></script>
|
|
10
10
|
<link rel="modulepreload" crossorigin href="/assets/vendor-MCpnpiKt.js">
|
|
11
11
|
<link rel="stylesheet" crossorigin href="/assets/index-CfVmBgkf.css">
|
|
12
12
|
</head>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextclaw/ui",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.14",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -28,10 +28,10 @@
|
|
|
28
28
|
"tailwind-merge": "^2.5.4",
|
|
29
29
|
"zod": "^3.23.8",
|
|
30
30
|
"zustand": "^5.0.2",
|
|
31
|
-
"@nextclaw/
|
|
31
|
+
"@nextclaw/agent-chat": "0.1.4",
|
|
32
32
|
"@nextclaw/agent-chat-ui": "0.2.14",
|
|
33
|
+
"@nextclaw/ncp": "0.4.1",
|
|
33
34
|
"@nextclaw/ncp-react": "0.4.5",
|
|
34
|
-
"@nextclaw/agent-chat": "0.1.4",
|
|
35
35
|
"@nextclaw/ncp-http-agent-client": "0.3.5"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
@@ -175,4 +175,43 @@ describe('buildModelToolbarSelect', () => {
|
|
|
175
175
|
}
|
|
176
176
|
]);
|
|
177
177
|
});
|
|
178
|
+
|
|
179
|
+
it('preserves recent model order from newest to oldest', () => {
|
|
180
|
+
const select = buildModelToolbarSelect({
|
|
181
|
+
modelOptions: [
|
|
182
|
+
{
|
|
183
|
+
value: 'openai/gpt-5',
|
|
184
|
+
modelLabel: 'gpt-5',
|
|
185
|
+
providerLabel: 'OpenAI'
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
value: 'anthropic/claude-sonnet-4',
|
|
189
|
+
modelLabel: 'claude-sonnet-4',
|
|
190
|
+
providerLabel: 'Anthropic'
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
value: 'deepseek/deepseek-chat',
|
|
194
|
+
modelLabel: 'deepseek-chat',
|
|
195
|
+
providerLabel: 'DeepSeek'
|
|
196
|
+
}
|
|
197
|
+
],
|
|
198
|
+
recentModelValues: ['deepseek/deepseek-chat', 'openai/gpt-5', 'anthropic/claude-sonnet-4'],
|
|
199
|
+
selectedModel: 'openai/gpt-5',
|
|
200
|
+
isModelOptionsLoading: false,
|
|
201
|
+
hasModelOptions: true,
|
|
202
|
+
onValueChange: vi.fn(),
|
|
203
|
+
texts: {
|
|
204
|
+
modelSelectPlaceholder: 'Select model',
|
|
205
|
+
modelNoOptionsLabel: 'No models',
|
|
206
|
+
recentModelsLabel: 'Recent',
|
|
207
|
+
allModelsLabel: 'All models'
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
expect(select.groups?.[0]?.options.map((option) => option.value)).toEqual([
|
|
212
|
+
'deepseek/deepseek-chat',
|
|
213
|
+
'openai/gpt-5',
|
|
214
|
+
'anthropic/claude-sonnet-4'
|
|
215
|
+
]);
|
|
216
|
+
});
|
|
178
217
|
});
|
|
@@ -251,7 +251,10 @@ export function buildModelToolbarSelect(params: {
|
|
|
251
251
|
const resolvedModelOption = selectedModelOption ?? fallbackModelOption;
|
|
252
252
|
const resolvedValue = params.hasModelOptions ? resolvedModelOption?.value : undefined;
|
|
253
253
|
const recentValueSet = new Set(params.recentModelValues ?? []);
|
|
254
|
-
const
|
|
254
|
+
const modelOptionMap = new Map(params.modelOptions.map((option) => [option.value, option] as const));
|
|
255
|
+
const recentOptions = (params.recentModelValues ?? [])
|
|
256
|
+
.map((value) => modelOptionMap.get(value))
|
|
257
|
+
.filter((option): option is ChatModelRecord => Boolean(option));
|
|
255
258
|
const remainingOptions = params.modelOptions.filter((option) => !recentValueSet.has(option.value));
|
|
256
259
|
const optionGroups =
|
|
257
260
|
recentOptions.length > 0
|
|
@@ -108,14 +108,10 @@ export function ChatInputBarContainer() {
|
|
|
108
108
|
[snapshot.skillRecords, officialSkillBadgeLabel]
|
|
109
109
|
);
|
|
110
110
|
const modelRecords = useMemo(() => toModelRecords(snapshot.modelOptions), [snapshot.modelOptions]);
|
|
111
|
-
const recentModelValues =
|
|
112
|
-
() =>
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
minAvailableCount: CHAT_RECENT_MODELS_MIN_OPTIONS
|
|
116
|
-
}),
|
|
117
|
-
[modelRecords, snapshot.selectedModel]
|
|
118
|
-
);
|
|
111
|
+
const recentModelValues = chatRecentModelsManager.resolveVisible({
|
|
112
|
+
availableValues: modelRecords.map((option) => option.value),
|
|
113
|
+
minAvailableCount: CHAT_RECENT_MODELS_MIN_OPTIONS
|
|
114
|
+
});
|
|
119
115
|
|
|
120
116
|
const hasModelOptions = modelRecords.length > 0;
|
|
121
117
|
const isModelOptionsLoading = !snapshot.isProviderStateResolved && !hasModelOptions;
|
|
@@ -128,6 +124,8 @@ export function ChatInputBarContainer() {
|
|
|
128
124
|
: hasModelOptions
|
|
129
125
|
? t('chatInputPlaceholder')
|
|
130
126
|
: t('chatModelNoOptions');
|
|
127
|
+
const recentModelsLabel = language === 'zh' ? '最近选择' : 'Recent';
|
|
128
|
+
const allModelsLabel = language === 'zh' ? '全部模型' : 'All models';
|
|
131
129
|
|
|
132
130
|
const slashItems = useMemo(
|
|
133
131
|
() => buildChatSlashItems(skillRecords, slashQuery ?? '', slashTexts),
|
|
@@ -191,8 +189,8 @@ export function ChatInputBarContainer() {
|
|
|
191
189
|
texts: {
|
|
192
190
|
modelSelectPlaceholder: t('chatSelectModel'),
|
|
193
191
|
modelNoOptionsLabel: t('chatModelNoOptions'),
|
|
194
|
-
recentModelsLabel
|
|
195
|
-
allModelsLabel
|
|
192
|
+
recentModelsLabel,
|
|
193
|
+
allModelsLabel
|
|
196
194
|
}
|
|
197
195
|
}),
|
|
198
196
|
buildThinkingToolbarSelect({
|
|
@@ -23,6 +23,7 @@ import { resolveSessionTypeLabel } from '@/components/chat/useChatSessionTypeSta
|
|
|
23
23
|
import { useConfirmDialog } from '@/hooks/useConfirmDialog';
|
|
24
24
|
import { normalizeRequestedSkills } from '@/lib/chat-runtime-utils';
|
|
25
25
|
import { appClient } from '@/transport';
|
|
26
|
+
import { resolveNcpChatRealtimeReloadAction } from '@/components/chat/ncp/ncp-chat-realtime-reload';
|
|
26
27
|
|
|
27
28
|
function buildNcpSendMetadata(payload: {
|
|
28
29
|
model?: string;
|
|
@@ -158,10 +159,19 @@ export function NcpChatPage({ view }: ChatPageProps) {
|
|
|
158
159
|
|
|
159
160
|
useEffect(() => {
|
|
160
161
|
const flushRealtimeReload = () => {
|
|
161
|
-
|
|
162
|
+
const action = resolveNcpChatRealtimeReloadAction({
|
|
163
|
+
isHydrating: agent.isHydrating,
|
|
164
|
+
isRunning: agent.isRunning,
|
|
165
|
+
isSending: agent.isSending,
|
|
166
|
+
});
|
|
167
|
+
if (action === 'defer') {
|
|
162
168
|
pendingRealtimeReloadRef.current = true;
|
|
163
169
|
return;
|
|
164
170
|
}
|
|
171
|
+
if (action === 'skip') {
|
|
172
|
+
pendingRealtimeReloadRef.current = false;
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
165
175
|
pendingRealtimeReloadRef.current = false;
|
|
166
176
|
void agent.reloadSeed();
|
|
167
177
|
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { resolveNcpChatRealtimeReloadAction } from '@/components/chat/ncp/ncp-chat-realtime-reload';
|
|
3
|
+
|
|
4
|
+
describe('resolveNcpChatRealtimeReloadAction', () => {
|
|
5
|
+
it('defers reload while the page is hydrating', () => {
|
|
6
|
+
expect(
|
|
7
|
+
resolveNcpChatRealtimeReloadAction({
|
|
8
|
+
isHydrating: true,
|
|
9
|
+
isRunning: false,
|
|
10
|
+
isSending: false,
|
|
11
|
+
}),
|
|
12
|
+
).toBe('defer');
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('skips reload while the current session run is still active', () => {
|
|
16
|
+
expect(
|
|
17
|
+
resolveNcpChatRealtimeReloadAction({
|
|
18
|
+
isHydrating: false,
|
|
19
|
+
isRunning: true,
|
|
20
|
+
isSending: false,
|
|
21
|
+
}),
|
|
22
|
+
).toBe('skip');
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('skips reload while the current page is still sending', () => {
|
|
26
|
+
expect(
|
|
27
|
+
resolveNcpChatRealtimeReloadAction({
|
|
28
|
+
isHydrating: false,
|
|
29
|
+
isRunning: false,
|
|
30
|
+
isSending: true,
|
|
31
|
+
}),
|
|
32
|
+
).toBe('skip');
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('reloads immediately once the current page is idle', () => {
|
|
36
|
+
expect(
|
|
37
|
+
resolveNcpChatRealtimeReloadAction({
|
|
38
|
+
isHydrating: false,
|
|
39
|
+
isRunning: false,
|
|
40
|
+
isSending: false,
|
|
41
|
+
}),
|
|
42
|
+
).toBe('reload');
|
|
43
|
+
});
|
|
44
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type NcpChatRealtimeReloadAction = "reload" | "defer" | "skip";
|
|
2
|
+
|
|
3
|
+
export function resolveNcpChatRealtimeReloadAction(params: {
|
|
4
|
+
isHydrating: boolean;
|
|
5
|
+
isRunning: boolean;
|
|
6
|
+
isSending: boolean;
|
|
7
|
+
}): NcpChatRealtimeReloadAction {
|
|
8
|
+
if (params.isHydrating) {
|
|
9
|
+
return "defer";
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// While the current page owns the active run, live stream events already
|
|
13
|
+
// update the conversation state. Rehydrating from realtime session summaries
|
|
14
|
+
// here can reintroduce transient "running" state after the run has ended.
|
|
15
|
+
if (params.isRunning || params.isSending) {
|
|
16
|
+
return "skip";
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return "reload";
|
|
20
|
+
}
|
package/src/lib/i18n.ts
CHANGED
|
@@ -185,8 +185,6 @@ export const LABELS: Record<string, { zh: string; en: string }> = {
|
|
|
185
185
|
zh: 'Agent 默认模型标识,使用带 provider 前缀的格式。例如:openai/gpt-5.1、anthropic/claude-opus-4-1、deepseek/deepseek-chat、minimax/MiniMax-M2.5、openrouter/openai/gpt-5.3-codex。',
|
|
186
186
|
en: 'Default model identifier used by the agent. Use provider-prefixed format. Examples: openai/gpt-5.1 · anthropic/claude-opus-4-1 · deepseek/deepseek-chat · minimax/MiniMax-M2.5 · openrouter/openai/gpt-5.3-codex.'
|
|
187
187
|
},
|
|
188
|
-
chatRecentModels: { zh: '最近选择', en: 'Recent' },
|
|
189
|
-
chatAllModels: { zh: '全部模型', en: 'All models' },
|
|
190
188
|
maxToolIterations: { zh: '最大工具迭代次数', en: 'Max Tool Iterations' },
|
|
191
189
|
saveChanges: { zh: '保存变更', en: 'Save Changes' },
|
|
192
190
|
|