@lvce-editor/chat-view 7.9.0 → 7.11.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.
@@ -2283,7 +2283,7 @@ const getVisibleModels = (models, modelPickerSearchValue) => {
2283
2283
  };
2284
2284
 
2285
2285
  const reasoningEfforts = ['extra-high', 'high', 'medium', 'low'];
2286
- const defaultReasoningEffort = 'high';
2286
+ const defaultReasoningEffort = 'medium';
2287
2287
  const isReasoningEffort = value => {
2288
2288
  return reasoningEfforts.includes(value);
2289
2289
  };
@@ -4999,8 +4999,22 @@ const getBackendErrorMessage = errorResult => {
4999
4999
  }
5000
5000
  return backendCompletionFailedMessage;
5001
5001
  }
5002
+ case 'invalid-response':
5003
+ {
5004
+ const errorMessage = errorResult.errorMessage?.trim();
5005
+ if (errorMessage) {
5006
+ return `Backend completion request failed. ${errorMessage}`;
5007
+ }
5008
+ return 'Backend completion request failed. Unexpected backend response format.';
5009
+ }
5002
5010
  case 'request-failed':
5003
- return backendCompletionFailedMessage;
5011
+ {
5012
+ const errorMessage = errorResult.errorMessage?.trim();
5013
+ if (errorMessage) {
5014
+ return `Backend completion request failed. ${errorMessage}`;
5015
+ }
5016
+ return backendCompletionFailedMessage;
5017
+ }
5004
5018
  }
5005
5019
  };
5006
5020
 
@@ -7173,6 +7187,7 @@ const isOpenRouterModel = (selectedModelId, models) => {
7173
7187
  };
7174
7188
 
7175
7189
  let errorResponse;
7190
+ let successResponse;
7176
7191
  const setHttpErrorResponse = (statusCode, body) => {
7177
7192
  errorResponse = {
7178
7193
  body,
@@ -7180,18 +7195,29 @@ const setHttpErrorResponse = (statusCode, body) => {
7180
7195
  type: 'http-error'
7181
7196
  };
7182
7197
  };
7198
+ const setResponse = body => {
7199
+ successResponse = {
7200
+ body,
7201
+ type: 'success'
7202
+ };
7203
+ };
7183
7204
  const takeErrorResponse = () => {
7184
7205
  const response = errorResponse;
7185
7206
  errorResponse = undefined;
7186
7207
  return response;
7187
7208
  };
7209
+ const takeResponse = () => {
7210
+ const response = successResponse;
7211
+ successResponse = undefined;
7212
+ return response;
7213
+ };
7188
7214
 
7189
7215
  /* eslint-disable prefer-destructuring */
7190
7216
 
7191
7217
  const trailingSlashesRegex = /\/+$/;
7192
- const getBackendCompletionsEndpoint = backendUrl => {
7218
+ const getBackendResponsesEndpoint = backendUrl => {
7193
7219
  const trimmedBackendUrl = backendUrl.replace(trailingSlashesRegex, '');
7194
- return `${trimmedBackendUrl}/v1/chat/completions`;
7220
+ return `${trimmedBackendUrl}/v1/responses`;
7195
7221
  };
7196
7222
  const hasImageAttachments = messages => {
7197
7223
  return messages.some(message => message.attachments?.some(attachment => attachment.displayType === 'image'));
@@ -7230,7 +7256,193 @@ const getBackendStatusCodeFromBody = body => {
7230
7256
  }
7231
7257
  return undefined;
7232
7258
  };
7233
- const getBackendAssistantText = async (messages, selectedModelId, backendUrl, authAccessToken, systemPrompt) => {
7259
+ const getBackendResponseId = body => {
7260
+ if (!isObject$2(body)) {
7261
+ return undefined;
7262
+ }
7263
+ const id = Reflect.get(body, 'id');
7264
+ return typeof id === 'string' && id ? id : undefined;
7265
+ };
7266
+ const getBackendResponseStatus = body => {
7267
+ if (!isObject$2(body)) {
7268
+ return undefined;
7269
+ }
7270
+ const status = Reflect.get(body, 'status');
7271
+ return typeof status === 'string' && status ? status : undefined;
7272
+ };
7273
+ const getBackendIncompleteMessage = body => {
7274
+ if (!isObject$2(body)) {
7275
+ return undefined;
7276
+ }
7277
+ const incompleteDetails = Reflect.get(body, 'incomplete_details');
7278
+ if (!isObject$2(incompleteDetails)) {
7279
+ return undefined;
7280
+ }
7281
+ const reason = Reflect.get(incompleteDetails, 'reason');
7282
+ if (typeof reason === 'string' && reason) {
7283
+ return `Backend response was incomplete (${reason}).`;
7284
+ }
7285
+ return undefined;
7286
+ };
7287
+ const getBackendResponseFunctionCalls = body => {
7288
+ if (!isObject$2(body)) {
7289
+ return [];
7290
+ }
7291
+ const output = Reflect.get(body, 'output');
7292
+ if (!Array.isArray(output)) {
7293
+ return [];
7294
+ }
7295
+ const calls = [];
7296
+ for (const outputItem of output) {
7297
+ if (!isObject$2(outputItem)) {
7298
+ continue;
7299
+ }
7300
+ if (Reflect.get(outputItem, 'type') !== 'function_call') {
7301
+ continue;
7302
+ }
7303
+ const callId = Reflect.get(outputItem, 'call_id');
7304
+ const name = Reflect.get(outputItem, 'name');
7305
+ const rawArguments = Reflect.get(outputItem, 'arguments');
7306
+ if (typeof callId !== 'string' || !callId || typeof name !== 'string' || !name) {
7307
+ continue;
7308
+ }
7309
+ calls.push({
7310
+ arguments: typeof rawArguments === 'string' ? rawArguments : '',
7311
+ callId,
7312
+ name
7313
+ });
7314
+ }
7315
+ return calls;
7316
+ };
7317
+ const getErrorMessage = error => {
7318
+ if (error instanceof Error) {
7319
+ return error.message;
7320
+ }
7321
+ return typeof error === 'string' && error ? error : undefined;
7322
+ };
7323
+ const getBackendInvalidResponseDetails = body => {
7324
+ const errorMessage = getBackendErrorMessageFromBody(body);
7325
+ if (errorMessage) {
7326
+ return errorMessage;
7327
+ }
7328
+ const incompleteMessage = getBackendIncompleteMessage(body);
7329
+ if (incompleteMessage) {
7330
+ return incompleteMessage;
7331
+ }
7332
+ const status = getBackendResponseStatus(body);
7333
+ if (status && status !== 'completed') {
7334
+ return `Backend response status was "${status}".`;
7335
+ }
7336
+ if (isObject$2(body) && Array.isArray(Reflect.get(body, 'output'))) {
7337
+ return 'Unexpected backend response format: no assistant text or tool calls were returned.';
7338
+ }
7339
+ return 'Unexpected backend response format.';
7340
+ };
7341
+ const toExecutedToolCall = (toolCall, content) => {
7342
+ const executionStatus = getToolCallExecutionStatus(content);
7343
+ const toolCallResult = getToolCallResult(toolCall.name, content);
7344
+ return {
7345
+ arguments: toolCall.arguments,
7346
+ ...(executionStatus.errorMessage ? {
7347
+ errorMessage: executionStatus.errorMessage
7348
+ } : {}),
7349
+ ...(executionStatus.errorStack ? {
7350
+ errorStack: executionStatus.errorStack
7351
+ } : {}),
7352
+ id: toolCall.callId,
7353
+ name: toolCall.name,
7354
+ ...(toolCallResult ? {
7355
+ result: toolCallResult
7356
+ } : {}),
7357
+ ...(executionStatus.status ? {
7358
+ status: executionStatus.status
7359
+ } : {})
7360
+ };
7361
+ };
7362
+ const getBackendResponseOutputText = body => {
7363
+ if (!isObject$2(body)) {
7364
+ return '';
7365
+ }
7366
+ const outputText = Reflect.get(body, 'output_text');
7367
+ if (typeof outputText === 'string' && outputText) {
7368
+ return outputText;
7369
+ }
7370
+ const text = Reflect.get(body, 'text');
7371
+ if (typeof text === 'string' && text) {
7372
+ return text;
7373
+ }
7374
+ const message = Reflect.get(body, 'message');
7375
+ if (isObject$2(message)) {
7376
+ const content = Reflect.get(message, 'content');
7377
+ if (typeof content === 'string' && content) {
7378
+ return content;
7379
+ }
7380
+ }
7381
+ const choices = Reflect.get(body, 'choices');
7382
+ if (Array.isArray(choices)) {
7383
+ const firstChoice = choices[0];
7384
+ if (isObject$2(firstChoice)) {
7385
+ const firstMessage = Reflect.get(firstChoice, 'message');
7386
+ if (isObject$2(firstMessage)) {
7387
+ const content = Reflect.get(firstMessage, 'content');
7388
+ if (typeof content === 'string' && content) {
7389
+ return content;
7390
+ }
7391
+ }
7392
+ }
7393
+ }
7394
+ const output = Reflect.get(body, 'output');
7395
+ if (!Array.isArray(output)) {
7396
+ return '';
7397
+ }
7398
+ const chunks = [];
7399
+ for (const outputItem of output) {
7400
+ if (!isObject$2(outputItem)) {
7401
+ continue;
7402
+ }
7403
+ if (Reflect.get(outputItem, 'type') !== 'message') {
7404
+ continue;
7405
+ }
7406
+ const content = Reflect.get(outputItem, 'content');
7407
+ if (!Array.isArray(content)) {
7408
+ continue;
7409
+ }
7410
+ for (const part of content) {
7411
+ if (!isObject$2(part)) {
7412
+ continue;
7413
+ }
7414
+ const type = Reflect.get(part, 'type');
7415
+ const text = Reflect.get(part, 'text');
7416
+ if ((type === 'output_text' || type === 'text') && typeof text === 'string' && text) {
7417
+ chunks.push(text);
7418
+ }
7419
+ }
7420
+ }
7421
+ return chunks.join('');
7422
+ };
7423
+ const getBackendResponsesBody = (input, modelId, systemPrompt, tools, maxToolCalls, webSearchEnabled, previousResponseId, reasoningEffort, supportsReasoningEffort = false) => {
7424
+ return getOpenAiParams(input, modelId, false, false, tools, webSearchEnabled, maxToolCalls, systemPrompt, previousResponseId, reasoningEffort, supportsReasoningEffort);
7425
+ };
7426
+ const getBackendAssistantText = async ({
7427
+ agentMode = defaultAgentMode,
7428
+ assetDir,
7429
+ authAccessToken,
7430
+ backendUrl,
7431
+ maxToolCalls = defaultMaxToolCalls,
7432
+ messages,
7433
+ modelId,
7434
+ onToolCallsChunk,
7435
+ platform,
7436
+ questionToolEnabled = false,
7437
+ reasoningEffort,
7438
+ sessionId,
7439
+ supportsReasoningEffort = false,
7440
+ systemPrompt,
7441
+ toolEnablement,
7442
+ useChatToolWorker,
7443
+ webSearchEnabled = false,
7444
+ workspaceUri
7445
+ }) => {
7234
7446
  const mockError = takeErrorResponse();
7235
7447
  if (mockError) {
7236
7448
  const errorMessage = getBackendErrorMessageFromBody(mockError.body);
@@ -7244,55 +7456,115 @@ const getBackendAssistantText = async (messages, selectedModelId, backendUrl, au
7244
7456
  } : {})
7245
7457
  });
7246
7458
  }
7247
- let response;
7248
- try {
7249
- response = await fetch(getBackendCompletionsEndpoint(backendUrl), {
7250
- body: JSON.stringify({
7251
- messages: [...(systemPrompt ? [{
7252
- content: systemPrompt,
7253
- role: 'system'
7254
- }] : []), ...messages.map(message => ({
7255
- content: message.text,
7256
- role: message.role
7257
- }))],
7258
- model: selectedModelId,
7259
- selectedModelId,
7260
- stream: false
7261
- }),
7262
- headers: {
7263
- Authorization: `Bearer ${authAccessToken}`,
7264
- 'Content-Type': 'application/json',
7265
- ...getClientRequestIdHeader()
7266
- },
7267
- method: 'POST'
7268
- });
7269
- } catch {
7270
- return getBackendErrorMessage({
7271
- details: 'request-failed'
7272
- });
7273
- }
7274
- if (!response.ok) {
7275
- const payload = await response.json().catch(() => undefined);
7276
- const errorMessage = getBackendErrorMessageFromBody(payload);
7277
- const statusCode = response.status || getBackendStatusCodeFromBody(payload);
7459
+ const mockResponse = takeResponse();
7460
+ const tools = await getBasicChatTools(agentMode, questionToolEnabled, toolEnablement);
7461
+ const input = messages.map(message => ({
7462
+ content: getChatMessageOpenAiContent(message),
7463
+ role: message.role
7464
+ }));
7465
+ let previousResponseId;
7466
+ const maxToolIterations = Math.max(0, maxToolCalls - 1);
7467
+ for (let index = 0; index <= maxToolIterations; index++) {
7468
+ let json;
7469
+ if (index === 0 && mockResponse) {
7470
+ json = mockResponse.body;
7471
+ } else {
7472
+ let response;
7473
+ try {
7474
+ response = await fetch(getBackendResponsesEndpoint(backendUrl), {
7475
+ body: JSON.stringify(getBackendResponsesBody(input, modelId, systemPrompt, tools, maxToolCalls, webSearchEnabled, previousResponseId, reasoningEffort, supportsReasoningEffort)),
7476
+ headers: {
7477
+ Authorization: `Bearer ${authAccessToken}`,
7478
+ 'Content-Type': 'application/json',
7479
+ ...getClientRequestIdHeader()
7480
+ },
7481
+ method: 'POST'
7482
+ });
7483
+ } catch (error) {
7484
+ const errorMessage = getErrorMessage(error);
7485
+ return getBackendErrorMessage({
7486
+ details: 'request-failed',
7487
+ ...(errorMessage ? {
7488
+ errorMessage
7489
+ } : {})
7490
+ });
7491
+ }
7492
+ if (!response.ok) {
7493
+ const payload = await response.json().catch(() => undefined);
7494
+ const errorMessage = getBackendErrorMessageFromBody(payload);
7495
+ const statusCode = response.status || getBackendStatusCodeFromBody(payload);
7496
+ return getBackendErrorMessage({
7497
+ details: 'http-error',
7498
+ ...(typeof statusCode === 'number' ? {
7499
+ statusCode
7500
+ } : {}),
7501
+ ...(errorMessage ? {
7502
+ errorMessage
7503
+ } : {})
7504
+ });
7505
+ }
7506
+ try {
7507
+ json = await response.json();
7508
+ } catch {
7509
+ return getBackendErrorMessage({
7510
+ details: 'invalid-response',
7511
+ errorMessage: 'Backend returned invalid JSON.'
7512
+ });
7513
+ }
7514
+ }
7515
+ const responseFunctionCalls = getBackendResponseFunctionCalls(json);
7516
+ if (responseFunctionCalls.length > 0) {
7517
+ const responseId = getBackendResponseId(json);
7518
+ if (!responseId) {
7519
+ return getBackendErrorMessage({
7520
+ details: 'invalid-response',
7521
+ errorMessage: 'Unexpected backend response format: tool calls were returned without a response id.'
7522
+ });
7523
+ }
7524
+ previousResponseId = responseId;
7525
+ input.length = 0;
7526
+ const executedToolCalls = [];
7527
+ for (const toolCall of responseFunctionCalls) {
7528
+ const content = await executeChatTool(toolCall.name, toolCall.arguments, {
7529
+ assetDir,
7530
+ platform,
7531
+ ...(sessionId ? {
7532
+ sessionId
7533
+ } : {}),
7534
+ toolCallId: toolCall.callId,
7535
+ ...(toolEnablement ? {
7536
+ toolEnablement
7537
+ } : {}),
7538
+ useChatToolWorker,
7539
+ ...(workspaceUri ? {
7540
+ workspaceUri
7541
+ } : {})
7542
+ });
7543
+ executedToolCalls.push(toExecutedToolCall(toolCall, content));
7544
+ input.push({
7545
+ call_id: toolCall.callId,
7546
+ output: content,
7547
+ type: 'function_call_output'
7548
+ });
7549
+ }
7550
+ if (onToolCallsChunk && executedToolCalls.length > 0) {
7551
+ await onToolCallsChunk(executedToolCalls);
7552
+ }
7553
+ continue;
7554
+ }
7555
+ const content = getBackendResponseOutputText(json);
7556
+ if (content) {
7557
+ return content;
7558
+ }
7278
7559
  return getBackendErrorMessage({
7279
- details: 'http-error',
7280
- ...(typeof statusCode === 'number' ? {
7281
- statusCode
7282
- } : {}),
7283
- ...(errorMessage ? {
7284
- errorMessage
7285
- } : {})
7560
+ details: 'invalid-response',
7561
+ errorMessage: getBackendInvalidResponseDetails(json)
7286
7562
  });
7287
7563
  }
7288
- let json;
7289
- try {
7290
- json = await response.json();
7291
- } catch {
7292
- return backendCompletionFailedMessage;
7293
- }
7294
- const content = json.text || json.message?.content || json.choices?.[0]?.message?.content;
7295
- return typeof content === 'string' && content ? content : backendCompletionFailedMessage;
7564
+ return getBackendErrorMessage({
7565
+ details: 'invalid-response',
7566
+ errorMessage: `Backend request ended after ${maxToolCalls} tool-call rounds without a final assistant response. This usually means the model got stuck in a tool loop.`
7567
+ });
7296
7568
  };
7297
7569
  const getAiResponse = async ({
7298
7570
  agentMode = defaultAgentMode,
@@ -7392,6 +7664,7 @@ const getAiResponse = async ({
7392
7664
  const selectedModel = models.find(model => model.id === selectedModelId);
7393
7665
  const supportsImages = selectedModel?.supportsImages ?? false;
7394
7666
  const supportsReasoningEffort = selectedModel?.supportsReasoningEffort ?? false;
7667
+ const safeMaxToolCalls = Math.max(1, maxToolCalls);
7395
7668
  if (hasImageAttachments(messages) && !supportsImages) {
7396
7669
  text = getImageNotSupportedMessage(selectedModel?.name);
7397
7670
  }
@@ -7399,13 +7672,35 @@ const getAiResponse = async ({
7399
7672
  if (!backendUrl) {
7400
7673
  text = backendUrlRequiredMessage;
7401
7674
  } else if (authAccessToken) {
7402
- text = await getBackendAssistantText(messages, selectedModelId, backendUrl, authAccessToken, systemPrompt);
7675
+ text = await getBackendAssistantText({
7676
+ agentMode,
7677
+ assetDir,
7678
+ authAccessToken,
7679
+ backendUrl,
7680
+ maxToolCalls: safeMaxToolCalls,
7681
+ messages,
7682
+ modelId: getOpenApiModelId(selectedModelId),
7683
+ onToolCallsChunk,
7684
+ platform,
7685
+ questionToolEnabled,
7686
+ reasoningEffort,
7687
+ supportsReasoningEffort,
7688
+ systemPrompt,
7689
+ toolEnablement,
7690
+ useChatToolWorker,
7691
+ webSearchEnabled: agentMode === 'plan' ? false : webSearchEnabled,
7692
+ ...(sessionId ? {
7693
+ sessionId
7694
+ } : {}),
7695
+ ...(workspaceUri ? {
7696
+ workspaceUri
7697
+ } : {})
7698
+ });
7403
7699
  } else {
7404
7700
  text = backendAccessTokenRequiredMessage;
7405
7701
  }
7406
7702
  }
7407
7703
  if (!text && usesOpenApiModel) {
7408
- const safeMaxToolCalls = Math.max(1, maxToolCalls);
7409
7704
  if (useMockApi) {
7410
7705
  const openAiInput = messages.map(message => ({
7411
7706
  content: getChatMessageOpenAiContent(message),
@@ -10744,6 +11039,11 @@ const mockBackendSetHttpErrorResponse = (state, statusCode, body) => {
10744
11039
  return state;
10745
11040
  };
10746
11041
 
11042
+ const mockBackendSetResponse = (state, body) => {
11043
+ setResponse(body);
11044
+ return state;
11045
+ };
11046
+
10747
11047
  const mockOpenApiRequestGetAll = _state => {
10748
11048
  return getAll();
10749
11049
  };
@@ -15830,6 +16130,7 @@ const commandMap = {
15830
16130
  'Chat.loadContent2': wrapCommand(loadContent),
15831
16131
  'Chat.mockBackendAuthResponse': wrapCommand(mockBackendAuthResponse),
15832
16132
  'Chat.mockBackendSetHttpErrorResponse': wrapCommand(mockBackendSetHttpErrorResponse),
16133
+ 'Chat.mockBackendSetResponse': wrapCommand(mockBackendSetResponse),
15833
16134
  'Chat.mockOpenApiRequestGetAll': wrapGetter(mockOpenApiRequestGetAll),
15834
16135
  'Chat.mockOpenApiRequestReset': wrapCommand(mockOpenApiRequestReset),
15835
16136
  'Chat.mockOpenApiSetHttpErrorResponse': wrapCommand(mockOpenApiSetHttpErrorResponse),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/chat-view",
3
- "version": "7.9.0",
3
+ "version": "7.11.0",
4
4
  "description": "Chat View Worker",
5
5
  "repository": {
6
6
  "type": "git",