diff --git a/packages/browser-extension/src/tools/browser-javascript.ts b/packages/browser-extension/src/tools/browser-javascript.ts index bfda6160..4c0cb37d 100644 --- a/packages/browser-extension/src/tools/browser-javascript.ts +++ b/packages/browser-extension/src/tools/browser-javascript.ts @@ -309,9 +309,7 @@ This ensures reliable execution.`, ); return { - output: - output.trim() || - "Code executed successfully (no output)\n\n⚠️ Note: CSP blocked direct execution. Code ran via JailJS interpreter.", + output: output.trim() || "Code executed successfully (no output)", isError: false, details: { files }, }; diff --git a/packages/web-ui/src/ChatPanel.ts b/packages/web-ui/src/ChatPanel.ts index a0870c3c..9a2a6bf5 100644 --- a/packages/web-ui/src/ChatPanel.ts +++ b/packages/web-ui/src/ChatPanel.ts @@ -168,7 +168,7 @@ export class ChatPanel extends LitElement { .session=${this.session} .enableAttachments=${true} .enableModelSelector=${true} - .enableThinking=${true} + .showThinkingSelector=${true} .showThemeToggle=${false} .showDebugToggle=${false} .onApiKeyRequired=${this.onApiKeyRequired} diff --git a/packages/web-ui/src/components/AgentInterface.ts b/packages/web-ui/src/components/AgentInterface.ts index d179cb25..4fa10223 100644 --- a/packages/web-ui/src/components/AgentInterface.ts +++ b/packages/web-ui/src/components/AgentInterface.ts @@ -21,9 +21,8 @@ export class AgentInterface extends LitElement { @property({ attribute: false }) session?: AgentSession; @property() enableAttachments = true; @property() enableModelSelector = true; - @property() enableThinking = true; + @property() enableThinkingSelector = true; @property() showThemeToggle = false; - @property() showDebugToggle = false; // Optional custom API key prompt handler - if not provided, uses default dialog @property({ attribute: false }) onApiKeyRequired?: (provider: string) => Promise; @@ -286,7 +285,7 @@ export class AgentInterface extends LitElement { .thinkingLevel=${state.thinkingLevel} .showAttachmentButton=${this.enableAttachments} .showModelSelector=${this.enableModelSelector} - .showThinking=${this.enableThinking} + .showThinkingSelector=${this.enableThinkingSelector} .onSend=${(input: string, attachments: Attachment[]) => { this.sendMessage(input, attachments); }} @@ -295,7 +294,7 @@ export class AgentInterface extends LitElement { ModelSelector.open(state.model, (model) => session.setModel(model)); }} .onThinkingChange=${ - this.enableThinking + this.enableThinkingSelector ? (level: "off" | "minimal" | "low" | "medium" | "high") => { session.setThinkingLevel(level); } diff --git a/packages/web-ui/src/components/MessageEditor.ts b/packages/web-ui/src/components/MessageEditor.ts index 7e35c2b8..aba4633d 100644 --- a/packages/web-ui/src/components/MessageEditor.ts +++ b/packages/web-ui/src/components/MessageEditor.ts @@ -1,9 +1,9 @@ -import { Button, html, icon } from "@mariozechner/mini-lit"; +import { Button, html, icon, Select, type SelectOption } from "@mariozechner/mini-lit"; import type { Model } from "@mariozechner/pi-ai"; import { LitElement } from "lit"; import { customElement, property, state } from "lit/decorators.js"; import { createRef, ref } from "lit/directives/ref.js"; -import { Loader2, Paperclip, Send, Sparkles, Square } from "lucide"; +import { Brain, Loader2, Paperclip, Send, Sparkles, Square } from "lucide"; import "./AttachmentTile.js"; import { type Attachment, loadAttachment } from "../utils/attachment-utils.js"; import { i18n } from "../utils/i18n.js"; @@ -33,13 +33,15 @@ export class MessageEditor extends LitElement { @property() isStreaming = false; @property() currentModel?: Model; + @property() thinkingLevel: "off" | "minimal" | "low" | "medium" | "high" = "off"; @property() showAttachmentButton = true; @property() showModelSelector = true; - @property() showThinking = false; // Disabled for now + @property() showThinkingSelector = true; @property() onInput?: (value: string) => void; @property() onSend?: (input: string, attachments: Attachment[]) => void; @property() onAbort?: () => void; @property() onModelSelect?: () => void; + @property() onThinkingChange?: (level: "off" | "minimal" | "low" | "medium" | "high") => void; @property() onFilesChange?: (files: Attachment[]) => void; @property() attachments: Attachment[] = []; @property() maxFiles = 10; @@ -150,6 +152,10 @@ export class MessageEditor extends LitElement { } override render() { + // Check if current model supports thinking/reasoning + const model = this.currentModel; + const supportsThinking = model?.reasoning === true; // Models with reasoning:true support thinking + return html`
@@ -194,7 +200,7 @@ export class MessageEditor extends LitElement {
- +
${ this.showAttachmentButton @@ -215,6 +221,30 @@ export class MessageEditor extends LitElement { ` : "" } + ${ + supportsThinking && this.showThinkingSelector + ? html` + ${Select({ + value: this.thinkingLevel, + placeholder: i18n("Off"), + options: [ + { value: "off", label: i18n("Off"), icon: icon(Brain, "sm") }, + { value: "minimal", label: i18n("Minimal"), icon: icon(Brain, "sm") }, + { value: "low", label: i18n("Low"), icon: icon(Brain, "sm") }, + { value: "medium", label: i18n("Medium"), icon: icon(Brain, "sm") }, + { value: "high", label: i18n("High"), icon: icon(Brain, "sm") }, + ] as SelectOption[], + onChange: (value: string) => { + this.onThinkingChange?.(value as "off" | "minimal" | "low" | "medium" | "high"); + }, + width: "80px", + size: "sm", + variant: "ghost", + fitContent: true, + })} + ` + : "" + }
diff --git a/packages/web-ui/src/utils/i18n.ts b/packages/web-ui/src/utils/i18n.ts index 6bdb5366..9cc2e56c 100644 --- a/packages/web-ui/src/utils/i18n.ts +++ b/packages/web-ui/src/utils/i18n.ts @@ -108,6 +108,11 @@ declare module "@mariozechner/mini-lit" { "API Key Required": string; "Enter your API key for {provider}": string; "The CORS proxy strips CORS headers from API responses, allowing browser-based apps to make direct calls to LLM providers without CORS restrictions. It forwards requests to providers while removing headers that would otherwise block cross-origin requests.": string; + Off: string; + Minimal: string; + Low: string; + Medium: string; + High: string; } } @@ -223,6 +228,11 @@ const translations = { "Enter your API key for {provider}": "Enter your API key for {provider}", "The CORS proxy strips CORS headers from API responses, allowing browser-based apps to make direct calls to LLM providers without CORS restrictions. It forwards requests to providers while removing headers that would otherwise block cross-origin requests.": "The CORS proxy strips CORS headers from API responses, allowing browser-based apps to make direct calls to LLM providers without CORS restrictions. It forwards requests to providers while removing headers that would otherwise block cross-origin requests.", + Off: "Off", + Minimal: "Minimal", + Low: "Low", + Medium: "Medium", + High: "High", }, de: { ...defaultGerman, @@ -335,6 +345,11 @@ const translations = { "Enter your API key for {provider}": "Geben Sie Ihren API-Schlüssel für {provider} ein", "The CORS proxy strips CORS headers from API responses, allowing browser-based apps to make direct calls to LLM providers without CORS restrictions. It forwards requests to providers while removing headers that would otherwise block cross-origin requests.": "Der CORS-Proxy entfernt CORS-Header aus API-Antworten und ermöglicht browserbasierte Anwendungen, direkte Aufrufe an LLM-Anbieter ohne CORS-Einschränkungen durchzuführen. Er leitet Anfragen an Anbieter weiter und entfernt Header, die sonst Cross-Origin-Anfragen blockieren würden.", + Off: "Aus", + Minimal: "Minimal", + Low: "Niedrig", + Medium: "Mittel", + High: "Hoch", }, };