blob: 8044e334054a3c4c96b58331b2e577b317cba896 [file] [log] [blame]
Sean McCullough86b56862025-04-18 13:04:03 -07001import { css, html, LitElement } from "lit";
Philip Zeyliger16fa8b42025-05-02 04:28:16 +00002import { customElement, property, state } from "lit/decorators.js";
Sean McCullough2deac842025-04-21 18:17:57 -07003import { repeat } from "lit/directives/repeat.js";
Sean McCulloughd9f13372025-04-21 15:08:49 -07004import { ToolCall } from "../types";
Pokey Ruleef58e062025-05-07 13:32:58 +01005import "./sketch-tool-card-bash";
6import "./sketch-tool-card-codereview";
7import "./sketch-tool-card-done";
8import "./sketch-tool-card-generic";
9import "./sketch-tool-card-multiple-choice";
10import "./sketch-tool-card-patch";
Philip Zeyliger33d282f2025-05-03 04:01:54 +000011import "./sketch-tool-card-screenshot";
Pokey Ruleef58e062025-05-07 13:32:58 +010012import "./sketch-tool-card-think";
13import "./sketch-tool-card-title";
Sean McCullough86b56862025-04-18 13:04:03 -070014
15@customElement("sketch-tool-calls")
16export class SketchToolCalls extends LitElement {
17 @property()
18 toolCalls: ToolCall[] = [];
19
Sean McCullough2deac842025-04-21 18:17:57 -070020 @property()
21 open: boolean = false;
22
Philip Zeyliger16fa8b42025-05-02 04:28:16 +000023 @state()
24 expanded: boolean = false;
25
Sean McCullough86b56862025-04-18 13:04:03 -070026 static styles = css`
27 /* Tool calls container styles */
28 .tool-calls-container {
Philip Zeyliger16fa8b42025-05-02 04:28:16 +000029 margin-top: 8px;
30 padding-top: 4px;
Sean McCullough86b56862025-04-18 13:04:03 -070031 }
32
Sean McCulloughec3ad1a2025-04-18 13:55:16 -070033 /* Card container */
Sean McCullough86b56862025-04-18 13:04:03 -070034 .tool-call-card {
35 display: flex;
36 flex-direction: column;
Philip Zeyliger16fa8b42025-05-02 04:28:16 +000037 background-color: rgba(255, 255, 255, 0.6);
38 border-radius: 6px;
39 margin-bottom: 6px;
Sean McCullough86b56862025-04-18 13:04:03 -070040 overflow: hidden;
41 cursor: pointer;
Philip Zeyliger16fa8b42025-05-02 04:28:16 +000042 border-left: 2px solid rgba(0, 0, 0, 0.1);
43 box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
Sean McCullough86b56862025-04-18 13:04:03 -070044 }
45
Sean McCulloughec3ad1a2025-04-18 13:55:16 -070046 /* Status indicators for tool calls */
Sean McCullough86b56862025-04-18 13:04:03 -070047 .tool-call-status {
48 margin-right: 4px;
49 text-align: center;
50 }
51
52 .tool-call-status.spinner {
53 animation: spin 1s infinite linear;
54 display: inline-block;
55 width: 1em;
56 }
57
Sean McCullough86b56862025-04-18 13:04:03 -070058 @keyframes spin {
59 0% {
60 transform: rotate(0deg);
61 }
62 100% {
63 transform: rotate(360deg);
64 }
65 }
Philip Zeyliger16fa8b42025-05-02 04:28:16 +000066
67 .tool-call-cards-container {
68 display: block;
69 }
Sean McCullough86b56862025-04-18 13:04:03 -070070 `;
71
72 constructor() {
73 super();
74 }
75
Sean McCullough86b56862025-04-18 13:04:03 -070076 connectedCallback() {
77 super.connectedCallback();
78 }
79
Sean McCullough86b56862025-04-18 13:04:03 -070080 disconnectedCallback() {
81 super.disconnectedCallback();
82 }
83
Sean McCulloughec3ad1a2025-04-18 13:55:16 -070084 cardForToolCall(toolCall: ToolCall, open: boolean) {
Sean McCullough86b56862025-04-18 13:04:03 -070085 switch (toolCall.name) {
Sean McCullough86b56862025-04-18 13:04:03 -070086 case "bash":
Sean McCulloughec3ad1a2025-04-18 13:55:16 -070087 return html`<sketch-tool-card-bash
88 .open=${open}
89 .toolCall=${toolCall}
90 ></sketch-tool-card-bash>`;
Sean McCullough86b56862025-04-18 13:04:03 -070091 case "codereview":
Sean McCulloughec3ad1a2025-04-18 13:55:16 -070092 return html`<sketch-tool-card-codereview
93 .open=${open}
94 .toolCall=${toolCall}
95 ></sketch-tool-card-codereview>`;
Sean McCullough86b56862025-04-18 13:04:03 -070096 case "done":
Sean McCulloughec3ad1a2025-04-18 13:55:16 -070097 return html`<sketch-tool-card-done
98 .open=${open}
99 .toolCall=${toolCall}
100 ></sketch-tool-card-done>`;
Sean McCullough485afc62025-04-28 14:28:39 -0700101 case "multiplechoice":
102 return html`<sketch-tool-card-multiple-choice
103 .open=${open}
104 .toolCall=${toolCall}
105 ></sketch-tool-card-multiple-choice>`;
Sean McCulloughec3ad1a2025-04-18 13:55:16 -0700106 case "patch":
107 return html`<sketch-tool-card-patch
108 .open=${open}
109 .toolCall=${toolCall}
110 ></sketch-tool-card-patch>`;
111 case "think":
112 return html`<sketch-tool-card-think
113 .open=${open}
114 .toolCall=${toolCall}
115 ></sketch-tool-card-think>`;
116 case "title":
117 return html`<sketch-tool-card-title
118 .open=${open}
119 .toolCall=${toolCall}
120 ></sketch-tool-card-title>`;
Philip Zeyliger33d282f2025-05-03 04:01:54 +0000121 case "browser_screenshot":
122 return html`<sketch-tool-card-screenshot
123 .open=${open}
124 .toolCall=${toolCall}
125 ></sketch-tool-card-screenshot>`;
Sean McCullough86b56862025-04-18 13:04:03 -0700126 }
Sean McCulloughec3ad1a2025-04-18 13:55:16 -0700127 return html`<sketch-tool-card-generic
128 .open=${open}
129 .toolCall=${toolCall}
130 ></sketch-tool-card-generic>`;
Sean McCullough86b56862025-04-18 13:04:03 -0700131 }
Sean McCulloughec3ad1a2025-04-18 13:55:16 -0700132
Sean McCullough2deac842025-04-21 18:17:57 -0700133 // toolUseKey return value should change, if the toolCall gets a response.
134 toolUseKey(toolCall: ToolCall): string {
Sean McCullough2deac842025-04-21 18:17:57 -0700135 if (!toolCall.result_message) {
136 return toolCall.tool_call_id;
137 }
138 return `${toolCall.tool_call_id}-${toolCall.result_message.idx}`;
139 }
140
Sean McCullough86b56862025-04-18 13:04:03 -0700141 render() {
Philip Zeyliger16fa8b42025-05-02 04:28:16 +0000142 if (!this.toolCalls || this.toolCalls.length === 0) {
143 return html``;
144 }
145
Sean McCulloughec3ad1a2025-04-18 13:55:16 -0700146 return html`<div class="tool-calls-container">
Sean McCullough86b56862025-04-18 13:04:03 -0700147 <div class="tool-call-cards-container">
Philip Zeyliger16fa8b42025-05-02 04:28:16 +0000148 ${repeat(this.toolCalls, this.toolUseKey, (toolCall, idx) => {
Philip Zeyliger33d282f2025-05-03 04:01:54 +0000149 let shouldOpen = false;
150 // Always expand screenshot tool calls, expand last tool call if this.open is true
151 if (
152 toolCall.name === "browser_screenshot" ||
153 (idx == this.toolCalls?.length - 1 && this.open)
154 ) {
155 shouldOpen = true;
Philip Zeyliger16fa8b42025-05-02 04:28:16 +0000156 }
157 return html`<div
158 id="${toolCall.tool_call_id}"
159 class="tool-call-card ${toolCall.name}"
160 >
Philip Zeyliger33d282f2025-05-03 04:01:54 +0000161 ${this.cardForToolCall(toolCall, shouldOpen)}
Philip Zeyliger16fa8b42025-05-02 04:28:16 +0000162 </div>`;
163 })}
Sean McCullough86b56862025-04-18 13:04:03 -0700164 </div>
165 </div>`;
166 }
167}
168
169declare global {
170 interface HTMLElementTagNameMap {
171 "sketch-tool-calls": SketchToolCalls;
172 }
173}