@lvce-editor/chat-view 2.0.0 → 2.1.0

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.
@@ -1027,7 +1027,7 @@ const createMockRpc = ({
1027
1027
  };
1028
1028
 
1029
1029
  const rpcs = Object.create(null);
1030
- const set$3 = (id, rpc) => {
1030
+ const set$4 = (id, rpc) => {
1031
1031
  rpcs[id] = rpc;
1032
1032
  };
1033
1033
  const get$2 = id => {
@@ -1060,7 +1060,7 @@ const create$2 = rpcId => {
1060
1060
  const mockRpc = createMockRpc({
1061
1061
  commandMap
1062
1062
  });
1063
- set$3(rpcId, mockRpc);
1063
+ set$4(rpcId, mockRpc);
1064
1064
  // @ts-ignore
1065
1065
  mockRpc[Symbol.dispose] = () => {
1066
1066
  remove(rpcId);
@@ -1069,11 +1069,15 @@ const create$2 = rpcId => {
1069
1069
  return mockRpc;
1070
1070
  },
1071
1071
  set(rpc) {
1072
- set$3(rpcId, rpc);
1072
+ set$4(rpcId, rpc);
1073
1073
  }
1074
1074
  };
1075
1075
  };
1076
1076
 
1077
+ const {
1078
+ set: set$3
1079
+ } = create$2(6002);
1080
+
1077
1081
  const ClientX = 'event.clientX';
1078
1082
  const ClientY = 'event.clientY';
1079
1083
  const Key = 'event.key';
@@ -1310,6 +1314,9 @@ const chats = () => {
1310
1314
  const newChat = () => {
1311
1315
  return i18nString('New Chat');
1312
1316
  };
1317
+ const debug = () => {
1318
+ return i18nString('Debug');
1319
+ };
1313
1320
  const backToChats = () => {
1314
1321
  return i18nString('Back to chats');
1315
1322
  };
@@ -2006,7 +2013,7 @@ const now$1 = () => {
2006
2013
  return new Date().toISOString();
2007
2014
  };
2008
2015
  const isSameMessage$1 = (a, b) => {
2009
- return a.id === b.id && a.inProgress === b.inProgress && a.role === b.role && a.text === b.text && a.time === b.time;
2016
+ return a.id === b.id && a.inProgress === b.inProgress && a.role === b.role && a.text === b.text && a.time === b.time && JSON.stringify(a.toolCalls || []) === JSON.stringify(b.toolCalls || []);
2010
2017
  };
2011
2018
  const canAppendMessages$1 = (previousMessages, nextMessages) => {
2012
2019
  if (nextMessages.length < previousMessages.length) {
@@ -2078,6 +2085,7 @@ const getMutationEvents$1 = (previous, next) => {
2078
2085
  text: nextMessage.text,
2079
2086
  time: nextMessage.time,
2080
2087
  timestamp,
2088
+ toolCalls: nextMessage.toolCalls,
2081
2089
  type: 'chat-message-updated'
2082
2090
  });
2083
2091
  }
@@ -2132,7 +2140,8 @@ const replaySession$1 = (id, summary, events) => {
2132
2140
  ...message,
2133
2141
  inProgress: event.inProgress,
2134
2142
  text: event.text,
2135
- time: event.time
2143
+ time: event.time,
2144
+ toolCalls: event.toolCalls
2136
2145
  };
2137
2146
  });
2138
2147
  continue;
@@ -2311,7 +2320,7 @@ const now = () => {
2311
2320
  return new Date().toISOString();
2312
2321
  };
2313
2322
  const isSameMessage = (a, b) => {
2314
- return a.id === b.id && a.inProgress === b.inProgress && a.role === b.role && a.text === b.text && a.time === b.time;
2323
+ return a.id === b.id && a.inProgress === b.inProgress && a.role === b.role && a.text === b.text && a.time === b.time && JSON.stringify(a.toolCalls || []) === JSON.stringify(b.toolCalls || []);
2315
2324
  };
2316
2325
  const canAppendMessages = (previousMessages, nextMessages) => {
2317
2326
  if (nextMessages.length < previousMessages.length) {
@@ -2383,6 +2392,7 @@ const getMutationEvents = (previous, next) => {
2383
2392
  text: nextMessage.text,
2384
2393
  time: nextMessage.time,
2385
2394
  timestamp,
2395
+ toolCalls: nextMessage.toolCalls,
2386
2396
  type: 'chat-message-updated'
2387
2397
  });
2388
2398
  }
@@ -2431,7 +2441,8 @@ const replaySession = (id, title, events) => {
2431
2441
  ...message,
2432
2442
  inProgress: event.inProgress,
2433
2443
  text: event.text,
2434
- time: event.time
2444
+ time: event.time,
2445
+ toolCalls: event.toolCalls
2435
2446
  };
2436
2447
  });
2437
2448
  continue;
@@ -3084,7 +3095,59 @@ const parseSseEvent = eventChunk => {
3084
3095
  }
3085
3096
  return dataLines;
3086
3097
  };
3087
- const parseOpenApiStream = async (response, onTextChunk) => {
3098
+ const updateToolCallAccumulator = (accumulator, chunk) => {
3099
+ let changed = false;
3100
+ const nextAccumulator = {
3101
+ ...accumulator
3102
+ };
3103
+ for (const item of chunk) {
3104
+ if (!item || typeof item !== 'object') {
3105
+ continue;
3106
+ }
3107
+ const index = Reflect.get(item, 'index');
3108
+ if (typeof index !== 'number') {
3109
+ continue;
3110
+ }
3111
+ const current = nextAccumulator[index] || {
3112
+ arguments: '',
3113
+ name: ''
3114
+ };
3115
+ const id = Reflect.get(item, 'id');
3116
+ const toolFunction = Reflect.get(item, 'function');
3117
+ let {
3118
+ name
3119
+ } = current;
3120
+ let args = current.arguments;
3121
+ if (toolFunction && typeof toolFunction === 'object') {
3122
+ const deltaName = Reflect.get(toolFunction, 'name');
3123
+ const deltaArguments = Reflect.get(toolFunction, 'arguments');
3124
+ if (typeof deltaName === 'string' && deltaName) {
3125
+ name = deltaName;
3126
+ }
3127
+ if (typeof deltaArguments === 'string') {
3128
+ args += deltaArguments;
3129
+ }
3130
+ }
3131
+ const next = {
3132
+ arguments: args,
3133
+ id: typeof id === 'string' ? id : current.id,
3134
+ name
3135
+ };
3136
+ if (JSON.stringify(next) !== JSON.stringify(current)) {
3137
+ nextAccumulator[index] = next;
3138
+ changed = true;
3139
+ }
3140
+ }
3141
+ if (!changed) {
3142
+ return undefined;
3143
+ }
3144
+ const toolCalls = Object.entries(nextAccumulator).toSorted((a, b) => Number(a[0]) - Number(b[0])).map(entry => entry[1]).filter(toolCall => !!toolCall.name);
3145
+ return {
3146
+ nextAccumulator,
3147
+ toolCalls
3148
+ };
3149
+ };
3150
+ const parseOpenApiStream = async (response, onTextChunk, onToolCallsChunk, onDataEvent, onEventStreamFinished) => {
3088
3151
  if (!response.body) {
3089
3152
  return {
3090
3153
  details: 'request-failed',
@@ -3096,6 +3159,7 @@ const parseOpenApiStream = async (response, onTextChunk) => {
3096
3159
  let remainder = '';
3097
3160
  let text = '';
3098
3161
  let done = false;
3162
+ let toolCallAccumulator = {};
3099
3163
  while (!done) {
3100
3164
  const {
3101
3165
  done: streamDone,
@@ -3121,6 +3185,9 @@ const parseOpenApiStream = async (response, onTextChunk) => {
3121
3185
  }
3122
3186
  for (const line of dataLines) {
3123
3187
  if (line === '[DONE]') {
3188
+ if (onEventStreamFinished) {
3189
+ await onEventStreamFinished();
3190
+ }
3124
3191
  done = true;
3125
3192
  break;
3126
3193
  }
@@ -3133,6 +3200,9 @@ const parseOpenApiStream = async (response, onTextChunk) => {
3133
3200
  if (!parsed || typeof parsed !== 'object') {
3134
3201
  continue;
3135
3202
  }
3203
+ if (onDataEvent) {
3204
+ await onDataEvent(parsed);
3205
+ }
3136
3206
  const choices = Reflect.get(parsed, 'choices');
3137
3207
  if (!Array.isArray(choices)) {
3138
3208
  continue;
@@ -3145,6 +3215,14 @@ const parseOpenApiStream = async (response, onTextChunk) => {
3145
3215
  if (!delta || typeof delta !== 'object') {
3146
3216
  continue;
3147
3217
  }
3218
+ const toolCalls = Reflect.get(delta, 'tool_calls');
3219
+ const updatedToolCallResult = Array.isArray(toolCalls) ? updateToolCallAccumulator(toolCallAccumulator, toolCalls) : undefined;
3220
+ if (updatedToolCallResult) {
3221
+ toolCallAccumulator = updatedToolCallResult.nextAccumulator;
3222
+ }
3223
+ if (updatedToolCallResult && onToolCallsChunk) {
3224
+ await onToolCallsChunk(updatedToolCallResult.toolCalls);
3225
+ }
3148
3226
  const content = Reflect.get(delta, 'content');
3149
3227
  const chunkText = getStreamChunkText(content);
3150
3228
  if (!chunkText) {
@@ -3161,6 +3239,9 @@ const parseOpenApiStream = async (response, onTextChunk) => {
3161
3239
  const dataLines = parseSseEvent(remainder);
3162
3240
  for (const line of dataLines) {
3163
3241
  if (line === '[DONE]') {
3242
+ if (onEventStreamFinished) {
3243
+ await onEventStreamFinished();
3244
+ }
3164
3245
  continue;
3165
3246
  }
3166
3247
  let parsed;
@@ -3172,6 +3253,9 @@ const parseOpenApiStream = async (response, onTextChunk) => {
3172
3253
  if (!parsed || typeof parsed !== 'object') {
3173
3254
  continue;
3174
3255
  }
3256
+ if (onDataEvent) {
3257
+ await onDataEvent(parsed);
3258
+ }
3175
3259
  const choices = Reflect.get(parsed, 'choices');
3176
3260
  if (!Array.isArray(choices)) {
3177
3261
  continue;
@@ -3184,6 +3268,14 @@ const parseOpenApiStream = async (response, onTextChunk) => {
3184
3268
  if (!delta || typeof delta !== 'object') {
3185
3269
  continue;
3186
3270
  }
3271
+ const toolCalls = Reflect.get(delta, 'tool_calls');
3272
+ const updatedToolCallResult = Array.isArray(toolCalls) ? updateToolCallAccumulator(toolCallAccumulator, toolCalls) : undefined;
3273
+ if (updatedToolCallResult) {
3274
+ toolCallAccumulator = updatedToolCallResult.nextAccumulator;
3275
+ }
3276
+ if (updatedToolCallResult && onToolCallsChunk) {
3277
+ await onToolCallsChunk(updatedToolCallResult.toolCalls);
3278
+ }
3187
3279
  const content = Reflect.get(delta, 'content');
3188
3280
  const chunkText = getStreamChunkText(content);
3189
3281
  if (!chunkText) {
@@ -3226,7 +3318,10 @@ const getOpenApiErrorDetails = async response => {
3226
3318
  const getOpenApiAssistantText = async (messages, modelId, openApiApiKey, openApiApiBaseUrl, assetDir, platform, options) => {
3227
3319
  const {
3228
3320
  includeObfuscation = false,
3321
+ onDataEvent,
3322
+ onEventStreamFinished,
3229
3323
  onTextChunk,
3324
+ onToolCallsChunk,
3230
3325
  stream
3231
3326
  } = options ?? {
3232
3327
  stream: false
@@ -3271,7 +3366,7 @@ const getOpenApiAssistantText = async (messages, modelId, openApiApiKey, openApi
3271
3366
  };
3272
3367
  }
3273
3368
  if (stream) {
3274
- return parseOpenApiStream(response, onTextChunk);
3369
+ return parseOpenApiStream(response, onTextChunk, onToolCallsChunk, onDataEvent, onEventStreamFinished);
3275
3370
  }
3276
3371
  let parsed;
3277
3372
  try {
@@ -3685,11 +3780,14 @@ const isOpenRouterModel = (selectedModelId, models) => {
3685
3780
 
3686
3781
  const getAiResponse = async ({
3687
3782
  assetDir,
3783
+ messageId,
3688
3784
  messages,
3689
3785
  mockApiCommandId,
3690
3786
  models,
3691
- nextMessageId,
3787
+ onDataEvent,
3788
+ onEventStreamFinished,
3692
3789
  onTextChunk,
3790
+ onToolCallsChunk,
3693
3791
  openApiApiBaseUrl,
3694
3792
  openApiApiKey,
3695
3793
  openRouterApiBaseUrl,
@@ -3718,7 +3816,10 @@ const getAiResponse = async ({
3718
3816
  } else if (openApiApiKey) {
3719
3817
  const result = await getOpenApiAssistantText(messages, getOpenApiModelId(selectedModelId), openApiApiKey, openApiApiBaseUrl, assetDir, platform, {
3720
3818
  includeObfuscation: passIncludeObfuscation,
3819
+ onDataEvent,
3820
+ onEventStreamFinished,
3721
3821
  onTextChunk,
3822
+ onToolCallsChunk,
3722
3823
  stream: streamingEnabled
3723
3824
  });
3724
3825
  if (result.type === 'success') {
@@ -3766,7 +3867,7 @@ const getAiResponse = async ({
3766
3867
  minute: '2-digit'
3767
3868
  });
3768
3869
  return {
3769
- id: `message-${nextMessageId}`,
3870
+ id: messageId || crypto.randomUUID(),
3770
3871
  role: 'assistant',
3771
3872
  text,
3772
3873
  time: assistantTime
@@ -3821,7 +3922,6 @@ const handleClickSaveOpenApiApiKey = async state => {
3821
3922
  messages: retryMessages,
3822
3923
  mockApiCommandId: updatedState.mockApiCommandId,
3823
3924
  models: updatedState.models,
3824
- nextMessageId: updatedState.nextMessageId,
3825
3925
  openApiApiBaseUrl: updatedState.openApiApiBaseUrl,
3826
3926
  openApiApiKey: updatedState.openApiApiKey,
3827
3927
  openRouterApiBaseUrl: updatedState.openRouterApiBaseUrl,
@@ -3901,7 +4001,6 @@ const handleClickSaveOpenRouterApiKey = async state => {
3901
4001
  messages: retryMessages,
3902
4002
  mockApiCommandId: updatedState.mockApiCommandId,
3903
4003
  models: updatedState.models,
3904
- nextMessageId: updatedState.nextMessageId,
3905
4004
  openApiApiBaseUrl: updatedState.openApiApiBaseUrl,
3906
4005
  openApiApiKey: updatedState.openApiApiKey,
3907
4006
  openRouterApiBaseUrl: updatedState.openRouterApiBaseUrl,
@@ -3958,6 +4057,25 @@ const updateMessageTextInSelectedSession = (sessions, selectedSessionId, message
3958
4057
  };
3959
4058
  });
3960
4059
  };
4060
+ const updateMessageToolCallsInSelectedSession = (sessions, selectedSessionId, messageId, toolCalls) => {
4061
+ return sessions.map(session => {
4062
+ if (session.id !== selectedSessionId) {
4063
+ return session;
4064
+ }
4065
+ return {
4066
+ ...session,
4067
+ messages: session.messages.map(message => {
4068
+ if (message.id !== messageId) {
4069
+ return message;
4070
+ }
4071
+ return {
4072
+ ...message,
4073
+ toolCalls
4074
+ };
4075
+ })
4076
+ };
4077
+ });
4078
+ };
3961
4079
  const handleTextChunkFunction = async (uid, assistantMessageId, chunk, handleTextChunkState) => {
3962
4080
  const selectedSession = handleTextChunkState.latestState.sessions.find(session => session.id === handleTextChunkState.latestState.selectedSessionId);
3963
4081
  if (!selectedSession) {
@@ -3994,6 +4112,34 @@ const handleTextChunkFunction = async (uid, assistantMessageId, chunk, handleTex
3994
4112
  previousState: nextState
3995
4113
  };
3996
4114
  };
4115
+ const handleToolCallsChunkFunction = async (uid, assistantMessageId, toolCalls, handleTextChunkState) => {
4116
+ const selectedSession = handleTextChunkState.latestState.sessions.find(session => session.id === handleTextChunkState.latestState.selectedSessionId);
4117
+ if (!selectedSession) {
4118
+ return {
4119
+ latestState: handleTextChunkState.latestState,
4120
+ previousState: handleTextChunkState.previousState
4121
+ };
4122
+ }
4123
+ const assistantMessage = selectedSession.messages.find(message => message.id === assistantMessageId);
4124
+ if (!assistantMessage) {
4125
+ return {
4126
+ latestState: handleTextChunkState.latestState,
4127
+ previousState: handleTextChunkState.previousState
4128
+ };
4129
+ }
4130
+ const updatedSessions = updateMessageToolCallsInSelectedSession(handleTextChunkState.latestState.sessions, handleTextChunkState.latestState.selectedSessionId, assistantMessageId, toolCalls);
4131
+ const nextState = {
4132
+ ...handleTextChunkState.latestState,
4133
+ sessions: updatedSessions
4134
+ };
4135
+ set(uid, handleTextChunkState.previousState, nextState);
4136
+ // @ts-ignore
4137
+ await invoke('Chat.rerender');
4138
+ return {
4139
+ latestState: nextState,
4140
+ previousState: nextState
4141
+ };
4142
+ };
3997
4143
 
3998
4144
  const appendMessageToSelectedSession = (sessions, selectedSessionId, message) => {
3999
4145
  return sessions.map(session => {
@@ -4034,13 +4180,14 @@ const handleSubmit = async state => {
4034
4180
  hour: '2-digit',
4035
4181
  minute: '2-digit'
4036
4182
  });
4183
+ const userMessageId = crypto.randomUUID();
4037
4184
  const userMessage = {
4038
- id: `message-${nextMessageId}`,
4185
+ id: userMessageId,
4039
4186
  role: 'user',
4040
4187
  text: userText,
4041
4188
  time: userTime
4042
4189
  };
4043
- const assistantMessageId = `message-${nextMessageId + 1}`;
4190
+ const assistantMessageId = crypto.randomUUID();
4044
4191
  const assistantTime = new Date().toLocaleTimeString([], {
4045
4192
  hour: '2-digit',
4046
4193
  minute: '2-digit'
@@ -4127,11 +4274,30 @@ const handleSubmit = async state => {
4127
4274
  } : undefined;
4128
4275
  const assistantMessage = await getAiResponse({
4129
4276
  assetDir,
4277
+ messageId: assistantMessageId,
4130
4278
  messages,
4131
4279
  mockApiCommandId,
4132
4280
  models,
4133
- nextMessageId: optimisticState.nextMessageId,
4281
+ onDataEvent: async value => {
4282
+ await appendChatViewEvent({
4283
+ sessionId: optimisticState.selectedSessionId,
4284
+ timestamp: new Date().toISOString(),
4285
+ type: 'data-event',
4286
+ value
4287
+ });
4288
+ },
4289
+ onEventStreamFinished: async () => {
4290
+ await appendChatViewEvent({
4291
+ sessionId: optimisticState.selectedSessionId,
4292
+ timestamp: new Date().toISOString(),
4293
+ type: 'event-stream-finished',
4294
+ value: '[DONE]'
4295
+ });
4296
+ },
4134
4297
  onTextChunk: handleTextChunkFunctionRef,
4298
+ onToolCallsChunk: async toolCalls => {
4299
+ handleTextChunkState = await handleToolCallsChunkFunction(state.uid, assistantMessageId, toolCalls, handleTextChunkState);
4300
+ },
4135
4301
  openApiApiBaseUrl,
4136
4302
  openApiApiKey,
4137
4303
  openRouterApiBaseUrl,
@@ -4177,6 +4343,7 @@ const Send = 'send';
4177
4343
  const Back = 'back';
4178
4344
  const Model = 'model';
4179
4345
  const CreateSession = 'create-session';
4346
+ const SessionDebug = 'session-debug';
4180
4347
  const Settings = 'settings';
4181
4348
  const CloseChat = 'close-chat';
4182
4349
  const SessionDelete = 'SessionDelete';
@@ -4321,6 +4488,11 @@ const handleClickNew = async state => {
4321
4488
  return createSession(state);
4322
4489
  };
4323
4490
 
4491
+ const handleClickSessionDebug = async state => {
4492
+ await invoke('Main.openUri', `chat-debug://${state.selectedSessionId}`);
4493
+ return state;
4494
+ };
4495
+
4324
4496
  const handleClickSettings = async () => {
4325
4497
  // TODO
4326
4498
  await invoke('Main.openUri', 'app://settings.json');
@@ -4377,7 +4549,7 @@ const handleInputFocus = async (state, name) => {
4377
4549
  focused: true
4378
4550
  };
4379
4551
  }
4380
- if (name === CreateSession || name === Settings || name === CloseChat || name === Back) {
4552
+ if (name === CreateSession || name === SessionDebug || name === Settings || name === CloseChat || name === Back) {
4381
4553
  return {
4382
4554
  ...state,
4383
4555
  focus: 'header',
@@ -4866,6 +5038,7 @@ const HandleSubmit = 19;
4866
5038
  const HandleModelChange = 20;
4867
5039
  const HandleChatListScroll = 21;
4868
5040
  const HandleMessagesScroll = 22;
5041
+ const HandleClickSessionDebug = 23;
4869
5042
 
4870
5043
  const getModelLabel = model => {
4871
5044
  if (model.provider === 'openRouter') {
@@ -5013,6 +5186,11 @@ const getHeaderActionVirtualDom = item => {
5013
5186
 
5014
5187
  const getChatHeaderActionsDom = () => {
5015
5188
  const items = [{
5189
+ icon: 'MaskIcon MaskIconDebugPause',
5190
+ name: SessionDebug,
5191
+ onClick: HandleClickSessionDebug,
5192
+ title: debug()
5193
+ }, {
5016
5194
  icon: 'MaskIcon MaskIconAdd',
5017
5195
  name: CreateSession,
5018
5196
  onClick: HandleClickNew,
@@ -5117,6 +5295,126 @@ const getMissingOpenRouterApiKeyDom = (openRouterApiKeyInput, openRouterApiKeySt
5117
5295
  });
5118
5296
  };
5119
5297
 
5298
+ const orderedListItemRegex = /^\s*\d+\.\s+(.*)$/;
5299
+ const parseMessageContent = rawMessage => {
5300
+ if (rawMessage === '') {
5301
+ return [{
5302
+ text: '',
5303
+ type: 'text'
5304
+ }];
5305
+ }
5306
+ const lines = rawMessage.split(/\r?\n/);
5307
+ const nodes = [];
5308
+ let paragraphLines = [];
5309
+ let listItems = [];
5310
+ const flushParagraph = () => {
5311
+ if (paragraphLines.length === 0) {
5312
+ return;
5313
+ }
5314
+ nodes.push({
5315
+ text: paragraphLines.join('\n'),
5316
+ type: 'text'
5317
+ });
5318
+ paragraphLines = [];
5319
+ };
5320
+ const flushList = () => {
5321
+ if (listItems.length === 0) {
5322
+ return;
5323
+ }
5324
+ nodes.push({
5325
+ items: listItems,
5326
+ type: 'list'
5327
+ });
5328
+ listItems = [];
5329
+ };
5330
+ for (const line of lines) {
5331
+ if (!line.trim()) {
5332
+ flushList();
5333
+ flushParagraph();
5334
+ continue;
5335
+ }
5336
+ const match = line.match(orderedListItemRegex);
5337
+ if (match) {
5338
+ flushParagraph();
5339
+ listItems.push({
5340
+ text: match[1],
5341
+ type: 'list-item'
5342
+ });
5343
+ continue;
5344
+ }
5345
+ flushList();
5346
+ paragraphLines.push(line);
5347
+ }
5348
+ flushList();
5349
+ flushParagraph();
5350
+ return nodes.length === 0 ? [{
5351
+ text: '',
5352
+ type: 'text'
5353
+ }] : nodes;
5354
+ };
5355
+ const getMessageContentDom = nodes => {
5356
+ return nodes.flatMap(node => {
5357
+ if (node.type === 'text') {
5358
+ return [{
5359
+ childCount: 1,
5360
+ className: Markdown,
5361
+ type: P
5362
+ }, text(node.text)];
5363
+ }
5364
+ return [{
5365
+ childCount: node.items.length,
5366
+ className: ChatOrderedList,
5367
+ type: Ol
5368
+ }, ...node.items.flatMap(item => {
5369
+ return [{
5370
+ childCount: 1,
5371
+ className: ChatOrderedListItem,
5372
+ type: Li
5373
+ }, text(item.text)];
5374
+ })];
5375
+ });
5376
+ };
5377
+
5378
+ const getToolCallArgumentPreview = rawArguments => {
5379
+ if (!rawArguments.trim()) {
5380
+ return '""';
5381
+ }
5382
+ let parsed;
5383
+ try {
5384
+ parsed = JSON.parse(rawArguments);
5385
+ } catch {
5386
+ return rawArguments;
5387
+ }
5388
+ if (!parsed || typeof parsed !== 'object') {
5389
+ return rawArguments;
5390
+ }
5391
+ const path = Reflect.get(parsed, 'path');
5392
+ if (typeof path === 'string') {
5393
+ return `"${path}"`;
5394
+ }
5395
+ const keys = Object.keys(parsed);
5396
+ if (keys.length === 1) {
5397
+ const value = Reflect.get(parsed, keys[0]);
5398
+ if (typeof value === 'string') {
5399
+ return `"${value}"`;
5400
+ }
5401
+ }
5402
+ return rawArguments;
5403
+ };
5404
+ const getToolCallsDom = message => {
5405
+ if (message.role !== 'assistant' || !message.toolCalls || message.toolCalls.length === 0) {
5406
+ return [];
5407
+ }
5408
+ return message.toolCalls.flatMap(toolCall => {
5409
+ const argumentPreview = getToolCallArgumentPreview(toolCall.arguments);
5410
+ const label = `${toolCall.name} ${argumentPreview}`;
5411
+ return [{
5412
+ childCount: 1,
5413
+ className: Markdown,
5414
+ type: P
5415
+ }, text(label)];
5416
+ });
5417
+ };
5120
5418
  const getOpenRouterRequestFailedDom = () => {
5121
5419
  return [{
5122
5420
  childCount: openRouterRequestFailureReasons.length,
@@ -5149,7 +5447,10 @@ const getChatMessageDom = (message, openRouterApiKeyInput, openApiApiKeyInput =
5149
5447
  const isOpenRouterApiKeyMissingMessage = message.role === 'assistant' && message.text === openRouterApiKeyRequiredMessage;
5150
5448
  const isOpenRouterRequestFailedMessage = message.role === 'assistant' && message.text === openRouterRequestFailedMessage;
5151
5449
  const isOpenRouterTooManyRequestsMessage = message.role === 'assistant' && message.text.startsWith(openRouterTooManyRequestsMessage);
5152
- const extraChildCount = isOpenApiApiKeyMissingMessage || isOpenRouterApiKeyMissingMessage || isOpenRouterRequestFailedMessage || isOpenRouterTooManyRequestsMessage ? 2 : 1;
5450
+ const messageIntermediate = parseMessageContent(message.text);
5451
+ const messageDom = getMessageContentDom(messageIntermediate);
5452
+ const toolCallsDom = getToolCallsDom(message);
5453
+ const extraChildCount = isOpenApiApiKeyMissingMessage || isOpenRouterApiKeyMissingMessage || isOpenRouterRequestFailedMessage || isOpenRouterTooManyRequestsMessage ? messageIntermediate.length + 1 + toolCallsDom.length : messageIntermediate.length + toolCallsDom.length;
5153
5454
  return [{
5154
5455
  childCount: 1,
5155
5456
  className: mergeClassNames(Message, roleClassName),
@@ -5158,11 +5459,7 @@ const getChatMessageDom = (message, openRouterApiKeyInput, openApiApiKeyInput =
5158
5459
  childCount: extraChildCount,
5159
5460
  className: ChatMessageContent,
5160
5461
  type: Div
5161
- }, {
5162
- childCount: 1,
5163
- className: Markdown,
5164
- type: P
5165
- }, text(message.text), ...(isOpenApiApiKeyMissingMessage ? getMissingOpenApiApiKeyDom(openApiApiKeyInput) : []), ...(isOpenRouterApiKeyMissingMessage ? getMissingOpenRouterApiKeyDom(openRouterApiKeyInput, openRouterApiKeyState) : []), ...(isOpenRouterRequestFailedMessage ? getOpenRouterRequestFailedDom() : []), ...(isOpenRouterTooManyRequestsMessage ? getOpenRouterTooManyRequestsDom() : [])];
5462
+ }, ...messageDom, ...toolCallsDom, ...(isOpenApiApiKeyMissingMessage ? getMissingOpenApiApiKeyDom(openApiApiKeyInput) : []), ...(isOpenRouterApiKeyMissingMessage ? getMissingOpenRouterApiKeyDom(openRouterApiKeyInput, openRouterApiKeyState) : []), ...(isOpenRouterRequestFailedMessage ? getOpenRouterRequestFailedDom() : []), ...(isOpenRouterTooManyRequestsMessage ? getOpenRouterTooManyRequestsDom() : [])];
5166
5463
  };
5167
5464
 
5168
5465
  const getEmptyMessagesDom = () => {
@@ -5406,6 +5703,9 @@ const renderEventListeners = () => {
5406
5703
  }, {
5407
5704
  name: HandleClickNew,
5408
5705
  params: ['handleClickNew']
5706
+ }, {
5707
+ name: HandleClickSessionDebug,
5708
+ params: ['handleClickSessionDebug']
5409
5709
  }, {
5410
5710
  name: HandleClickBack,
5411
5711
  params: ['handleClickBack']
@@ -5553,6 +5853,7 @@ const commandMap = {
5553
5853
  'Chat.handleClickDelete': wrapCommand(handleClickDelete),
5554
5854
  'Chat.handleClickList': wrapCommand(handleClickList),
5555
5855
  'Chat.handleClickNew': wrapCommand(handleClickNew),
5856
+ 'Chat.handleClickSessionDebug': wrapCommand(handleClickSessionDebug),
5556
5857
  'Chat.handleClickSettings': handleClickSettings,
5557
5858
  'Chat.handleInput': wrapCommand(handleInput),
5558
5859
  'Chat.handleInputFocus': wrapCommand(handleInputFocus),
@@ -5588,7 +5889,7 @@ const initializeChatNetworkWorker = async () => {
5588
5889
  commandMap: {},
5589
5890
  send
5590
5891
  });
5591
- return rpc;
5892
+ set$3(rpc);
5592
5893
  };
5593
5894
 
5594
5895
  const listen = async () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/chat-view",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "Chat View Worker",
5
5
  "repository": {
6
6
  "type": "git",