loop: add knowledge_base tool for on-demand information
The knowledge_base tool provides a way for agents to access specialized information
when needed. Initial topics include:
- sketch: how to use Sketch, including SSH, secrets, and file management
- go_iterators: information about Go's iterator feature added in Go 1.22
Co-Authored-By: sketch <hello@sketch.dev>
diff --git a/webui/src/web-components/sketch-tool-calls.ts b/webui/src/web-components/sketch-tool-calls.ts
index 5f416e1..99b0f21 100644
--- a/webui/src/web-components/sketch-tool-calls.ts
+++ b/webui/src/web-components/sketch-tool-calls.ts
@@ -4,6 +4,7 @@
import { ToolCall } from "../types";
import "./sketch-tool-card";
import "./sketch-tool-card-take-screenshot";
+import "./sketch-tool-card-knowledge-base";
@customElement("sketch-tool-calls")
export class SketchToolCalls extends LitElement {
@@ -127,6 +128,11 @@
.open=${open}
.toolCall=${toolCall}
></sketch-tool-card-take-screenshot>`;
+ case "knowledge_base":
+ return html`<sketch-tool-card-knowledge-base
+ .open=${open}
+ .toolCall=${toolCall}
+ ></sketch-tool-card-knowledge-base>`;
}
return html`<sketch-tool-card-generic
.open=${open}
diff --git a/webui/src/web-components/sketch-tool-card-knowledge-base.ts b/webui/src/web-components/sketch-tool-card-knowledge-base.ts
new file mode 100644
index 0000000..48dd798
--- /dev/null
+++ b/webui/src/web-components/sketch-tool-card-knowledge-base.ts
@@ -0,0 +1,79 @@
+import { css, html, LitElement } from "lit";
+import { unsafeHTML } from "lit/directives/unsafe-html.js";
+import { customElement, property } from "lit/decorators.js";
+import { ToolCall } from "../types";
+import { marked } from "marked";
+
+// Safely renders markdown with fallback to plain text on failure
+function renderMarkdown(markdownContent: string): string {
+ try {
+ return marked.parse(markdownContent, {
+ gfm: true,
+ breaks: true,
+ async: false,
+ }) as string;
+ } catch (error) {
+ console.error("Error rendering markdown:", error);
+ return markdownContent;
+ }
+}
+
+@customElement("sketch-tool-card-knowledge-base")
+export class SketchToolCardKnowledgeBase extends LitElement {
+ @property() toolCall: ToolCall;
+ @property() open: boolean;
+
+ static styles = css`
+ .summary-text {
+ font-style: italic;
+ }
+ .knowledge-content {
+ background: rgb(246, 248, 250);
+ border-radius: 6px;
+ padding: 12px;
+ margin-top: 10px;
+ max-height: 300px;
+ overflow-y: auto;
+ border: 1px solid #e1e4e8;
+ }
+ .topic-label {
+ font-weight: bold;
+ color: #24292e;
+ }
+ .icon {
+ margin-right: 6px;
+ }
+ `;
+
+ render() {
+ const inputData = JSON.parse(this.toolCall?.input || "{}");
+ const topic = inputData.topic || "unknown";
+ const resultText = this.toolCall?.result_message?.tool_result || "";
+
+ return html`
+ <sketch-tool-card .open=${this.open} .toolCall=${this.toolCall}>
+ <span slot="summary" class="summary-text">
+ <span class="icon">📚</span> Knowledge: ${topic}
+ </span>
+ <div slot="input">
+ <div>
+ <span class="topic-label">Topic:</span> ${topic}
+ </div>
+ </div>
+ ${this.toolCall?.result_message?.tool_result
+ ? html`<div slot="result">
+ <div class="knowledge-content">
+ ${unsafeHTML(renderMarkdown(resultText))}
+ </div>
+ </div>`
+ : ""}
+ </sketch-tool-card>
+ `;
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "sketch-tool-card-knowledge-base": SketchToolCardKnowledgeBase;
+ }
+}