Browser tools: initialize lazily and add timeouts.

Also rename browser_screenshot to browser_take_screenshot for clarity\n- Update both Go and UI code to maintain consistency

Co-Authored-By: sketch <hello@sketch.dev>
Change-ID: s8a5cabff914f88dfk
diff --git a/webui/src/web-components/sketch-tool-card-take-screenshot.ts b/webui/src/web-components/sketch-tool-card-take-screenshot.ts
new file mode 100644
index 0000000..33bfae3
--- /dev/null
+++ b/webui/src/web-components/sketch-tool-card-take-screenshot.ts
@@ -0,0 +1,158 @@
+import { css, html, LitElement } from "lit";
+import { customElement, property, state } from "lit/decorators.js";
+import { ToolCall } from "../types";
+
+@customElement("sketch-tool-card-take-screenshot")
+export class SketchToolCardTakeScreenshot extends LitElement {
+  @property()
+  toolCall: ToolCall;
+
+  @property()
+  open: boolean;
+
+  @state()
+  imageLoaded: boolean = false;
+
+  @state()
+  loadError: boolean = false;
+
+  static styles = css`
+    .summary-text {
+      font-style: italic;
+      padding: 0.5em;
+    }
+
+    .screenshot-container {
+      margin: 10px 0;
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+    }
+
+    .screenshot {
+      max-width: 100%;
+      max-height: 500px;
+      border-radius: 4px;
+      box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
+      border: 1px solid #ddd;
+    }
+
+    .loading-indicator {
+      margin: 20px;
+      color: #666;
+      font-style: italic;
+    }
+
+    .error-message {
+      color: #d32f2f;
+      font-style: italic;
+      margin: 10px 0;
+    }
+
+    .screenshot-info {
+      margin-top: 8px;
+      font-size: 12px;
+      color: #666;
+    }
+
+    .selector-info {
+      padding: 4px 8px;
+      background-color: #f5f5f5;
+      border-radius: 4px;
+      font-family: monospace;
+      margin: 5px 0;
+      display: inline-block;
+    }
+  `;
+
+  constructor() {
+    super();
+  }
+
+  connectedCallback() {
+    super.connectedCallback();
+  }
+
+  disconnectedCallback() {
+    super.disconnectedCallback();
+  }
+
+  render() {
+    // Parse the input to get selector
+    let selector = "";
+    try {
+      if (this.toolCall?.input) {
+        const input = JSON.parse(this.toolCall.input);
+        selector = input.selector || "(full page)";
+      }
+    } catch (e) {
+      console.error("Error parsing screenshot input:", e);
+    }
+
+    // Get the screenshot ID from the result
+    let screenshotId = "";
+    let hasResult = false;
+    if (this.toolCall?.result_message?.tool_result) {
+      try {
+        const result = JSON.parse(this.toolCall.result_message.tool_result);
+        screenshotId = result.id;
+        hasResult = true;
+      } catch (e) {
+        console.error("Error parsing screenshot result:", e);
+      }
+    }
+
+    // Construct the URL for the screenshot (using relative URL without leading slash)
+    const screenshotUrl = screenshotId ? `screenshot/${screenshotId}` : "";
+
+    return html`
+      <sketch-tool-card .open=${this.open} .toolCall=${this.toolCall}>
+        <span slot="summary" class="summary-text">
+          Screenshot of ${selector}
+        </span>
+        <div slot="input" class="selector-info">
+          ${selector !== "(full page)"
+            ? `Taking screenshot of element: ${selector}`
+            : `Taking full page screenshot`}
+        </div>
+        <div slot="result">
+          ${hasResult
+            ? html`
+                <div class="screenshot-container">
+                  ${!this.imageLoaded && !this.loadError
+                    ? html`<div class="loading-indicator">
+                        Loading screenshot...
+                      </div>`
+                    : ""}
+                  ${this.loadError
+                    ? html`<div class="error-message">
+                        Failed to load screenshot
+                      </div>`
+                    : html`
+                        <img
+                          class="screenshot"
+                          src="${screenshotUrl}"
+                          @load=${() => (this.imageLoaded = true)}
+                          @error=${() => (this.loadError = true)}
+                          ?hidden=${!this.imageLoaded}
+                        />
+                        ${this.imageLoaded
+                          ? html`<div class="screenshot-info">
+                              Screenshot ID: ${screenshotId}
+                            </div>`
+                          : ""}
+                      `}
+                </div>
+              `
+            : ""}
+        </div>
+      </sketch-tool-card>
+    `;
+  }
+}
+
+declare global {
+  interface HTMLElementTagNameMap {
+    "sketch-tool-card-take-screenshot": SketchToolCardTakeScreenshot;
+  }
+}