chrome-devtools-frontend 1.0.1603822 → 1.0.1605219

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 (89) hide show
  1. package/AUTHORS +1 -0
  2. package/front_end/Tests.js +23 -7
  3. package/front_end/core/host/AidaClient.ts +153 -525
  4. package/front_end/core/host/AidaClientTypes.ts +470 -0
  5. package/front_end/core/host/AidaGcaTranslation.ts +231 -122
  6. package/front_end/core/host/GcaClient.ts +112 -0
  7. package/front_end/core/host/GcaTypes.ts +107 -155
  8. package/front_end/core/host/UserMetrics.ts +0 -1
  9. package/front_end/core/host/host.ts +2 -0
  10. package/front_end/core/protocol_client/DevToolsCDPConnection.ts +1 -1
  11. package/front_end/core/root/ExperimentNames.ts +0 -1
  12. package/front_end/core/root/Runtime.ts +5 -0
  13. package/front_end/core/sdk/AutofillModel.ts +3 -2
  14. package/front_end/core/sdk/CSSModel.ts +3 -4
  15. package/front_end/core/sdk/CSSProperty.ts +1 -1
  16. package/front_end/core/sdk/ConsoleModel.ts +15 -13
  17. package/front_end/core/sdk/CookieModel.ts +5 -4
  18. package/front_end/core/sdk/DOMDebuggerModel.ts +20 -14
  19. package/front_end/core/sdk/DOMModel.ts +24 -22
  20. package/front_end/core/sdk/DebuggerModel.ts +21 -36
  21. package/front_end/core/sdk/EmulationModel.ts +21 -23
  22. package/front_end/core/sdk/EventBreakpointsModel.ts +16 -6
  23. package/front_end/core/sdk/HeapProfilerModel.ts +4 -7
  24. package/front_end/core/sdk/IsolateManager.ts +12 -7
  25. package/front_end/core/sdk/NetworkManager.ts +35 -28
  26. package/front_end/core/sdk/OverlayModel.ts +10 -10
  27. package/front_end/core/sdk/PreloadingModel.ts +3 -4
  28. package/front_end/core/sdk/ServiceWorkerManager.ts +2 -3
  29. package/front_end/core/sdk/SourceMapScopesInfo.ts +93 -63
  30. package/front_end/entrypoints/formatter_worker/FormatterWorker.ts +1 -3
  31. package/front_end/entrypoints/heap_snapshot_worker/AllocationProfile.ts +22 -48
  32. package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshot.ts +1 -1
  33. package/front_end/entrypoints/main/MainImpl.ts +0 -4
  34. package/front_end/generated/InspectorBackendCommands.ts +4 -0
  35. package/front_end/generated/SupportedCSSProperties.js +68 -2
  36. package/front_end/generated/protocol-mapping.d.ts +7 -0
  37. package/front_end/generated/protocol-proxy-api.d.ts +14 -0
  38. package/front_end/generated/protocol.ts +22 -0
  39. package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +31 -17
  40. package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.snapshot.txt +1 -1
  41. package/front_end/models/bindings/TempFile.ts +1 -4
  42. package/front_end/models/emulation/DeviceModeModel.ts +21 -26
  43. package/front_end/models/extensions/ExtensionAPI.ts +1 -1
  44. package/front_end/models/heap_snapshot_model/HeapSnapshotModel.ts +34 -47
  45. package/front_end/models/javascript_metadata/NativeFunctions.js +6 -6
  46. package/front_end/models/trace/insights/LCPDiscovery.ts +14 -6
  47. package/front_end/panels/ai_assistance/AiAssistancePanel.ts +85 -31
  48. package/front_end/panels/ai_assistance/components/ChatMessage.ts +50 -40
  49. package/front_end/panels/ai_assistance/components/ChatView.ts +3 -2
  50. package/front_end/panels/ai_assistance/components/WalkthroughView.ts +35 -7
  51. package/front_end/panels/ai_assistance/components/chatMessage.css +5 -1
  52. package/front_end/panels/application/ApplicationPanelSidebar.ts +6 -0
  53. package/front_end/panels/application/IndexedDBViews.ts +0 -9
  54. package/front_end/panels/application/WebMCPTreeElement.ts +35 -0
  55. package/front_end/panels/application/WebMCPView.ts +118 -0
  56. package/front_end/panels/application/application.ts +4 -0
  57. package/front_end/panels/application/webMCPView.css +65 -0
  58. package/front_end/panels/common/aiCodeCompletionSummaryToolbar.css +1 -1
  59. package/front_end/panels/console/consoleView.css +4 -0
  60. package/front_end/panels/elements/ElementsTreeElement.ts +91 -13
  61. package/front_end/panels/elements/StylesAiCodeCompletionProvider.ts +23 -2
  62. package/front_end/panels/elements/StylesSidebarPane.ts +85 -20
  63. package/front_end/panels/elements/elementsPanel.css +14 -0
  64. package/front_end/panels/elements/elementsTreeOutline.css +18 -0
  65. package/front_end/panels/network/NetworkLogViewColumns.ts +3 -3
  66. package/front_end/panels/profiler/HeapSnapshotDataGrids.ts +15 -19
  67. package/front_end/panels/profiler/HeapSnapshotGridNodes.ts +4 -2
  68. package/front_end/panels/profiler/HeapSnapshotProxy.ts +12 -16
  69. package/front_end/panels/profiler/HeapSnapshotView.ts +3 -10
  70. package/front_end/panels/profiler/ProfilesPanel.ts +5 -7
  71. package/front_end/panels/recorder/components/recordingView.css +0 -6
  72. package/front_end/panels/sensors/SensorsView.ts +28 -61
  73. package/front_end/panels/timeline/EventsTimelineTreeView.ts +2 -2
  74. package/front_end/panels/timeline/ThirdPartyTreeView.ts +35 -36
  75. package/front_end/panels/timeline/TimelineDetailsView.ts +47 -41
  76. package/front_end/panels/timeline/TimelinePanel.ts +1 -3
  77. package/front_end/panels/timeline/TimelineTreeView.ts +13 -13
  78. package/front_end/panels/timeline/components/LiveMetricsView.ts +852 -824
  79. package/front_end/panels/timeline/components/liveMetricsView.css +4 -0
  80. package/front_end/panels/timeline/thirdPartyTreeView.css +2 -2
  81. package/front_end/third_party/chromium/README.chromium +1 -1
  82. package/front_end/ui/components/buttons/button.css +2 -2
  83. package/front_end/ui/components/text_editor/AiCodeCompletionProvider.ts +0 -11
  84. package/front_end/ui/legacy/InspectorDrawerView.ts +206 -0
  85. package/front_end/ui/legacy/InspectorView.ts +41 -91
  86. package/front_end/ui/legacy/ViewManager.ts +14 -5
  87. package/front_end/ui/legacy/inspectorDrawerTabbedPane.css +5 -0
  88. package/front_end/ui/visual_logging/KnownContextValues.ts +2 -1
  89. package/package.json +1 -1
@@ -2,18 +2,19 @@
2
2
  // Use of this source code is governed by a BSD-style license that can be
3
3
  // found in the LICENSE file.
4
4
 
5
- import * as AIDA from './AidaClient.js';
5
+ import * as AIDA from './AidaClientTypes.js';
6
6
  import * as GCA from './GcaTypes.js';
7
7
 
8
8
  type AidaRequest = AIDA.DoConversationRequest|AIDA.CompletionRequest|AIDA.GenerateCodeRequest;
9
9
 
10
- function createBaseGcaRequest(request: AidaRequest, contents: GCA.Content[]): GCA.GenerateContentRequest {
11
- const gcaRequest: GCA.GenerateContentRequest = {contents};
10
+ function createBaseGcaRequest(
11
+ request: AidaRequest, contents: GCA.Content[], experience: string): GCA.GenerateContentRequest {
12
+ const gcaRequest: GCA.GenerateContentRequest = {contents, aicode: {experience}};
12
13
  mapCommonAidaRequestFields(request, gcaRequest);
13
14
  buildLabels(request, gcaRequest);
14
15
 
15
16
  if ('preamble' in request && request.preamble) {
16
- gcaRequest.system_instruction = {
17
+ gcaRequest.systemInstruction = {
17
18
  role: 'user',
18
19
  parts: [{text: request.preamble}],
19
20
  };
@@ -23,38 +24,41 @@ function createBaseGcaRequest(request: AidaRequest, contents: GCA.Content[]): GC
23
24
  }
24
25
 
25
26
  export function aidaDoConversationRequestToGcaRequest(request: AIDA.DoConversationRequest): GCA.GenerateContentRequest {
26
- const contents: GCA.Content[] = [];
27
+ try {
28
+ const contents: GCA.Content[] = [];
27
29
 
28
- if (request.historical_contexts) {
29
- contents.push(...request.historical_contexts.map(convertAidaContentToGcaContent));
30
- }
31
- contents.push(convertAidaContentToGcaContent(request.current_message));
32
-
33
- const gcaRequest = createBaseGcaRequest(request, contents);
34
-
35
- if (request.function_declarations) {
36
- gcaRequest.tools = [{
37
- function_declarations: request.function_declarations.map(fd => ({
38
- name: fd.name,
39
- description: fd.description,
40
- parameters: convertAidaParamToGcaSchema(fd.parameters),
41
- })),
42
- }];
30
+ if (request.historical_contexts) {
31
+ contents.push(...(request.historical_contexts).map(convertAidaContentToGcaContent));
32
+ }
33
+ contents.push(convertAidaContentToGcaContent(request.current_message));
34
+
35
+ const gcaRequest = createBaseGcaRequest(request, contents, 'chat_console_insights');
36
+
37
+ if (request.function_declarations) {
38
+ gcaRequest.tools = [{
39
+ functionDeclarations:
40
+ (request.function_declarations).map(fd => ({
41
+ name: fd.name,
42
+ description: fd.description,
43
+ parameters: convertAidaParamToGcaSchema(fd.parameters),
44
+ })),
45
+ }];
46
+ }
47
+ AIDA.debugLog('Translation succeded:', JSON.stringify(request), JSON.stringify(gcaRequest));
48
+ return gcaRequest;
49
+ } catch (e) {
50
+ AIDA.debugLog('Translation error:', JSON.stringify(request), e);
51
+ throw e;
43
52
  }
44
-
45
- return gcaRequest;
46
53
  }
47
54
 
48
55
  function mapCommonAidaRequestFields(aidaRequest: AidaRequest, gcaRequest: GCA.GenerateContentRequest): void {
49
56
  if (aidaRequest.options?.model_id) {
50
57
  gcaRequest.model = aidaRequest.options.model_id;
51
58
  }
52
- if (aidaRequest.metadata.string_session_id) {
53
- gcaRequest.session_id = aidaRequest.metadata.string_session_id;
54
- }
55
59
  if (aidaRequest.options?.temperature !== undefined) {
56
- gcaRequest.generation_config = {
57
- ...gcaRequest.generation_config,
60
+ gcaRequest.generationConfig = {
61
+ ...gcaRequest.generationConfig,
58
62
  temperature: aidaRequest.options.temperature,
59
63
  };
60
64
  }
@@ -62,24 +66,23 @@ function mapCommonAidaRequestFields(aidaRequest: AidaRequest, gcaRequest: GCA.Ge
62
66
 
63
67
  export function gcaResponseToAidaDoConversationResponse(response: GCA.GenerateContentResponse):
64
68
  AIDA.DoConversationResponse {
65
- const candidate = response.candidates[0];
66
69
  const functionCalls: AIDA.AidaFunctionCallResponse[] = [];
67
70
 
68
- if (candidate?.content?.parts) {
69
- for (const part of candidate.content.parts) {
70
- if (part.function_call) {
71
+ if (response.candidates?.[0].content?.parts) {
72
+ for (const part of response.candidates[0].content.parts) {
73
+ if (part.functionCall) {
71
74
  functionCalls.push({
72
- name: part.function_call.name,
73
- args: part.function_call.args || {},
75
+ name: part.functionCall.name,
76
+ args: part.functionCall.args || {},
74
77
  });
75
78
  }
76
79
  }
77
80
  }
78
81
 
79
82
  return {
80
- explanation: extractTextFromGcaParts(candidate?.content?.parts),
83
+ explanation: extractTextFromGcaParts(response.candidates[0].content?.parts),
81
84
  metadata: {
82
- rpcGlobalId: response.response_id,
85
+ rpcGlobalId: response.responseId,
83
86
  },
84
87
  functionCalls: functionCalls.length > 0 ?
85
88
  (functionCalls as [AIDA.AidaFunctionCallResponse, ...AIDA.AidaFunctionCallResponse[]]) :
@@ -96,33 +99,41 @@ function extractTextFromGcaParts(parts: GCA.Part[]|undefined): string {
96
99
  }
97
100
 
98
101
  export function aidaEventToGcaTelemetryRequest(clientEvent: AIDA.AidaRegisterClientEvent): GCA.SendTelemetryRequest {
99
- const feedbackMetrics: GCA.FeedbackMetric[] = [];
100
- const responseId = String(clientEvent.corresponding_aida_rpc_global_id);
101
- const eventTime = new Date().toISOString();
102
-
103
- if (clientEvent.do_conversation_client_event) {
104
- const feedback = clientEvent.do_conversation_client_event.user_feedback;
105
- if (feedback.sentiment) {
106
- let interaction: GCA.InteractionType = GCA.InteractionType.INTERACTION_TYPE_UNSPECIFIED;
107
- if (feedback.sentiment === AIDA.Rating.POSITIVE) {
108
- interaction = GCA.InteractionType.THUMBS_UP;
109
- } else if (feedback.sentiment === AIDA.Rating.NEGATIVE) {
110
- interaction = GCA.InteractionType.THUMBS_DOWN;
102
+ try {
103
+ const feedbackMetrics: GCA.FeedbackMetric[] = [];
104
+ const responseId = String(clientEvent.corresponding_aida_rpc_global_id);
105
+ const eventTime = new Date().toISOString();
106
+
107
+ if (clientEvent.do_conversation_client_event) {
108
+ const feedback = clientEvent.do_conversation_client_event.user_feedback;
109
+ if (feedback.sentiment) {
110
+ let interaction: GCA.InteractionType = GCA.InteractionType.INTERACTION_TYPE_UNSPECIFIED;
111
+ if (feedback.sentiment === AIDA.Rating.POSITIVE) {
112
+ interaction = GCA.InteractionType.THUMBS_UP;
113
+ } else if (feedback.sentiment === AIDA.Rating.NEGATIVE) {
114
+ interaction = GCA.InteractionType.THUMBS_DOWN;
115
+ }
116
+ feedbackMetrics.push({
117
+ eventTime,
118
+ responseId,
119
+ suggestionInteraction: {interaction},
120
+ });
111
121
  }
112
- feedbackMetrics.push({
113
- event_time: eventTime,
114
- response_id: responseId,
115
- suggestion_interaction: {interaction},
116
- });
117
122
  }
118
- }
119
-
120
- feedbackMetrics.push(
121
- ...convertCodeTelemetry(clientEvent.complete_code_client_event, GCA.Method.COMPLETE_CODE, responseId, eventTime));
122
- feedbackMetrics.push(
123
- ...convertCodeTelemetry(clientEvent.generate_code_client_event, GCA.Method.GENERATE_CODE, responseId, eventTime));
124
123
 
125
- return {feedback_metrics: feedbackMetrics};
124
+ feedbackMetrics.push(...convertCodeTelemetry(
125
+ clientEvent.complete_code_client_event, GCA.Method.COMPLETE_CODE, responseId, eventTime));
126
+ feedbackMetrics.push(...convertCodeTelemetry(
127
+ clientEvent.generate_code_client_event, GCA.Method.GENERATE_CODE, responseId, eventTime));
128
+ const gcaTelemetryRequest: GCA.SendTelemetryRequest = {
129
+ feedbackMetrics,
130
+ };
131
+ AIDA.debugLog('Translation succeeded:', JSON.stringify(clientEvent), JSON.stringify(gcaTelemetryRequest));
132
+ return gcaTelemetryRequest;
133
+ } catch (e) {
134
+ AIDA.debugLog('Translation error:', JSON.stringify(clientEvent), e);
135
+ throw e;
136
+ }
126
137
  }
127
138
 
128
139
  /* eslint-disable @typescript-eslint/naming-convention */
@@ -135,23 +146,23 @@ function convertCodeTelemetry(
135
146
  if ('user_impression' in event && event.user_impression) {
136
147
  const impression = event.user_impression;
137
148
  return [{
138
- event_time: eventTime,
139
- response_id: responseId,
140
- suggestion_offered: {
149
+ eventTime,
150
+ responseId,
151
+ suggestionOffered: {
141
152
  method,
142
153
  status: GCA.SuggestionStatus.NO_ERROR,
143
- response_latency: `${impression.latency.duration.seconds + impression.latency.duration.nanos / 1e9}s`,
154
+ responseLatency: `${impression.latency.duration.seconds + impression.latency.duration.nanos / 1e9}s`,
144
155
  },
145
156
  }];
146
157
  }
147
158
  if ('user_acceptance' in event && event.user_acceptance) {
148
159
  const acceptance = event.user_acceptance;
149
160
  return [{
150
- event_time: eventTime,
151
- response_id: responseId,
152
- suggestion_interaction: {
161
+ eventTime,
162
+ responseId,
163
+ suggestionInteraction: {
153
164
  interaction: GCA.InteractionType.ACCEPT,
154
- candidate_index: acceptance.sample.sample_id,
165
+ candidateIndex: acceptance.sample.sample_id,
155
166
  },
156
167
  }];
157
168
  }
@@ -160,33 +171,56 @@ function convertCodeTelemetry(
160
171
  /* eslint-enable @typescript-eslint/naming-convention */
161
172
 
162
173
  export function aidaCompletionRequestToGcaRequest(request: AIDA.CompletionRequest): GCA.GenerateContentRequest {
163
- const contents: GCA.Content[] = [
164
- {
165
- role: 'user',
166
- parts: [{text: request.prefix + (request.suffix || '')}],
167
- },
168
- ];
169
-
170
- const gcaRequest = createBaseGcaRequest(request, contents);
174
+ try {
175
+ let additionalFiles: GCA.SourceFile[] =
176
+ (request.additional_files ?? []).map(f => ({
177
+ fileUri: f.path,
178
+ inclusionReason: [AidaReasonToGcaInclusionReason[f.included_reason]],
179
+ }));
180
+
181
+ const inEditorFile: GCA.SourceFile = inFileEditRequestToSourceFile(request);
182
+ if (inEditorFile) {
183
+ additionalFiles = [inEditorFile, ...additionalFiles];
184
+ }
171
185
 
172
- if (request.options?.stop_sequences) {
173
- gcaRequest.generation_config = {
174
- ...gcaRequest.generation_config,
175
- stop_sequences: request.options.stop_sequences,
176
- };
186
+ const gcaRequest = createBaseGcaRequest(request, [], 'complete_code');
187
+ gcaRequest.aicode.files = additionalFiles;
188
+ if (request.options?.stop_sequences) {
189
+ gcaRequest.generationConfig = {
190
+ ...gcaRequest.generationConfig,
191
+ stopSequences: request.options.stop_sequences,
192
+ };
193
+ }
194
+ AIDA.debugLog('Translation succeeded:', JSON.stringify(request), JSON.stringify(gcaRequest));
195
+ return gcaRequest;
196
+ } catch (e) {
197
+ AIDA.debugLog('Translation error:', JSON.stringify(request), e);
198
+ throw e;
177
199
  }
200
+ }
178
201
 
179
- if (request.additional_files) {
180
- gcaRequest.aicode = {
181
- experience: 'completion',
182
- files: request.additional_files.map(f => ({
183
- file_uri: f.path,
184
- inclusion_reason: [AidaReasonToGcaInclusionReason[f.included_reason]],
185
- })),
186
- };
202
+ function inFileEditRequestToSourceFile(request: AIDA.CompletionRequest): GCA.SourceFile {
203
+ const sourceFile: GCA.SourceFile = {
204
+ inclusionReason: [GCA.InclusionReason.ACTIVE],
205
+ fileUri: 'devtools-code-completion',
206
+ segments: [
207
+ {
208
+ content: request.prefix,
209
+ isSelected: false,
210
+ },
211
+ {
212
+ content: '',
213
+ isSelected: true, // Cursor position
214
+ }
215
+ ],
216
+ };
217
+ if (request.suffix) {
218
+ sourceFile.segments?.push({
219
+ content: request.suffix,
220
+ isSelected: false,
221
+ });
187
222
  }
188
-
189
- return gcaRequest;
223
+ return sourceFile;
190
224
  }
191
225
 
192
226
  /* eslint-disable @typescript-eslint/naming-convention */
@@ -207,6 +241,9 @@ function buildLabels(request: AidaRequest, gcaRequest: GCA.GenerateContentReques
207
241
  if ('use_case' in request && request.use_case !== undefined) {
208
242
  labels['use_case'] = AIDA.UseCase[request.use_case];
209
243
  }
244
+ if (request.metadata.string_session_id) {
245
+ labels['session_id'] = request.metadata.string_session_id;
246
+ }
210
247
  const options = request.options as {
211
248
  inference_language?: string,
212
249
  expect_code_output?: boolean,
@@ -217,6 +254,12 @@ function buildLabels(request: AidaRequest, gcaRequest: GCA.GenerateContentReques
217
254
  if (options?.expect_code_output !== undefined) {
218
255
  labels['expect_code_output'] = String(options.expect_code_output);
219
256
  }
257
+ if (request.metadata.disable_user_content_logging !== undefined) {
258
+ labels['disable_user_content_logging'] = String(request.metadata.disable_user_content_logging);
259
+ }
260
+ if (request.metadata.client_version) {
261
+ labels['client_version'] = request.metadata.client_version;
262
+ }
220
263
 
221
264
  if (Object.keys(labels).length > 0) {
222
265
  gcaRequest.labels = labels;
@@ -236,11 +279,18 @@ const AidaReasonToGcaInclusionReason: Record<AIDA.Reason, GCA.InclusionReason> =
236
279
  };
237
280
 
238
281
  export function gcaResponseToAidaCompletionResponse(response: GCA.GenerateContentResponse): AIDA.CompletionResponse {
239
- const {samples, metadata} = gcaResponseToAidaSamplesAndMetadata(response);
240
- return {
241
- generatedSamples: samples,
242
- metadata,
243
- };
282
+ try {
283
+ const {samples, metadata} = gcaResponseToAidaSamplesAndMetadata(response);
284
+ const aidaResponse: AIDA.CompletionResponse = {
285
+ generatedSamples: samples,
286
+ metadata,
287
+ };
288
+ AIDA.debugLog('Translation succeeded:', JSON.stringify(response), JSON.stringify(aidaResponse));
289
+ return aidaResponse;
290
+ } catch (e) {
291
+ AIDA.debugLog('Translation error', JSON.stringify(response), e);
292
+ throw e;
293
+ }
244
294
  }
245
295
 
246
296
  function gcaResponseToAidaSamplesAndMetadata(response: GCA.GenerateContentResponse): {
@@ -248,32 +298,41 @@ function gcaResponseToAidaSamplesAndMetadata(response: GCA.GenerateContentRespon
248
298
  metadata: AIDA.ResponseMetadata,
249
299
  } {
250
300
  return {
251
- samples: response.candidates.map(gcaCandidateToAidaGenerationSample),
301
+ samples: (response.candidates ?? []).map(gcaCandidateToAidaGenerationSample),
252
302
  metadata: {
253
- rpcGlobalId: response.response_id,
303
+ rpcGlobalId: response.responseId,
254
304
  },
255
305
  };
256
306
  }
257
307
 
258
308
  export function aidaGenerateCodeRequestToGcaRequest(request: AIDA.GenerateCodeRequest): GCA.GenerateContentRequest {
259
- const gcaRequest = createBaseGcaRequest(request, [convertAidaContentToGcaContent(request.current_message)]);
260
-
261
- if (request.context_files) {
262
- gcaRequest.aicode = {
263
- experience: 'generate_code',
264
- files: request.context_files.map(f => ({
265
- file_uri: f.path,
266
- programming_language: f.programming_language,
267
- })),
268
- };
309
+ try {
310
+ const gcaRequest =
311
+ createBaseGcaRequest(request, [convertAidaContentToGcaContent(request.current_message)], 'generate_code');
312
+ if (request.context_files) {
313
+ gcaRequest.aicode.files = (request.context_files).map(f => ({
314
+ fileUri: f.path,
315
+ programmingLanguage: f.programming_language,
316
+ }));
317
+ }
318
+ AIDA.debugLog('Translation succeeded:', JSON.stringify(request), JSON.stringify(gcaRequest));
319
+ return gcaRequest;
320
+ } catch (e) {
321
+ AIDA.debugLog('Translation error', JSON.stringify(request), e);
322
+ throw e;
269
323
  }
270
-
271
- return gcaRequest;
272
324
  }
273
325
 
274
326
  export function gcaResponseToAidaGenerateCodeResponse(response: GCA.GenerateContentResponse):
275
327
  AIDA.GenerateCodeResponse {
276
- return gcaResponseToAidaSamplesAndMetadata(response);
328
+ try {
329
+ const aidaResponse: AIDA.GenerateCodeResponse = gcaResponseToAidaSamplesAndMetadata(response);
330
+ AIDA.debugLog('Translation succeeded:', JSON.stringify(response), JSON.stringify(aidaResponse));
331
+ return aidaResponse;
332
+ } catch (e) {
333
+ AIDA.debugLog('translation error', JSON.stringify(response), e);
334
+ throw e;
335
+ }
277
336
  }
278
337
 
279
338
  function gcaCandidateToAidaGenerationSample(candidate: GCA.Candidate): AIDA.GenerationSample {
@@ -282,14 +341,14 @@ function gcaCandidateToAidaGenerationSample(candidate: GCA.Candidate): AIDA.Gene
282
341
  score: 0,
283
342
  sampleId: candidate.index,
284
343
  };
285
- if (candidate.citation_metadata) {
344
+ if (candidate.citationMetadata) {
286
345
  generationSample.attributionMetadata = {
287
346
  attributionAction: AIDA.RecitationAction.CITE,
288
- citations: candidate.citation_metadata.citations.map(c => ({
289
- startIndex: c.start_index,
290
- endIndex: c.end_index,
291
- uri: c.uri,
292
- })),
347
+ citations: (candidate.citationMetadata.citations ?? []).map(c => ({
348
+ startIndex: c.startIndex,
349
+ endIndex: c.endIndex,
350
+ uri: c.uri,
351
+ })),
293
352
  };
294
353
  }
295
354
  return generationSample;
@@ -305,7 +364,7 @@ function convertAidaContentToGcaContent(content: AIDA.Content): GCA.Content {
305
364
  }
306
365
  return {
307
366
  role,
308
- parts: content.parts.map(convertAidaPartToGcaPart),
367
+ parts: (content.parts ?? []).map(convertAidaPartToGcaPart),
309
368
  };
310
369
  }
311
370
 
@@ -315,7 +374,7 @@ function convertAidaPartToGcaPart(part: AIDA.Part): GCA.Part {
315
374
  }
316
375
  if ('functionCall' in part) {
317
376
  return {
318
- function_call: {
377
+ functionCall: {
319
378
  name: part.functionCall.name,
320
379
  args: part.functionCall.args,
321
380
  },
@@ -334,7 +393,7 @@ function convertAidaPartToGcaPart(part: AIDA.Part): GCA.Part {
334
393
  fResponse.error = part.functionResponse.response['error'];
335
394
  }
336
395
  return {
337
- function_response: {
396
+ functionResponse: {
338
397
  name: part.functionResponse.name,
339
398
  response: fResponse,
340
399
  },
@@ -342,8 +401,8 @@ function convertAidaPartToGcaPart(part: AIDA.Part): GCA.Part {
342
401
  }
343
402
  if ('inlineData' in part) {
344
403
  return {
345
- inline_data: {
346
- mime_type: part.inlineData.mimeType,
404
+ inlineData: {
405
+ mimeType: part.inlineData.mimeType,
347
406
  data: part.inlineData.data,
348
407
  },
349
408
  };
@@ -370,8 +429,58 @@ function convertAidaParamToGcaSchema<T extends string|number|symbol = string>(pa
370
429
  for (const [key, value] of Object.entries(param.properties)) {
371
430
  schema.properties[key] = convertAidaParamToGcaSchema(value as FunctionParam);
372
431
  }
373
- schema.required = param.required.map(r => r.toString());
432
+ schema.required = (param.required ?? []).map(r => r.toString());
374
433
  }
375
434
 
376
435
  return schema;
377
436
  }
437
+
438
+ export function gcaChunkResponseToAidaChunkResponse(response: GCA.GenerateContentResponse): AIDA.AidaChunkResponse[] {
439
+ try {
440
+ const candidate = response.candidates?.[0];
441
+ const parts = candidate?.content?.parts || [];
442
+ const metadata: AIDA.ResponseMetadata = {
443
+ rpcGlobalId: response.responseId,
444
+ };
445
+
446
+ if (candidate?.citationMetadata?.citations) {
447
+ metadata.attributionMetadata = {
448
+ attributionAction: AIDA.RecitationAction.CITE,
449
+ citations: candidate.citationMetadata.citations.map(c => ({
450
+ startIndex: c.startIndex,
451
+ endIndex: c.endIndex,
452
+ uri: c.uri,
453
+ })),
454
+ };
455
+ }
456
+ const chunks: AIDA.AidaChunkResponse[] = (parts).map(part => {
457
+ const aidaChunkResponse: AIDA.AidaChunkResponse = {metadata};
458
+ if (part.text) {
459
+ aidaChunkResponse.textChunk = {
460
+ text: extractTextFromGcaParts(parts),
461
+ };
462
+ }
463
+ if (part.functionCall) {
464
+ aidaChunkResponse.functionCallChunk = {
465
+ functionCall: {
466
+ name: part.functionCall.name,
467
+ args: part.functionCall.args || {},
468
+ },
469
+ };
470
+ }
471
+ if (part.executableCode) {
472
+ aidaChunkResponse.codeChunk = {
473
+ code: part.executableCode.code,
474
+ inferenceLanguage: part.executableCode.language ? AIDA.AidaInferenceLanguage.PYTHON :
475
+ AIDA.AidaInferenceLanguage.UNKNOWN,
476
+ };
477
+ }
478
+ return aidaChunkResponse;
479
+ });
480
+ AIDA.debugLog('Translation succeeded:', JSON.stringify(response), JSON.stringify(chunks));
481
+ return chunks;
482
+ } catch (e) {
483
+ AIDA.debugLog('Translation error', JSON.stringify(response), e);
484
+ throw e;
485
+ }
486
+ }
@@ -0,0 +1,112 @@
1
+ // Copyright 2026 The Chromium Authors
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ import * as Root from '../root/root.js';
6
+
7
+ import {
8
+ type AidaRegisterClientEvent,
9
+ type CompletionRequest,
10
+ type CompletionResponse,
11
+ debugLog,
12
+ type DoConversationRequest,
13
+ type GenerateCodeRequest,
14
+ type GenerateCodeResponse
15
+ } from './AidaClientTypes.js';
16
+ import {
17
+ aidaCompletionRequestToGcaRequest,
18
+ aidaDoConversationRequestToGcaRequest,
19
+ aidaEventToGcaTelemetryRequest,
20
+ aidaGenerateCodeRequestToGcaRequest,
21
+ gcaResponseToAidaCompletionResponse,
22
+ gcaResponseToAidaGenerateCodeResponse
23
+ } from './AidaGcaTranslation.js';
24
+ import * as DispatchHttpRequestClient from './DispatchHttpRequestClient.js';
25
+ import type {GenerateContentRequest, GenerateContentResponse} from './GcaTypes.js';
26
+ import type {AidaClientResult} from './InspectorFrontendHostAPI.js';
27
+
28
+ const SERVICE_NAME = 'gcaService';
29
+
30
+ const ENDPOINTS = {
31
+ CONTENT: '/v1beta:generateContent',
32
+ SEND_TELEMETRY: '/v1beta:sendTelemetry',
33
+ STREAM_CONTENT: '/v1beta:streamGenerateContent',
34
+ };
35
+
36
+ export class GcaClient {
37
+ enabled(): boolean|undefined {
38
+ return Root.Runtime.hostConfig.devToolsUseGcaApi?.enabled;
39
+ }
40
+
41
+ async conversationRequest(request: DoConversationRequest, streamId: number, options?: {signal?: AbortSignal}):
42
+ Promise<void> {
43
+ try {
44
+ const gcaRequest = aidaDoConversationRequestToGcaRequest(request);
45
+ const response = await DispatchHttpRequestClient.makeHttpRequest<GenerateContentResponse>(
46
+ {
47
+ service: SERVICE_NAME,
48
+ path: ENDPOINTS.STREAM_CONTENT,
49
+ method: 'POST',
50
+ body: JSON.stringify(gcaRequest),
51
+ streamId,
52
+ },
53
+ options);
54
+ debugLog('GCA conversation request succeeded:', JSON.stringify(request), JSON.stringify(response));
55
+ } catch (err) {
56
+ debugLog('GCA request failed:', JSON.stringify(request), err);
57
+ throw err;
58
+ }
59
+ }
60
+
61
+ registerClientEvent(clientEvent: AidaRegisterClientEvent): Promise<AidaClientResult> {
62
+ const gcaEvent = aidaEventToGcaTelemetryRequest(clientEvent);
63
+ const response = DispatchHttpRequestClient.makeHttpRequest({
64
+ service: SERVICE_NAME,
65
+ path: ENDPOINTS.SEND_TELEMETRY,
66
+ method: 'POST',
67
+ body: JSON.stringify(gcaEvent),
68
+ });
69
+ return response.then(
70
+ result => {
71
+ debugLog('GCA register event succeeded:', JSON.stringify(gcaEvent), JSON.stringify(result));
72
+ return {} as AidaClientResult;
73
+ },
74
+ err => {
75
+ debugLog('GCA register event failed:', JSON.stringify(gcaEvent), err);
76
+ return {error: JSON.stringify(err)} as AidaClientResult;
77
+ });
78
+ }
79
+
80
+ async completeCode(request: CompletionRequest): Promise<CompletionResponse|null> {
81
+ const gcaRequest = aidaCompletionRequestToGcaRequest(request);
82
+ const result = await this.#requestContent(gcaRequest);
83
+ const aidaResult = result ? gcaResponseToAidaCompletionResponse(result) : null;
84
+ return aidaResult;
85
+ }
86
+
87
+ async generateCode(request: GenerateCodeRequest, options?: {signal?: AbortSignal}):
88
+ Promise<GenerateCodeResponse|null> {
89
+ const gcaRequest = aidaGenerateCodeRequestToGcaRequest(request);
90
+ const result = await this.#requestContent(gcaRequest, options);
91
+ return result ? gcaResponseToAidaGenerateCodeResponse(result) : null;
92
+ }
93
+
94
+ async #requestContent(request: GenerateContentRequest, options?: {signal?: AbortSignal}):
95
+ Promise<GenerateContentResponse|null> {
96
+ try {
97
+ const response = await DispatchHttpRequestClient.makeHttpRequest<GenerateContentResponse>(
98
+ {
99
+ service: SERVICE_NAME,
100
+ path: ENDPOINTS.CONTENT,
101
+ method: 'POST',
102
+ body: JSON.stringify(request),
103
+ },
104
+ options);
105
+ debugLog('GCA request succeeded:', JSON.stringify(request), JSON.stringify(response));
106
+ return response;
107
+ } catch (err) {
108
+ debugLog('GCA request failed:', JSON.stringify(request), err);
109
+ return null;
110
+ }
111
+ }
112
+ }