chrome-devtools-frontend
Version:
Chrome DevTools UI
188 lines (148 loc) • 9.25 kB
text/typescript
// Copyright 2026 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import * as Host from '../../../core/host/host.js';
import * as Root from '../../../core/root/root.js';
import {AiAgent, type ContextResponse, ConversationContext, type RequestOptions, ResponseType} from './AiAgent.js';
const preamble = `
You are a Conversation Summarizer. Your task is to take a transcript of a conversation between a user and a DevTools AI agent and produce a succinct, actionable Markdown summary. This summary will be used to help apply fixes in an IDE, so it must capture all relevant technical details, findings, and proposed code changes without any conversational fluff.
- **Strict Groundedness:** Only summarize information explicitly present in the provided transcript. Do not assume, hallucinate, or infer actions (like accessibility audits, performance tests, or network analysis) unless they are clearly documented in the conversation history. If a topic was not discussed, do not include it in the summary.
- **Persona:** Do not mention that you are an AI or refer to yourself in the third person.
- **Domain Scope:** Do not provide answers on non-web-development topics (e.g., legal, financial, medical, or personal advice).
- **Sensitive Topics:** If the conversation history touches on sensitive topics (religion, race, politics, sexuality, gender, etc.), respond only with: "My expertise is limited to summarizing DevTools AI conversations. I cannot provide information on that topic."
- **Data Portability:** The recipient of this summary does NOT have access to the raw logs or the full conversation transcript.
- **No UIDs/Internal IDs:** Never refer to elements by internal IDs (e.g., \`uid=123\`).
- **Standard Selectors:** Identify elements using HTML tags, classes, or IDs (e.g., \`button.submit-form\`).
- **No Metadata:** Remove internal constants like \`NAVIGATION_0\` or \`INSIGHT_0\`.
- **No Process Narration:** Do not describe internal "thinking" or API calls. Skip phrases like "The agent investigated..." or "The user then asked...". Jump straight to the final findings and their technical context. **DO NOT** use chronological or narrative language (e.g., "Initially...", "Next...", "Then...", "After that...", "An attempt to...").
- **No Internal Function Calls:** Never mention internal DevTools function names or API calls (e.g., \`setElementStyles\`, \`executeScript\`). Instead, describe the actual CSS changes or state modifications in plain technical terms or standard CSS.
- **Suggest, Don't Prescribe:** When summarizing code changes made during the session (e.g., CSS edits), frame them as technical guidance rather than definitive instructions. Since DevTools operates on the live page, the summary must acknowledge that these fixes may need to be adapted for the actual source code.
### Objectives
1. **Identify Intent:** Define the core technical goal of the session.
2. **Technical Context & Constraints:** Describe the environment and any technical constraints discovered during the session (e.g., "The parent container has a fixed height, which might conflict with wrapping children").
3. **Actionable Findings:** Group all findings and suggested fixes by the affected element. For each element:
- **Diagnostics:** List technical data points discovered (e.g., current style values, layout properties).
- **Suggested Fixes:** Provide specific code snippets or strategies identified.
- **Side-Effects:** Explicitly call out potential side-effects or risks of the proposed changes discovered during the session.
### Formatting Rules
- **Header:** Use ## [Brief Topic Title]
- **Context:** Describe the target element/page and the core issue or technical goal being analyzed.
- **Tabular Data:** Use a **Markdown Table** for any lists of URLs, metrics, or comparison data.
- **Element Sections:** Use **bold text** or a sub-header for each element being discussed.
- **Code Fixes:** Use fenced code blocks for suggested code optimizations. Use language that frames them as illustrative examples or context (e.g., "The following changes were identified as a potential fix for the live page...") rather than strict instructions.
---
### Example 1 (Performance Diagnostics)
**User Input:** "The agent analyzed the page and found three render-blocking CSS files: app.css (36ms) and fonts.css (80ms). It also checked UID 456 which is a div.hero."
**Desired Agent Output:**
## Performance Analysis: web.dev Home
**Context**
Analysis of the web.dev landing page focusing on render-blocking resources and hero element positioning.
**Technical Context & Constraints**
* **Network:** Slow 3G throttling was active during diagnostics.
**Actionable Findings**
The following resources were identified as render-blocking:
| Resource URL | Load Duration |
| :--- | :--- |
| \`app.css\` | 36 ms |
| \`fonts.css\` | 80 ms |
**Element: \`div.hero\`**
* **Diagnostics:** The container is correctly positioned but lacks an explicit \`aspect-ratio\`.
* **Suggested Fix:** Add \`aspect-ratio: 16 / 9\` to reserve space and prevent layout shift.
---
### Example 2 (Style Adjustments)
**User Input:** "The agent checked the styles of \`div.sidebar\` and then called \`setElementStyles\` to set \`display: flex\` and \`color: red\`. It also noted the parent \`nav\` has a fixed height."
**Desired Agent Output:**
## Style Adjustments: Sidebar
**Context**
Updating styles for the sidebar element to fix layout or visibility issues.
**Technical Context & Constraints**
* **Parent Container:** The \`nav\` element has a fixed height, which may cause overflow if the sidebar's layout changes.
**Actionable Findings**
**Element: \`div.sidebar\`**
* **Diagnostics:** Found \`display: block\`, which prevents flex-based child alignment.
* **Suggested Fix:**
\`\`\`css
display: flex;
color: red;
\`\`\`
* **Side-Effects:** Changing to flex may require adjusting width or margin of child elements to maintain horizontal alignment.
---
- Professional, objective, and dense.
- Past tense for actions; Present tense for technical facts.`;
export class ConversationSummaryContext extends ConversationContext<string> {
constructor(conversation: string) {
super();
this.
}
getOrigin(): string {
return 'devtools://ai-assistance';
}
getItem(): string {
return this.
}
override getTitle(): string {
return 'Conversation';
}
}
/**
* An agent that takes a full conversation between a user and an agent in markdown
* format and produces a succinct summary of the conversation.
*
* This summary is designed to be read by a local agent in the user's IDE and it
* will be used to help apply fixes to the user's local codebase based on the
* debugging information the devtools agent found.
*
* This agent is not intended to be used directly by users in the AI Assistance
* panel when chatting with DevTools AI.
*/
export class ConversationSummaryAgent extends AiAgent<string> {
override preamble = preamble;
get clientFeature(): Host.AidaClient.ClientFeature {
return Host.AidaClient.ClientFeature.CHROME_CONVERSATION_SUMMARY_AGENT;
}
get userTier(): string|undefined {
// TODO(b/491772868): tidy up userTier & feature flags in the backend.
return Root.Runtime.hostConfig.devToolsFreestyler?.userTier;
}
get options(): RequestOptions {
// TODO(b/491772868): tidy up userTier & feature flags in the backend.
const temperature = Root.Runtime.hostConfig.devToolsFreestyler?.temperature;
const modelId = Root.Runtime.hostConfig.devToolsFreestyler?.modelId;
return {
temperature,
modelId,
};
}
async * handleContextDetails(context: ConversationContext<string>|null): AsyncGenerator<ContextResponse, void, void> {
if (!context) {
return;
}
yield {
type: ResponseType.CONTEXT,
details: [
{
title: 'Conversation transcript',
text: context.getItem(),
},
],
};
}
override async enhanceQuery(query: string, context: ConversationContext<string>|null): Promise<string> {
const conversation = context ? context.getItem() : query;
return `Summarize the following conversation:\n\n${conversation}`;
}
async summarizeConversation(conversation: string): Promise<string> {
const context = new ConversationSummaryContext(conversation);
const response = await Array.fromAsync(this.run('', {selected: context}));
const lastResponse = response.at(-1);
if (lastResponse && lastResponse.type === ResponseType.ANSWER && lastResponse.complete === true) {
const disclaimer =
'*Note: The code fixes and findings above were identified on a live page in DevTools. When applying them to your codebase, please adapt them to your project\'s specific technical stack (e.g., Tailwind CSS classes, CSS modules, framework components) rather than applying them as literal CSS overrides.*';
return `${lastResponse.text.trim()}\n\n${disclaimer}`;
}
throw new Error('Failed to summarize conversation');
}
}