@nextclaw/ui 0.9.0 → 0.9.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 (44) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/assets/{ChannelsList-C7F_As4r.js → ChannelsList-DKD6Llid.js} +1 -1
  3. package/dist/assets/ChatPage-BK9X4Tin.js +38 -0
  4. package/dist/assets/{DocBrowser-Dsd8Dlq8.js → DocBrowser-CVwUDJMO.js} +1 -1
  5. package/dist/assets/{LogoBadge-2ChEc_oz.js → LogoBadge-CYQ_b7jk.js} +1 -1
  6. package/dist/assets/{MarketplacePage-BXck6-X3.js → MarketplacePage-B_2z3ii_.js} +1 -1
  7. package/dist/assets/{ModelConfig-CgHRSD0b.js → ModelConfig-CsX-_fyy.js} +1 -1
  8. package/dist/assets/{ProvidersList-PPfZucvS.js → ProvidersList-CZstsyv7.js} +1 -1
  9. package/dist/assets/{RuntimeConfig-ClLEKNTN.js → RuntimeConfig-CX2TGEG1.js} +1 -1
  10. package/dist/assets/{SearchConfig-CuXVCbrf.js → SearchConfig-C-WBTcWi.js} +1 -1
  11. package/dist/assets/{SecretsConfig-udJz6Ake.js → SecretsConfig-9kbR0ZCB.js} +1 -1
  12. package/dist/assets/{SessionsConfig-C1XnFfiC.js → SessionsConfig-Bohn3P1q.js} +1 -1
  13. package/dist/assets/{chat-message-BETwXLD4.js → chat-message-AWIcksDK.js} +1 -1
  14. package/dist/assets/{index-CsvP4CER.js → index-BEgClaDH.js} +3 -3
  15. package/dist/assets/index-C8GsgIUn.css +1 -0
  16. package/dist/assets/{index-COJdlL0e.js → index-CPDASUXh.js} +1 -1
  17. package/dist/assets/{label-BGL-ztxh.js → label-DD61y-4v.js} +1 -1
  18. package/dist/assets/{page-layout-aw88k7tG.js → page-layout-CfnoVycc.js} +1 -1
  19. package/dist/assets/{popover-DyEvzhmV.js → popover-DsugZ6rp.js} +1 -1
  20. package/dist/assets/{security-config-BuPAQn82.js → security-config-DIrf2Z0O.js} +1 -1
  21. package/dist/assets/skeleton-DJ-Wen2o.js +1 -0
  22. package/dist/assets/{switch-BK8jIzto.js → switch-NX5OmUXQ.js} +1 -1
  23. package/dist/assets/{tabs-custom-Da3cEOji.js → tabs-custom-9ihB5Jem.js} +1 -1
  24. package/dist/assets/{useConfirmDialog-z0CE92iS.js → useConfirmDialog-BuQnVTeR.js} +1 -1
  25. package/dist/assets/{vendor-CkJHmX1g.js → vendor-DKBNiC31.js} +1 -1
  26. package/dist/index.html +3 -3
  27. package/package.json +6 -6
  28. package/src/api/types.ts +63 -3
  29. package/src/components/chat/chat-composer-state.ts +53 -0
  30. package/src/components/chat/chat-page-data.ts +1 -15
  31. package/src/components/chat/chat-page-runtime.test.ts +26 -0
  32. package/src/components/chat/chat-page-runtime.ts +21 -4
  33. package/src/components/chat/chat-stream/types.ts +3 -0
  34. package/src/components/chat/containers/chat-input-bar.container.tsx +12 -41
  35. package/src/components/chat/legacy/LegacyChatPage.tsx +1 -15
  36. package/src/components/chat/managers/chat-input.manager.ts +43 -13
  37. package/src/components/chat/ncp/NcpChatPage.tsx +11 -18
  38. package/src/components/chat/ncp/ncp-chat-input.manager.ts +42 -12
  39. package/src/components/chat/ncp/ncp-chat-page-data.ts +1 -15
  40. package/src/components/chat/presenter/chat-presenter-context.tsx +2 -0
  41. package/src/components/chat/stores/chat-input.store.ts +4 -0
  42. package/dist/assets/ChatPage-Oo7-OUsx.js +0 -37
  43. package/dist/assets/index-D-bXl7qL.css +0 -1
  44. package/dist/assets/skeleton-drzO_tdU.js +0 -1
@@ -1,6 +1,14 @@
1
+ import type { ChatComposerNode } from '@nextclaw/agent-chat-ui';
1
2
  import type { SetStateAction } from 'react';
2
3
  import type { ThinkingLevel } from '@/api/types';
3
4
  import { updateNcpSession } from '@/api/ncp-session';
5
+ import {
6
+ createChatComposerNodesFromDraft,
7
+ createInitialChatComposerNodes,
8
+ deriveChatComposerDraft,
9
+ deriveSelectedSkillsFromComposer,
10
+ syncComposerSkills
11
+ } from '@/components/chat/chat-composer-state';
4
12
  import { useChatInputStore } from '@/components/chat/stores/chat-input.store';
5
13
  import { useChatSessionListStore } from '@/components/chat/stores/chat-session-list.store';
6
14
  import type { ChatInputSnapshot } from '@/components/chat/stores/chat-input.store';
@@ -36,6 +44,17 @@ export class NcpChatInputManager {
36
44
  return next;
37
45
  };
38
46
 
47
+ private isSameStringArray = (left: string[], right: string[]): boolean =>
48
+ left.length === right.length && left.every((value, index) => value === right[index]);
49
+
50
+ private syncComposerSnapshot = (nodes: ChatComposerNode[]) => {
51
+ useChatInputStore.getState().setSnapshot({
52
+ composerNodes: nodes,
53
+ draft: deriveChatComposerDraft(nodes),
54
+ selectedSkills: deriveSelectedSkillsFromComposer(nodes)
55
+ });
56
+ };
57
+
39
58
  syncSnapshot = (patch: Partial<ChatInputSnapshot>) => {
40
59
  if (!this.hasSnapshotChanges(patch)) {
41
60
  return;
@@ -46,8 +65,8 @@ export class NcpChatInputManager {
46
65
  Object.prototype.hasOwnProperty.call(patch, 'selectedModel') ||
47
66
  Object.prototype.hasOwnProperty.call(patch, 'selectedThinkingLevel')
48
67
  ) {
49
- const snapshot = useChatInputStore.getState().snapshot;
50
- this.reconcileThinkingForModel(snapshot.selectedModel);
68
+ const { selectedModel } = useChatInputStore.getState().snapshot;
69
+ this.reconcileThinkingForModel(selectedModel);
51
70
  }
52
71
  };
53
72
 
@@ -57,7 +76,16 @@ export class NcpChatInputManager {
57
76
  if (value === prev) {
58
77
  return;
59
78
  }
60
- useChatInputStore.getState().setSnapshot({ draft: value });
79
+ this.syncComposerSnapshot(createChatComposerNodesFromDraft(value));
80
+ };
81
+
82
+ setComposerNodes = (next: SetStateAction<ChatComposerNode[]>) => {
83
+ const prev = useChatInputStore.getState().snapshot.composerNodes;
84
+ const value = this.resolveUpdateValue(prev, next);
85
+ if (Object.is(value, prev)) {
86
+ return;
87
+ }
88
+ this.syncComposerSnapshot(value);
61
89
  };
62
90
 
63
91
  setPendingSessionType = (next: SetStateAction<string>) => {
@@ -76,13 +104,12 @@ export class NcpChatInputManager {
76
104
  if (!message) {
77
105
  return;
78
106
  }
79
- const requestedSkills = inputSnapshot.selectedSkills;
107
+ const { selectedSkills: requestedSkills, composerNodes } = inputSnapshot;
80
108
  const sessionKey = sessionSnapshot.selectedSessionKey ?? this.getDraftSessionId();
81
109
  if (!sessionSnapshot.selectedSessionKey) {
82
110
  this.uiManager.goToSession(sessionKey, { replace: true });
83
111
  }
84
- this.setDraft('');
85
- this.setSelectedSkills([]);
112
+ this.setComposerNodes(createInitialChatComposerNodes());
86
113
  await this.streamActionsManager.sendMessage({
87
114
  message,
88
115
  sessionKey,
@@ -92,7 +119,8 @@ export class NcpChatInputManager {
92
119
  thinkingLevel: inputSnapshot.selectedThinkingLevel ?? undefined,
93
120
  stopSupported: true,
94
121
  requestedSkills,
95
- restoreDraftOnError: true
122
+ restoreDraftOnError: true,
123
+ composerNodes
96
124
  });
97
125
  };
98
126
 
@@ -129,12 +157,13 @@ export class NcpChatInputManager {
129
157
  };
130
158
 
131
159
  setSelectedSkills = (next: SetStateAction<string[]>) => {
132
- const prev = useChatInputStore.getState().snapshot.selectedSkills;
160
+ const snapshot = useChatInputStore.getState().snapshot;
161
+ const { selectedSkills: prev } = snapshot;
133
162
  const value = this.resolveUpdateValue(prev, next);
134
- if (Object.is(value, prev)) {
163
+ if (this.isSameStringArray(value, prev)) {
135
164
  return;
136
165
  }
137
- useChatInputStore.getState().setSnapshot({ selectedSkills: value });
166
+ this.syncComposerSnapshot(syncComposerSkills(snapshot.composerNodes, value, snapshot.skillRecords));
138
167
  };
139
168
 
140
169
  selectModel = (value: string) => {
@@ -171,8 +200,9 @@ export class NcpChatInputManager {
171
200
  private reconcileThinkingForModel(model: string): void {
172
201
  const snapshot = useChatInputStore.getState().snapshot;
173
202
  const modelOption = snapshot.modelOptions.find((option) => option.value === model);
174
- const nextThinking = this.resolveThinkingForModel(modelOption, snapshot.selectedThinkingLevel);
175
- if (nextThinking !== snapshot.selectedThinkingLevel) {
203
+ const { selectedThinkingLevel } = snapshot;
204
+ const nextThinking = this.resolveThinkingForModel(modelOption, selectedThinkingLevel);
205
+ if (nextThinking !== selectedThinkingLevel) {
176
206
  useChatInputStore.getState().setSnapshot({ selectedThinkingLevel: nextThinking });
177
207
  }
178
208
  }
@@ -8,7 +8,6 @@ import {
8
8
  } from '@/components/chat/ncp/ncp-session-adapter';
9
9
  import { useChatSessionTypeState } from '@/components/chat/useChatSessionTypeState';
10
10
  import {
11
- resolveSelectedModelValue,
12
11
  resolveRecentSessionPreferredModel,
13
12
  useSyncSelectedModel
14
13
  } from '@/components/chat/chat-page-runtime';
@@ -128,25 +127,13 @@ export function useNcpChatPageData(params: UseNcpChatPageDataParams) {
128
127
  useSyncSelectedModel({
129
128
  modelOptions,
130
129
  selectedSessionKey: params.selectedSessionKey,
130
+ selectedSessionExists: Boolean(selectedSession),
131
131
  selectedSessionPreferredModel: selectedSession?.preferredModel,
132
132
  fallbackPreferredModel: recentSessionPreferredModel,
133
133
  defaultModel: configQuery.data?.agents.defaults.model,
134
134
  setSelectedModel: params.setSelectedModel
135
135
  });
136
136
 
137
- const hydratedSessionModel = useMemo(
138
- () =>
139
- resolveSelectedModelValue({
140
- currentSelectedModel: '',
141
- modelOptions,
142
- selectedSessionPreferredModel: selectedSession?.preferredModel,
143
- fallbackPreferredModel: recentSessionPreferredModel,
144
- defaultModel: configQuery.data?.agents.defaults.model,
145
- preferSessionPreferredModel: true
146
- }),
147
- [configQuery.data?.agents.defaults.model, modelOptions, recentSessionPreferredModel, selectedSession?.preferredModel]
148
- );
149
-
150
137
  return {
151
138
  configQuery,
152
139
  configMetaQuery,
@@ -159,7 +146,6 @@ export function useNcpChatPageData(params: UseNcpChatPageDataParams) {
159
146
  sessions,
160
147
  skillRecords,
161
148
  selectedSession,
162
- hydratedSessionModel,
163
149
  selectedSessionThinkingLevel,
164
150
  ...sessionTypeState
165
151
  };
@@ -1,3 +1,4 @@
1
+ import type { ChatComposerNode } from '@nextclaw/agent-chat-ui';
1
2
  import { createContext, useContext } from 'react';
2
3
  import type { ReactNode } from 'react';
3
4
  import type { SetStateAction } from 'react';
@@ -11,6 +12,7 @@ import type { ThinkingLevel } from '@/api/types';
11
12
  export type ChatInputManagerLike = {
12
13
  syncSnapshot: (patch: Record<string, unknown>) => void;
13
14
  setDraft: (next: SetStateAction<string>) => void;
15
+ setComposerNodes: (next: SetStateAction<ChatComposerNode[]>) => void;
14
16
  setPendingSessionType: (next: SetStateAction<string>) => void;
15
17
  send: () => Promise<void>;
16
18
  stop: () => Promise<void>;
@@ -1,10 +1,13 @@
1
1
  import { create } from 'zustand';
2
+ import type { ChatComposerNode } from '@nextclaw/agent-chat-ui';
2
3
  import type { MarketplaceInstalledRecord } from '@/api/types';
3
4
  import type { ThinkingLevel } from '@/api/types';
4
5
  import type { ChatModelOption } from '@/components/chat/chat-input.types';
6
+ import { createInitialChatComposerNodes } from '@/components/chat/chat-composer-state';
5
7
 
6
8
  export type ChatInputSnapshot = {
7
9
  isProviderStateResolved: boolean;
10
+ composerNodes: ChatComposerNode[];
8
11
  draft: string;
9
12
  pendingSessionType: string;
10
13
  defaultSessionType: string;
@@ -33,6 +36,7 @@ type ChatInputStore = {
33
36
 
34
37
  const initialSnapshot: ChatInputSnapshot = {
35
38
  isProviderStateResolved: false,
39
+ composerNodes: createInitialChatComposerNodes(),
36
40
  draft: '',
37
41
  pendingSessionType: 'native',
38
42
  defaultSessionType: 'native',