@nextclaw/ui 0.6.10 → 0.6.11

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 (80) hide show
  1. package/.eslintrc.cjs +10 -0
  2. package/CHANGELOG.md +9 -0
  3. package/dist/assets/{ChannelsList-TyMb5Mgz.js → ChannelsList-C49JQ-Zt.js} +1 -1
  4. package/dist/assets/ChatPage-DIx05c6s.js +36 -0
  5. package/dist/assets/{DocBrowser-CNtrA0ps.js → DocBrowser-CpOosDEI.js} +1 -1
  6. package/dist/assets/{LogoBadge-BLqiOM5D.js → LogoBadge-CL_8ZPXU.js} +1 -1
  7. package/dist/assets/MarketplacePage-BOzko5s9.js +49 -0
  8. package/dist/assets/{ModelConfig-CCsQ8KFq.js → ModelConfig-BZ4ZfaQB.js} +1 -1
  9. package/dist/assets/ProvidersList-fPpJ5gl6.js +1 -0
  10. package/dist/assets/{RuntimeConfig-BO6s-ls-.js → RuntimeConfig-Dt9pLB9P.js} +1 -1
  11. package/dist/assets/{SecretsConfig-mayFdxpM.js → SecretsConfig-C1PU0Yy8.js} +2 -2
  12. package/dist/assets/{SessionsConfig-DAIczdBj.js → SessionsConfig-EskBOofQ.js} +2 -2
  13. package/dist/assets/{card-BP5YnL-G.js → card-C7Gtw2Vs.js} +1 -1
  14. package/dist/assets/index-Cn6_2To7.js +8 -0
  15. package/dist/assets/{index-BUiahmWm.css → index-nEYGCJTC.css} +1 -1
  16. package/dist/assets/{input-B1D2QX0O.js → input-oBvxsnV9.js} +1 -1
  17. package/dist/assets/{label-DW0j-fXA.js → label-C7F8lMpQ.js} +1 -1
  18. package/dist/assets/{page-layout-Ch-H9gD-.js → page-layout-DO8BlScF.js} +1 -1
  19. package/dist/assets/session-run-status-Kg0FwAPn.js +3 -0
  20. package/dist/assets/{switch-_cZHlGKB.js → switch-C6a5GyZB.js} +1 -1
  21. package/dist/assets/{tabs-custom-ARxqYYjG.js → tabs-custom-BatFap5k.js} +1 -1
  22. package/dist/assets/{useConfirmDialog-BaU7nIat.js → useConfirmDialog-zJzVKMdu.js} +2 -2
  23. package/dist/assets/{vendor-C--HHaLf.js → vendor-TlME1INH.js} +84 -84
  24. package/dist/index.html +3 -3
  25. package/package.json +4 -2
  26. package/src/App.tsx +1 -2
  27. package/src/api/config.ts +199 -200
  28. package/src/api/types.ts +36 -24
  29. package/src/components/chat/ChatConversationPanel.tsx +102 -121
  30. package/src/components/chat/ChatPage.tsx +165 -437
  31. package/src/components/chat/ChatSidebar.tsx +30 -36
  32. package/src/components/chat/ChatThread.tsx +73 -131
  33. package/src/components/chat/chat-input/ChatInputBarView.tsx +82 -0
  34. package/src/components/chat/chat-input/ChatInputBottomToolbar.tsx +71 -0
  35. package/src/components/chat/chat-input/components/ChatInputModelStateHint.tsx +39 -0
  36. package/src/components/chat/chat-input/components/ChatInputSelectedSkillsSection.tsx +31 -0
  37. package/src/components/chat/chat-input/components/ChatInputSlashPanelSection.tsx +112 -0
  38. package/src/components/chat/chat-input/components/bottom-toolbar/ChatInputAttachButton.tsx +24 -0
  39. package/src/components/chat/chat-input/components/bottom-toolbar/ChatInputModelSelector.tsx +58 -0
  40. package/src/components/chat/chat-input/components/bottom-toolbar/ChatInputSendControls.tsx +56 -0
  41. package/src/components/chat/chat-input/components/bottom-toolbar/ChatInputSessionTypeSelector.tsx +40 -0
  42. package/src/components/chat/chat-input/useChatInputBarController.ts +313 -0
  43. package/src/components/chat/chat-input.types.ts +15 -0
  44. package/src/components/chat/chat-page-data.ts +121 -0
  45. package/src/components/chat/chat-page-runtime.ts +221 -0
  46. package/src/components/chat/chat-session-route.ts +59 -0
  47. package/src/components/chat/chat-stream/nextbot-parsers.ts +52 -0
  48. package/src/components/chat/chat-stream/nextbot-runtime-agent.ts +413 -0
  49. package/src/components/chat/chat-stream/stream-event-adapter.ts +98 -0
  50. package/src/components/chat/chat-stream/transport.ts +159 -0
  51. package/src/components/chat/chat-stream/types.ts +76 -0
  52. package/src/components/chat/managers/chat-input.manager.ts +142 -0
  53. package/src/components/chat/managers/chat-run-status.manager.ts +32 -0
  54. package/src/components/chat/managers/chat-session-list.manager.ts +77 -0
  55. package/src/components/chat/managers/chat-stream-actions.manager.ts +34 -0
  56. package/src/components/chat/managers/chat-thread.manager.ts +86 -0
  57. package/src/components/chat/managers/chat-ui.manager.ts +65 -0
  58. package/src/components/chat/presenter/chat-presenter-context.tsx +25 -0
  59. package/src/components/chat/presenter/chat.presenter.ts +32 -0
  60. package/src/components/chat/stores/chat-input.store.ts +62 -0
  61. package/src/components/chat/stores/chat-run-status.store.ts +30 -0
  62. package/src/components/chat/stores/chat-session-list.store.ts +34 -0
  63. package/src/components/chat/stores/chat-thread.store.ts +52 -0
  64. package/src/components/chat/useChatRuntimeController.ts +134 -0
  65. package/src/components/chat/useChatSessionTypeState.ts +148 -0
  66. package/src/components/common/MaskedInput.tsx +1 -1
  67. package/src/hooks/useConfig.ts +31 -1
  68. package/src/hooks/useObservable.ts +20 -0
  69. package/src/lib/chat-message.ts +2 -202
  70. package/src/lib/chat-runtime-utils.ts +250 -0
  71. package/src/lib/i18n.ts +9 -0
  72. package/tsconfig.json +2 -1
  73. package/vite.config.ts +2 -1
  74. package/dist/assets/ChatPage-CQerYqvy.js +0 -34
  75. package/dist/assets/MarketplacePage-CotZxxNe.js +0 -49
  76. package/dist/assets/ProvidersList-BYYX5K_g.js +0 -1
  77. package/dist/assets/index-D6_5HaDl.js +0 -7
  78. package/dist/assets/session-run-status-BUYsQeWs.js +0 -5
  79. package/src/components/chat/ChatInputBar.tsx +0 -590
  80. package/src/components/chat/useChatStreamController.ts +0 -591
@@ -0,0 +1,250 @@
1
+ import type { SessionMessageView } from '@/api/types';
2
+ import { extractMessageText } from '@/lib/chat-message';
3
+ import { ToolInvocationStatus, type UIMessage } from '@nextclaw/agent-chat';
4
+
5
+ export { isAbortLikeError, formatSendError, buildLocalAssistantMessage } from '@nextclaw/agent-chat';
6
+
7
+ export function normalizeRequestedSkills(value: string[] | undefined): string[] {
8
+ if (!Array.isArray(value)) {
9
+ return [];
10
+ }
11
+ const deduped = new Set<string>();
12
+ for (const item of value) {
13
+ const trimmed = item.trim();
14
+ if (trimmed) {
15
+ deduped.add(trimmed);
16
+ }
17
+ }
18
+ return [...deduped];
19
+ }
20
+
21
+ export function buildUiMessagesFromHistoryMessages(messages: SessionMessageView[]): UIMessage[] {
22
+ const normalizedToolRoles = new Set(['tool', 'tool_result', 'toolresult', 'function']);
23
+ const output: UIMessage[] = [];
24
+ let cursor = 0;
25
+ let assistantIndex = 0;
26
+ let activeAssistant: UIMessage | null = null;
27
+
28
+ const buildId = (role: UIMessage['role'], timestamp: string) => {
29
+ cursor += 1;
30
+ return `history-${role}-${timestamp || 'unknown'}-${cursor}`;
31
+ };
32
+
33
+ const parseArgsPayload = (raw: unknown): { args: string; parsedArgs?: unknown } => {
34
+ const args = typeof raw === 'string' ? raw : JSON.stringify(raw ?? {});
35
+ try {
36
+ return { args, parsedArgs: JSON.parse(args) };
37
+ } catch {
38
+ return { args };
39
+ }
40
+ };
41
+
42
+ const findToolPartIndex = (parts: UIMessage['parts'], toolCallId: string): number => {
43
+ for (let index = parts.length - 1; index >= 0; index -= 1) {
44
+ const part = parts[index];
45
+ if (part.type === 'tool-invocation' && part.toolInvocation.toolCallId === toolCallId) {
46
+ return index;
47
+ }
48
+ }
49
+ return -1;
50
+ };
51
+
52
+ const ensureAssistant = (timestamp: string): UIMessage => {
53
+ if (activeAssistant) {
54
+ activeAssistant = {
55
+ ...activeAssistant,
56
+ meta: {
57
+ ...activeAssistant.meta,
58
+ timestamp
59
+ }
60
+ };
61
+ return activeAssistant;
62
+ }
63
+ assistantIndex += 1;
64
+ activeAssistant = {
65
+ id: `history-assistant-${assistantIndex}-${timestamp || 'unknown'}`,
66
+ role: 'assistant',
67
+ parts: [],
68
+ meta: {
69
+ source: 'history',
70
+ status: 'final',
71
+ timestamp
72
+ }
73
+ };
74
+ return activeAssistant;
75
+ };
76
+
77
+ const flushAssistant = () => {
78
+ if (!activeAssistant) {
79
+ return;
80
+ }
81
+ if (activeAssistant.parts.length > 0) {
82
+ output.push(activeAssistant);
83
+ }
84
+ activeAssistant = null;
85
+ };
86
+
87
+ const appendAssistantText = (timestamp: string, text: string) => {
88
+ if (!text) {
89
+ return;
90
+ }
91
+ const assistant = ensureAssistant(timestamp);
92
+ assistant.parts = [...assistant.parts, { type: 'text', text }];
93
+ };
94
+
95
+ const appendAssistantReasoning = (timestamp: string, reasoning: string) => {
96
+ if (!reasoning) {
97
+ return;
98
+ }
99
+ const assistant = ensureAssistant(timestamp);
100
+ assistant.parts = [...assistant.parts, { type: 'reasoning', reasoning, details: [] }];
101
+ };
102
+
103
+ const appendAssistantToolCall = (params: {
104
+ timestamp: string;
105
+ toolCallId: string;
106
+ toolName: string;
107
+ args: string;
108
+ parsedArgs?: unknown;
109
+ }) => {
110
+ const assistant = ensureAssistant(params.timestamp);
111
+ const partIndex = findToolPartIndex(assistant.parts, params.toolCallId);
112
+ const part = {
113
+ type: 'tool-invocation' as const,
114
+ toolInvocation: {
115
+ status: ToolInvocationStatus.CALL,
116
+ toolCallId: params.toolCallId,
117
+ toolName: params.toolName,
118
+ args: params.args,
119
+ parsedArgs: params.parsedArgs
120
+ }
121
+ };
122
+ if (partIndex >= 0) {
123
+ assistant.parts = [...assistant.parts.slice(0, partIndex), part, ...assistant.parts.slice(partIndex + 1)];
124
+ return;
125
+ }
126
+ assistant.parts = [...assistant.parts, part];
127
+ };
128
+
129
+ const appendAssistantToolResult = (params: {
130
+ timestamp: string;
131
+ toolCallId: string;
132
+ toolName: string;
133
+ result: unknown;
134
+ }) => {
135
+ if (!params.toolCallId) {
136
+ return;
137
+ }
138
+ const assistant = ensureAssistant(params.timestamp);
139
+ const partIndex = findToolPartIndex(assistant.parts, params.toolCallId);
140
+ if (partIndex < 0) {
141
+ assistant.parts = [
142
+ ...assistant.parts,
143
+ {
144
+ type: 'tool-invocation',
145
+ toolInvocation: {
146
+ status: ToolInvocationStatus.RESULT,
147
+ toolCallId: params.toolCallId,
148
+ toolName: params.toolName,
149
+ args: '{}',
150
+ parsedArgs: undefined,
151
+ result: params.result
152
+ }
153
+ }
154
+ ];
155
+ return;
156
+ }
157
+ const part = assistant.parts[partIndex];
158
+ if (part.type !== 'tool-invocation') {
159
+ return;
160
+ }
161
+ assistant.parts = [
162
+ ...assistant.parts.slice(0, partIndex),
163
+ {
164
+ ...part,
165
+ toolInvocation: {
166
+ ...part.toolInvocation,
167
+ status: ToolInvocationStatus.RESULT,
168
+ result: params.result
169
+ }
170
+ },
171
+ ...assistant.parts.slice(partIndex + 1)
172
+ ];
173
+ };
174
+
175
+ for (const message of messages) {
176
+ const roleValue = message.role?.toLowerCase().trim();
177
+ if (!roleValue) {
178
+ continue;
179
+ }
180
+ const timestamp = message.timestamp;
181
+
182
+ if (roleValue === 'user' || roleValue === 'system' || roleValue === 'data') {
183
+ flushAssistant();
184
+ const text = extractMessageText(message.content).trim();
185
+ if (!text) {
186
+ continue;
187
+ }
188
+ output.push({
189
+ id: buildId(roleValue as UIMessage['role'], timestamp),
190
+ role: roleValue as UIMessage['role'],
191
+ parts: [{ type: 'text', text }],
192
+ meta: {
193
+ source: 'history',
194
+ status: 'final',
195
+ timestamp
196
+ }
197
+ });
198
+ continue;
199
+ }
200
+
201
+ if (roleValue === 'assistant') {
202
+ const text = extractMessageText(message.content).trim();
203
+ if (text) {
204
+ appendAssistantText(timestamp, text);
205
+ }
206
+ if (typeof message.reasoning_content === 'string' && message.reasoning_content.trim()) {
207
+ appendAssistantReasoning(timestamp, message.reasoning_content.trim());
208
+ }
209
+ if (Array.isArray(message.tool_calls)) {
210
+ for (const call of message.tool_calls) {
211
+ if (!call || typeof call !== 'object') {
212
+ continue;
213
+ }
214
+ const callRecord = call as Record<string, unknown>;
215
+ const fnValue = callRecord.function;
216
+ const fn = typeof fnValue === 'object' && fnValue ? (fnValue as { name?: unknown; arguments?: unknown }) : null;
217
+ const toolCallId = typeof callRecord.id === 'string' ? callRecord.id.trim() : '';
218
+ if (!toolCallId) {
219
+ continue;
220
+ }
221
+ const toolName =
222
+ typeof fn?.name === 'string' ? fn.name : typeof callRecord.name === 'string' ? callRecord.name : 'tool';
223
+ const payload = parseArgsPayload(fn?.arguments ?? callRecord.arguments ?? '');
224
+ appendAssistantToolCall({
225
+ timestamp,
226
+ toolCallId,
227
+ toolName,
228
+ args: payload.args,
229
+ parsedArgs: payload.parsedArgs
230
+ });
231
+ }
232
+ }
233
+ continue;
234
+ }
235
+
236
+ if (normalizedToolRoles.has(roleValue)) {
237
+ const toolCallId = typeof message.tool_call_id === 'string' ? message.tool_call_id.trim() : '';
238
+ const toolName = typeof message.name === 'string' && message.name.trim() ? message.name.trim() : 'tool';
239
+ appendAssistantToolResult({
240
+ timestamp,
241
+ toolCallId,
242
+ toolName,
243
+ result: message.content
244
+ });
245
+ }
246
+ }
247
+
248
+ flushAssistant();
249
+ return output;
250
+ }
package/src/lib/i18n.ts CHANGED
@@ -506,6 +506,14 @@ export const LABELS: Record<string, { zh: string; en: string }> = {
506
506
  chatSelectAgent: { zh: '选择 Agent', en: 'Select Agent' },
507
507
  chatModelLabel: { zh: '对话模型', en: 'Chat Model' },
508
508
  chatSelectModel: { zh: '选择模型', en: 'Select model' },
509
+ chatSessionTypeLabel: { zh: '会话类型', en: 'Session Type' },
510
+ chatSessionTypeNative: { zh: '原生', en: 'Native' },
511
+ chatSessionTypeCodex: { zh: 'Codex', en: 'Codex' },
512
+ chatSessionTypeClaude: { zh: 'Claude Code', en: 'Claude Code' },
513
+ chatSessionTypeUnavailableSuffix: {
514
+ zh: '当前不可用,请启用对应插件或新建 Native 会话。',
515
+ en: 'is unavailable now. Re-enable the plugin or create a native session.'
516
+ },
509
517
  chatModelNoOptions: { zh: '暂无可用模型,请先配置提供商。', en: 'No available models. Configure a provider first.' },
510
518
  chatGoConfigureProvider: { zh: '去配置提供商', en: 'Go to Providers' },
511
519
  chatProviderSetupTitle: { zh: '开始前先配置提供商', en: 'Configure a Provider First' },
@@ -539,6 +547,7 @@ export const LABELS: Record<string, { zh: string; en: string }> = {
539
547
  chatQueueSend: { zh: '排队发送', en: 'Queue' },
540
548
  chatQueuedHintPrefix: { zh: '当前有', en: 'Queued' },
541
549
  chatQueuedHintSuffix: { zh: '条消息待发送。', en: 'pending messages.' },
550
+ chatQueueMoveFirst: { zh: '置顶到下一条', en: 'Move to Next' },
542
551
  chatDeleteSession: { zh: '删除会话', en: 'Delete Session' },
543
552
  chatDeleteSessionConfirm: { zh: '确认删除当前会话?', en: 'Delete the current session?' },
544
553
  chatSendFailed: { zh: '发送消息失败', en: 'Failed to send message' },
package/tsconfig.json CHANGED
@@ -11,7 +11,8 @@
11
11
  "types": ["vite/client"],
12
12
  "baseUrl": ".",
13
13
  "paths": {
14
- "@/*": ["./src/*"]
14
+ "@/*": ["./src/*"],
15
+ "@nextclaw/agent-chat": ["../nextclaw-agent-chat/src/index.ts"]
15
16
  }
16
17
  },
17
18
  "include": ["src"]
package/vite.config.ts CHANGED
@@ -9,7 +9,8 @@ export default defineConfig({
9
9
  plugins: [react(), splitVendorChunkPlugin()],
10
10
  resolve: {
11
11
  alias: {
12
- '@': path.resolve(__dirname, './src')
12
+ '@': path.resolve(__dirname, './src'),
13
+ '@nextclaw/agent-chat': path.resolve(__dirname, '../nextclaw-agent-chat/src/index.ts')
13
14
  }
14
15
  },
15
16
  server: {