Compare commits
5 Commits
v0.11.2-de
...
v0.11.3-de
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9800afb785 | ||
|
|
e84adebe61 | ||
|
|
d45a1ff078 | ||
|
|
b4121696bb | ||
|
|
f75c942162 |
15
package-lock.json
generated
15
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "codenomad-workspace",
|
||||
"version": "0.11.2",
|
||||
"version": "0.11.3",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "codenomad-workspace",
|
||||
"version": "0.11.2",
|
||||
"version": "0.11.3",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"7zip-bin": "^5.2.0",
|
||||
@@ -11985,7 +11985,7 @@
|
||||
},
|
||||
"packages/electron-app": {
|
||||
"name": "@neuralnomads/codenomad-electron-app",
|
||||
"version": "0.11.2",
|
||||
"version": "0.11.3",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@codenomad/ui": "file:../ui",
|
||||
@@ -12021,7 +12021,7 @@
|
||||
},
|
||||
"packages/server": {
|
||||
"name": "@neuralnomads/codenomad",
|
||||
"version": "0.11.2",
|
||||
"version": "0.11.3",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@fastify/cors": "^8.5.0",
|
||||
@@ -12062,7 +12062,7 @@
|
||||
},
|
||||
"packages/tauri-app": {
|
||||
"name": "@codenomad/tauri-app",
|
||||
"version": "0.11.2",
|
||||
"version": "0.11.3",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@tauri-apps/cli": "^2.9.4"
|
||||
@@ -12070,7 +12070,7 @@
|
||||
},
|
||||
"packages/ui": {
|
||||
"name": "@codenomad/ui",
|
||||
"version": "0.11.2",
|
||||
"version": "0.11.3",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@git-diff-view/solid": "^0.0.8",
|
||||
@@ -12092,7 +12092,8 @@
|
||||
"shiki": "^3.13.0",
|
||||
"solid-js": "^1.8.0",
|
||||
"solid-toast": "^0.5.0",
|
||||
"tauri-plugin-keepawake-api": "^0.1.0"
|
||||
"tauri-plugin-keepawake-api": "^0.1.0",
|
||||
"yaml": "^2.4.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vite-pwa/assets-generator": "^1.0.2",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "codenomad-workspace",
|
||||
"version": "0.11.2",
|
||||
"version": "0.11.3",
|
||||
"private": true,
|
||||
"description": "CodeNomad monorepo workspace",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@neuralnomads/codenomad-electron-app",
|
||||
"version": "0.11.2",
|
||||
"version": "0.11.3",
|
||||
"description": "CodeNomad - AI coding assistant",
|
||||
"license": "MIT",
|
||||
"author": {
|
||||
|
||||
4
packages/server/package-lock.json
generated
4
packages/server/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@neuralnomads/codenomad",
|
||||
"version": "0.11.2",
|
||||
"version": "0.11.3",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@neuralnomads/codenomad",
|
||||
"version": "0.11.2",
|
||||
"version": "0.11.3",
|
||||
"dependencies": {
|
||||
"@fastify/cors": "^8.5.0",
|
||||
"@fastify/reply-from": "^9.8.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@neuralnomads/codenomad",
|
||||
"version": "0.11.2",
|
||||
"version": "0.11.3",
|
||||
"description": "CodeNomad Server",
|
||||
"license": "MIT",
|
||||
"author": {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { FastifyInstance } from "fastify"
|
||||
import { z } from "zod"
|
||||
import { spawnSync } from "child_process"
|
||||
import { buildSpawnSpec } from "../../workspaces/runtime"
|
||||
import { probeBinaryVersion } from "../../workspaces/runtime"
|
||||
import type { SettingsService } from "../../settings/service"
|
||||
import type { Logger } from "../../logger"
|
||||
|
||||
@@ -15,37 +14,8 @@ const ValidateBinarySchema = z.object({
|
||||
})
|
||||
|
||||
function validateBinaryPath(binaryPath: string): { valid: boolean; version?: string; error?: string } {
|
||||
if (!binaryPath) {
|
||||
return { valid: false, error: "Missing binary path" }
|
||||
}
|
||||
|
||||
const spec = buildSpawnSpec(binaryPath, ["--version"])
|
||||
try {
|
||||
const result = spawnSync(spec.command, spec.args, {
|
||||
encoding: "utf8",
|
||||
windowsVerbatimArguments: Boolean((spec.options as { windowsVerbatimArguments?: boolean }).windowsVerbatimArguments),
|
||||
})
|
||||
|
||||
if (result.error) {
|
||||
return { valid: false, error: result.error.message }
|
||||
}
|
||||
if (result.status !== 0) {
|
||||
const stderr = result.stderr?.trim()
|
||||
const stdout = result.stdout?.trim()
|
||||
const combined = stderr || stdout
|
||||
const error = combined ? `Exited with code ${result.status}: ${combined}` : `Exited with code ${result.status}`
|
||||
return { valid: false, error }
|
||||
}
|
||||
|
||||
const stdout = (result.stdout ?? "").trim()
|
||||
const firstLine = stdout.split(/\r?\n/).find((line) => line.trim().length > 0)
|
||||
const normalized = firstLine?.trim()
|
||||
const versionMatch = normalized?.match(/([0-9]+\.[0-9]+\.[0-9A-Za-z.-]+)/)
|
||||
const version = versionMatch?.[1]
|
||||
return { valid: true, version }
|
||||
} catch (error) {
|
||||
return { valid: false, error: error instanceof Error ? error.message : String(error) }
|
||||
}
|
||||
const result = probeBinaryVersion(binaryPath)
|
||||
return { valid: result.valid, version: result.version, error: result.error }
|
||||
}
|
||||
|
||||
export function registerSettingsRoutes(app: FastifyInstance, deps: RouteDeps) {
|
||||
|
||||
@@ -8,7 +8,7 @@ import { FileSystemBrowser } from "../filesystem/browser"
|
||||
import { searchWorkspaceFiles, WorkspaceFileSearchOptions } from "../filesystem/search"
|
||||
import { clearWorkspaceSearchCache } from "../filesystem/search-cache"
|
||||
import { WorkspaceDescriptor, WorkspaceFileResponse, FileSystemEntry } from "../api-types"
|
||||
import { WorkspaceRuntime, ProcessExitInfo } from "./runtime"
|
||||
import { WorkspaceRuntime, ProcessExitInfo, probeBinaryVersion } from "./runtime"
|
||||
import { Logger } from "../logger"
|
||||
import { getOpencodeConfigDir } from "../opencode-config.js"
|
||||
import {
|
||||
@@ -283,28 +283,22 @@ export class WorkspaceManager {
|
||||
return undefined
|
||||
}
|
||||
|
||||
try {
|
||||
const result = spawnSync(resolvedPath, ["--version"], { encoding: "utf8" })
|
||||
if (result.status === 0 && result.stdout) {
|
||||
const line = result.stdout.split(/\r?\n/).find((entry) => entry.trim().length > 0)
|
||||
if (line) {
|
||||
const normalized = line.trim()
|
||||
const versionMatch = normalized.match(/([0-9]+\.[0-9]+\.[0-9A-Za-z.-]+)/)
|
||||
if (versionMatch) {
|
||||
const version = versionMatch[1]
|
||||
this.options.logger.debug({ binary: resolvedPath, version }, "Detected binary version")
|
||||
return version
|
||||
}
|
||||
this.options.logger.debug({ binary: resolvedPath, reported: normalized }, "Binary reported version string")
|
||||
return normalized
|
||||
}
|
||||
} else if (result.error) {
|
||||
this.options.logger.warn({ binary: resolvedPath, err: result.error }, "Failed to read binary version")
|
||||
const result = probeBinaryVersion(resolvedPath)
|
||||
if (result.valid) {
|
||||
if (result.version) {
|
||||
this.options.logger.debug({ binary: resolvedPath, version: result.version }, "Detected binary version")
|
||||
return result.version
|
||||
}
|
||||
} catch (error) {
|
||||
this.options.logger.warn({ binary: resolvedPath, err: error }, "Failed to detect binary version")
|
||||
if (result.reported) {
|
||||
this.options.logger.debug({ binary: resolvedPath, reported: result.reported }, "Binary reported version string")
|
||||
return result.reported
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
if (result.error) {
|
||||
this.options.logger.warn({ binary: resolvedPath, err: result.error }, "Failed to detect binary version")
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@ import { Logger } from "../logger"
|
||||
export const WINDOWS_CMD_EXTENSIONS = new Set([".cmd", ".bat"])
|
||||
export const WINDOWS_POWERSHELL_EXTENSIONS = new Set([".ps1"])
|
||||
|
||||
const VERSION_REGEX = /([0-9]+\.[0-9]+\.[0-9A-Za-z.-]+)/
|
||||
|
||||
export function buildSpawnSpec(binaryPath: string, args: string[]) {
|
||||
if (process.platform !== "win32") {
|
||||
return { command: binaryPath, args, options: {} as const }
|
||||
@@ -40,6 +42,61 @@ export function buildSpawnSpec(binaryPath: string, args: string[]) {
|
||||
return { command: binaryPath, args, options: {} as const }
|
||||
}
|
||||
|
||||
export function probeBinaryVersion(binaryPath: string): {
|
||||
valid: boolean
|
||||
version?: string
|
||||
reported?: string
|
||||
error?: string
|
||||
} {
|
||||
if (!binaryPath) {
|
||||
return { valid: false, error: "Missing binary path" }
|
||||
}
|
||||
|
||||
const spec = buildSpawnSpec(binaryPath, ["--version"])
|
||||
|
||||
try {
|
||||
const result = spawnSync(spec.command, spec.args, {
|
||||
encoding: "utf8",
|
||||
windowsVerbatimArguments: Boolean(
|
||||
(spec.options as { windowsVerbatimArguments?: boolean }).windowsVerbatimArguments,
|
||||
),
|
||||
})
|
||||
|
||||
if (result.error) {
|
||||
return { valid: false, error: result.error.message }
|
||||
}
|
||||
|
||||
if (result.status !== 0) {
|
||||
const stderr = result.stderr?.trim()
|
||||
const stdout = result.stdout?.trim()
|
||||
const combined = stderr || stdout
|
||||
const error = combined ? `Exited with code ${result.status}: ${combined}` : `Exited with code ${result.status}`
|
||||
return { valid: false, error }
|
||||
}
|
||||
|
||||
const stdoutLines = String(result.stdout ?? "")
|
||||
.split(/\r?\n/)
|
||||
.map((line) => line.trim())
|
||||
.filter((line) => line.length > 0)
|
||||
const stderrLines = String(result.stderr ?? "")
|
||||
.split(/\r?\n/)
|
||||
.map((line) => line.trim())
|
||||
.filter((line) => line.length > 0)
|
||||
|
||||
// Prefer stdout; fall back to stderr (some tools report version there).
|
||||
const reported = stdoutLines[0] ?? stderrLines[0]
|
||||
if (!reported) {
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
const versionMatch = reported.match(VERSION_REGEX)
|
||||
const version = versionMatch?.[1]
|
||||
return { valid: true, version, reported }
|
||||
} catch (error) {
|
||||
return { valid: false, error: error instanceof Error ? error.message : String(error) }
|
||||
}
|
||||
}
|
||||
|
||||
const SENSITIVE_ENV_KEY = /(PASSWORD|TOKEN|SECRET)/i
|
||||
|
||||
function redactEnvironment(env: Record<string, string | undefined>): Record<string, string | undefined> {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@codenomad/tauri-app",
|
||||
"version": "0.11.2",
|
||||
"version": "0.11.3",
|
||||
"private": true,
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@codenomad/ui",
|
||||
"version": "0.11.2",
|
||||
"version": "0.11.3",
|
||||
"private": true,
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
@@ -30,7 +30,8 @@
|
||||
"shiki": "^3.13.0",
|
||||
"solid-js": "^1.8.0",
|
||||
"solid-toast": "^0.5.0",
|
||||
"tauri-plugin-keepawake-api": "^0.1.0"
|
||||
"tauri-plugin-keepawake-api": "^0.1.0",
|
||||
"yaml": "^2.4.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vite-pwa/assets-generator": "^1.0.2",
|
||||
|
||||
@@ -72,6 +72,7 @@ const App: Component = () => {
|
||||
setToolOutputExpansion,
|
||||
setDiagnosticsExpansion,
|
||||
setThinkingBlocksExpansion,
|
||||
setToolInputsVisibility,
|
||||
} = useConfig()
|
||||
const [escapeInDebounce, setEscapeInDebounce] = createSignal(false)
|
||||
interface LaunchErrorState {
|
||||
@@ -402,6 +403,7 @@ const App: Component = () => {
|
||||
setToolOutputExpansion,
|
||||
setDiagnosticsExpansion,
|
||||
setThinkingBlocksExpansion,
|
||||
setToolInputsVisibility,
|
||||
handleNewInstanceRequest,
|
||||
handleCloseInstance,
|
||||
handleNewSession,
|
||||
|
||||
@@ -31,10 +31,10 @@ export default function AgentSelector(props: AgentSelectorProps) {
|
||||
const availableAgents = createMemo(() => {
|
||||
const allAgents = instanceAgents()
|
||||
if (isChildSession()) {
|
||||
return allAgents
|
||||
return allAgents.filter((agent) => !agent.hidden)
|
||||
}
|
||||
|
||||
const filtered = allAgents.filter((agent) => agent.mode !== "subagent")
|
||||
const filtered = allAgents.filter((agent) => !agent.hidden && agent.mode !== "subagent")
|
||||
|
||||
const currentAgent = allAgents.find((a) => a.name === props.currentAgent)
|
||||
if (currentAgent && !filtered.find((a) => a.name === props.currentAgent)) {
|
||||
@@ -103,10 +103,10 @@ export default function AgentSelector(props: AgentSelectorProps) {
|
||||
>
|
||||
<div class="flex-1 min-w-0">
|
||||
<Select.Value<Agent>>
|
||||
{(state) => (
|
||||
{() => (
|
||||
<div class="selector-trigger-label selector-trigger-label--stacked">
|
||||
<span class="selector-trigger-primary selector-trigger-primary--align-left">
|
||||
{t("agentSelector.trigger.primary", { agent: state.selectedOption()?.name ?? t("agentSelector.none") })}
|
||||
{t("agentSelector.trigger.primary", { agent: props.currentAgent || t("agentSelector.none") })}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { createSignal, Show, createEffect, createMemo, onCleanup } from "solid-js"
|
||||
import { Copy } from "lucide-solid"
|
||||
import { ArrowRightSquare, Copy } from "lucide-solid"
|
||||
import { stringify as stringifyYaml } from "yaml"
|
||||
import { messageStoreBus } from "../stores/message-v2/bus"
|
||||
import { useTheme } from "../lib/theme"
|
||||
import { useGlobalCache } from "../lib/hooks/use-global-cache"
|
||||
@@ -27,7 +28,17 @@ import type {
|
||||
ToolRendererContext,
|
||||
ToolScrollHelpers,
|
||||
} from "./tool-call/types"
|
||||
import { getRelativePath, getToolIcon, getToolName, isToolStateCompleted, isToolStateError, isToolStateRunning, getDefaultToolAction } from "./tool-call/utils"
|
||||
import {
|
||||
ensureMarkdownContent,
|
||||
getRelativePath,
|
||||
getToolIcon,
|
||||
getToolName,
|
||||
isToolStateCompleted,
|
||||
isToolStateError,
|
||||
isToolStateRunning,
|
||||
getDefaultToolAction,
|
||||
readToolStatePayload,
|
||||
} from "./tool-call/utils"
|
||||
import { resolveTitleForTool } from "./tool-call/tool-title"
|
||||
import { getLogger } from "../lib/logger"
|
||||
|
||||
@@ -155,12 +166,33 @@ export default function ToolCall(props: ToolCallProps) {
|
||||
const prefExpanded = toolOutputDefaultExpanded()
|
||||
const toolName = toolCallMemo()?.tool || ""
|
||||
if (toolName === "read") {
|
||||
const state = toolState()
|
||||
if (state?.status === "error") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
return prefExpanded
|
||||
})
|
||||
|
||||
const [userExpanded, setUserExpanded] = createSignal<boolean | null>(null)
|
||||
const toolInputsVisibility = createMemo(() => preferences().toolInputsVisibility || "collapsed")
|
||||
const [toolInputVisibilityOverride, setToolInputVisibilityOverride] = createSignal<"hidden" | "expanded" | null>(null)
|
||||
const effectiveToolInputsVisibility = createMemo(() => toolInputVisibilityOverride() ?? toolInputsVisibility())
|
||||
const isToolInputVisible = createMemo(() => effectiveToolInputsVisibility() !== "hidden")
|
||||
const inputDefaultExpanded = createMemo(() => effectiveToolInputsVisibility() === "expanded")
|
||||
const [inputSectionOverride, setInputSectionOverride] = createSignal<boolean | null>(null)
|
||||
const [outputSectionOverride, setOutputSectionOverride] = createSignal<boolean | null>(null)
|
||||
const inputSectionExpanded = () => {
|
||||
const override = inputSectionOverride()
|
||||
if (override !== null) return override
|
||||
return inputDefaultExpanded()
|
||||
}
|
||||
const outputSectionExpanded = () => {
|
||||
const override = outputSectionOverride()
|
||||
if (override !== null) return override
|
||||
return true
|
||||
}
|
||||
|
||||
const isPermissionActive = createMemo(() => {
|
||||
const pending = pendingPermission()
|
||||
@@ -183,6 +215,35 @@ export default function ToolCall(props: ToolCallProps) {
|
||||
return defaultExpandedForTool()
|
||||
}
|
||||
|
||||
const toolInput = createMemo(() => {
|
||||
const state = toolState()
|
||||
return readToolStatePayload(state).input
|
||||
})
|
||||
|
||||
const hasToolInput = createMemo(() => {
|
||||
const input = toolInput()
|
||||
return input && Object.keys(input).length > 0
|
||||
})
|
||||
|
||||
const toolInputMarkdown = createMemo(() => {
|
||||
const input = toolInput()
|
||||
if (!input || Object.keys(input).length === 0) return null
|
||||
|
||||
try {
|
||||
const yamlText = stringifyYaml(input)
|
||||
return ensureMarkdownContent(yamlText, "yaml", true)
|
||||
} catch (error) {
|
||||
log.error("Failed to convert tool call input to YAML", error)
|
||||
try {
|
||||
const jsonText = JSON.stringify(input, null, 2)
|
||||
return ensureMarkdownContent(jsonText, "json", true)
|
||||
} catch (nestedError) {
|
||||
log.error("Failed to stringify tool call input", nestedError)
|
||||
return null
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const permissionDetails = createMemo(() => pendingPermission()?.permission)
|
||||
const questionDetails = createMemo(() => pendingQuestion()?.request)
|
||||
|
||||
@@ -548,6 +609,25 @@ export default function ToolCall(props: ToolCallProps) {
|
||||
})
|
||||
}
|
||||
|
||||
createEffect(() => {
|
||||
// When global preference changes, reset per-tool-call overrides so palette changes apply.
|
||||
toolInputsVisibility()
|
||||
setToolInputVisibilityOverride(null)
|
||||
setInputSectionOverride(null)
|
||||
setOutputSectionOverride(null)
|
||||
})
|
||||
|
||||
const handleToggleInputVisibility = (event: MouseEvent) => {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
if (!expanded()) {
|
||||
toggle()
|
||||
}
|
||||
|
||||
const currentlyVisible = isToolInputVisible()
|
||||
setToolInputVisibilityOverride(currentlyVisible ? "hidden" : "expanded")
|
||||
}
|
||||
|
||||
const renderer = createMemo(() => resolveToolRenderer(toolName()))
|
||||
|
||||
const { renderAnsiContent } = createAnsiContentRenderer({
|
||||
@@ -789,6 +869,23 @@ export default function ToolCall(props: ToolCallProps) {
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<Show when={hasToolInput()}>
|
||||
<button
|
||||
type="button"
|
||||
class="tool-call-header-input"
|
||||
onClick={handleToggleInputVisibility}
|
||||
aria-pressed={isToolInputVisible()}
|
||||
aria-label={
|
||||
isToolInputVisible()
|
||||
? t("toolCall.header.hideInputAriaLabel")
|
||||
: t("toolCall.header.showInputAriaLabel")
|
||||
}
|
||||
title={isToolInputVisible() ? t("toolCall.header.hideInputTitle") : t("toolCall.header.showInputTitle")}
|
||||
>
|
||||
<ArrowRightSquare class="w-3.5 h-3.5" />
|
||||
</button>
|
||||
</Show>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="tool-call-header-copy"
|
||||
@@ -806,19 +903,79 @@ export default function ToolCall(props: ToolCallProps) {
|
||||
|
||||
{expanded() && (
|
||||
<div class="tool-call-details">
|
||||
{renderToolBody()}
|
||||
|
||||
{renderError()}
|
||||
|
||||
{renderPermissionBlock()}
|
||||
{renderQuestionBlock()}
|
||||
|
||||
<Show when={status() === "pending" && !pendingPermission()}>
|
||||
<div class="tool-call-pending-message">
|
||||
<span class="spinner-small"></span>
|
||||
<span>{t("toolCall.pending.waitingToRun")}</span>
|
||||
<Show
|
||||
when={isToolInputVisible() && hasToolInput()}
|
||||
fallback={
|
||||
<>
|
||||
{renderToolBody()}
|
||||
{renderError()}
|
||||
|
||||
<Show when={status() === "pending" && !pendingPermission()}>
|
||||
<div class="tool-call-pending-message">
|
||||
<span class="spinner-small"></span>
|
||||
<span>{t("toolCall.pending.waitingToRun")}</span>
|
||||
</div>
|
||||
</Show>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<div class="tool-call-io-sections">
|
||||
<div class="tool-call-io-section">
|
||||
<button
|
||||
type="button"
|
||||
class="tool-call-io-toggle"
|
||||
aria-expanded={inputSectionExpanded()}
|
||||
onClick={() => setInputSectionOverride((prev) => {
|
||||
const current = prev === null ? inputSectionExpanded() : prev
|
||||
return !current
|
||||
})}
|
||||
>
|
||||
<span class="tool-call-io-title">{t("toolCall.io.input")}</span>
|
||||
</button>
|
||||
|
||||
<Show when={inputSectionExpanded()}>
|
||||
<div class="tool-call-io-body">
|
||||
{(() => {
|
||||
const content = toolInputMarkdown()
|
||||
if (!content) return null
|
||||
return renderMarkdownContent({ content, cacheKey: "input" })
|
||||
})()}
|
||||
</div>
|
||||
</Show>
|
||||
</div>
|
||||
|
||||
<div class="tool-call-io-section">
|
||||
<button
|
||||
type="button"
|
||||
class="tool-call-io-toggle"
|
||||
aria-expanded={outputSectionExpanded()}
|
||||
onClick={() => setOutputSectionOverride((prev) => {
|
||||
const current = prev === null ? outputSectionExpanded() : prev
|
||||
return !current
|
||||
})}
|
||||
>
|
||||
<span class="tool-call-io-title">{t("toolCall.io.output")}</span>
|
||||
</button>
|
||||
|
||||
<Show when={outputSectionExpanded()}>
|
||||
<div class="tool-call-io-body">
|
||||
{renderToolBody()}
|
||||
{renderError()}
|
||||
|
||||
<Show when={status() === "pending" && !pendingPermission()}>
|
||||
<div class="tool-call-pending-message">
|
||||
<span class="spinner-small"></span>
|
||||
<span>{t("toolCall.pending.waitingToRun")}</span>
|
||||
</div>
|
||||
</Show>
|
||||
</div>
|
||||
</Show>
|
||||
</div>
|
||||
</div>
|
||||
</Show>
|
||||
|
||||
{renderPermissionBlock()}
|
||||
{renderQuestionBlock()}
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
@@ -287,13 +287,14 @@ const UnifiedPicker: Component<UnifiedPickerProps> = (props) => {
|
||||
if (mode() !== "mention") return
|
||||
|
||||
const query = props.searchQuery.toLowerCase()
|
||||
const visibleAgents = props.agents.filter((agent) => !agent.hidden)
|
||||
const filtered = query
|
||||
? props.agents.filter(
|
||||
? visibleAgents.filter(
|
||||
(agent) =>
|
||||
agent.name.toLowerCase().includes(query) ||
|
||||
(agent.description && agent.description.toLowerCase().includes(query)),
|
||||
)
|
||||
: props.agents
|
||||
: visibleAgents
|
||||
|
||||
setFilteredAgents(filtered)
|
||||
})
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { createSignal, onMount } from "solid-js"
|
||||
import type { Accessor } from "solid-js"
|
||||
import type { Preferences, ExpansionPreference } from "../../stores/preferences"
|
||||
import type { Preferences, ExpansionPreference, ToolInputsVisibilityPreference } from "../../stores/preferences"
|
||||
import { createCommandRegistry, type Command } from "../commands"
|
||||
import { instances, activeInstanceId, setActiveInstanceId } from "../../stores/instances"
|
||||
import type { ClientPart, MessageInfo } from "../../types/message"
|
||||
@@ -38,6 +38,7 @@ export interface UseCommandsOptions {
|
||||
setToolOutputExpansion: (mode: ExpansionPreference) => void
|
||||
setDiagnosticsExpansion: (mode: ExpansionPreference) => void
|
||||
setThinkingBlocksExpansion: (mode: ExpansionPreference) => void
|
||||
setToolInputsVisibility: (mode: ToolInputsVisibilityPreference) => void
|
||||
handleNewInstanceRequest: () => void
|
||||
handleCloseInstance: (instanceId: string) => Promise<void>
|
||||
handleNewSession: (instanceId: string) => Promise<void>
|
||||
@@ -551,6 +552,29 @@ export function useCommands(options: UseCommandsOptions) {
|
||||
},
|
||||
})
|
||||
|
||||
commandRegistry.register({
|
||||
id: "tool-inputs-visibility",
|
||||
label: () => {
|
||||
const mode = options.preferences().toolInputsVisibility || "hidden"
|
||||
const state =
|
||||
mode === "expanded"
|
||||
? tGlobal("commands.common.expanded")
|
||||
: mode === "collapsed"
|
||||
? tGlobal("commands.common.collapsed")
|
||||
: tGlobal("commands.common.hidden")
|
||||
return tGlobal("commands.toolInputsVisibility.label", { state })
|
||||
},
|
||||
description: () => tGlobal("commands.toolInputsVisibility.description"),
|
||||
category: "System",
|
||||
keywords: () => splitKeywords("commands.toolInputsVisibility.keywords"),
|
||||
action: () => {
|
||||
const mode = options.preferences().toolInputsVisibility || "hidden"
|
||||
const next: ToolInputsVisibilityPreference =
|
||||
mode === "hidden" ? "collapsed" : mode === "collapsed" ? "expanded" : "hidden"
|
||||
options.setToolInputsVisibility(next)
|
||||
},
|
||||
})
|
||||
|
||||
commandRegistry.register({
|
||||
id: "token-usage-visibility",
|
||||
label: () => {
|
||||
|
||||
@@ -130,6 +130,10 @@ export const commandMessages = {
|
||||
"commands.diagnosticsDefault.description": "Toggle default expansion for diagnostics output",
|
||||
"commands.diagnosticsDefault.keywords": "diagnostics, expand, collapse",
|
||||
|
||||
"commands.toolInputsVisibility.label": "Tool Inputs Visibility · {state}",
|
||||
"commands.toolInputsVisibility.description": "Set default visibility for tool call input arguments",
|
||||
"commands.toolInputsVisibility.keywords": "tool, inputs, arguments, visibility, hide, show, expand, collapse",
|
||||
|
||||
"commands.tokenUsageDisplay.label": "Token Usage Display · {state}",
|
||||
"commands.tokenUsageDisplay.description": "Show or hide token and cost stats for assistant messages",
|
||||
"commands.tokenUsageDisplay.keywords": "token, usage, cost, stats",
|
||||
|
||||
@@ -5,6 +5,14 @@ export const toolCallMessages = {
|
||||
"toolCall.header.copyTitle": "Copy tool call title",
|
||||
"toolCall.header.copyAriaLabel": "Copy tool call title",
|
||||
|
||||
"toolCall.header.showInputTitle": "Show Tool Arguments",
|
||||
"toolCall.header.showInputAriaLabel": "Show Tool Arguments",
|
||||
"toolCall.header.hideInputTitle": "Hide Tool Arguments",
|
||||
"toolCall.header.hideInputAriaLabel": "Hide Tool Arguments",
|
||||
|
||||
"toolCall.io.input": "Tool Input",
|
||||
"toolCall.io.output": "Tool Output",
|
||||
|
||||
"toolCall.diff.label": "Diff",
|
||||
"toolCall.diff.label.withPath": "Diff · {path}",
|
||||
"toolCall.diff.viewMode.ariaLabel": "Diff view mode",
|
||||
|
||||
@@ -130,6 +130,10 @@ export const commandMessages = {
|
||||
"commands.diagnosticsDefault.description": "Alternar la expansión por defecto de la salida de diagnósticos",
|
||||
"commands.diagnosticsDefault.keywords": "diagnósticos, expandir, colapsar",
|
||||
|
||||
"commands.toolInputsVisibility.label": "Visibilidad de entradas de herramientas · {state}",
|
||||
"commands.toolInputsVisibility.description": "Configurar la visibilidad por defecto de los argumentos de entrada de llamadas de herramienta",
|
||||
"commands.toolInputsVisibility.keywords": "herramienta, entradas, argumentos, visibilidad, ocultar, mostrar, expandir, colapsar",
|
||||
|
||||
"commands.tokenUsageDisplay.label": "Mostrar uso de tokens · {state}",
|
||||
"commands.tokenUsageDisplay.description": "Mostrar u ocultar estadísticas de tokens y costo en los mensajes del asistente",
|
||||
"commands.tokenUsageDisplay.keywords": "token, uso, costo, estadísticas",
|
||||
|
||||
@@ -5,6 +5,14 @@ export const toolCallMessages = {
|
||||
"toolCall.header.copyTitle": "Copy tool call title",
|
||||
"toolCall.header.copyAriaLabel": "Copy tool call title",
|
||||
|
||||
"toolCall.header.showInputTitle": "Show Tool Arguments",
|
||||
"toolCall.header.showInputAriaLabel": "Show Tool Arguments",
|
||||
"toolCall.header.hideInputTitle": "Hide Tool Arguments",
|
||||
"toolCall.header.hideInputAriaLabel": "Hide Tool Arguments",
|
||||
|
||||
"toolCall.io.input": "Tool Input",
|
||||
"toolCall.io.output": "Tool Output",
|
||||
|
||||
"toolCall.diff.label": "Diff",
|
||||
"toolCall.diff.label.withPath": "Diff · {path}",
|
||||
"toolCall.diff.viewMode.ariaLabel": "Modo de vista de diff",
|
||||
|
||||
@@ -130,6 +130,10 @@ export const commandMessages = {
|
||||
"commands.diagnosticsDefault.description": "Choisir l'ouverture par défaut de la sortie des diagnostics",
|
||||
"commands.diagnosticsDefault.keywords": "diagnostics, développer, réduire",
|
||||
|
||||
"commands.toolInputsVisibility.label": "Visibilité des entrées d'outil · {state}",
|
||||
"commands.toolInputsVisibility.description": "Définir la visibilité par défaut des arguments d'entrée des appels d'outil",
|
||||
"commands.toolInputsVisibility.keywords": "outil, entrées, arguments, visibilité, masquer, afficher, développer, réduire",
|
||||
|
||||
"commands.tokenUsageDisplay.label": "Affichage de l'usage des tokens · {state}",
|
||||
"commands.tokenUsageDisplay.description": "Afficher ou masquer les stats de tokens et de coût pour les messages de l'assistant",
|
||||
"commands.tokenUsageDisplay.keywords": "token, usage, coût, stats",
|
||||
|
||||
@@ -5,6 +5,14 @@ export const toolCallMessages = {
|
||||
"toolCall.header.copyTitle": "Copy tool call title",
|
||||
"toolCall.header.copyAriaLabel": "Copy tool call title",
|
||||
|
||||
"toolCall.header.showInputTitle": "Show Tool Arguments",
|
||||
"toolCall.header.showInputAriaLabel": "Show Tool Arguments",
|
||||
"toolCall.header.hideInputTitle": "Hide Tool Arguments",
|
||||
"toolCall.header.hideInputAriaLabel": "Hide Tool Arguments",
|
||||
|
||||
"toolCall.io.input": "Tool Input",
|
||||
"toolCall.io.output": "Tool Output",
|
||||
|
||||
"toolCall.diff.label": "Diff",
|
||||
"toolCall.diff.label.withPath": "Diff · {path}",
|
||||
"toolCall.diff.viewMode.ariaLabel": "Mode d'affichage du diff",
|
||||
|
||||
@@ -130,6 +130,10 @@ export const commandMessages = {
|
||||
"commands.diagnosticsDefault.description": "診断出力を既定で展開するか切り替え",
|
||||
"commands.diagnosticsDefault.keywords": "診断, 展開, 折りたたみ, diagnostics, expand, collapse",
|
||||
|
||||
"commands.toolInputsVisibility.label": "ツール入力の表示 · {state}",
|
||||
"commands.toolInputsVisibility.description": "ツール呼び出しの入力引数の既定の表示状態を設定します",
|
||||
"commands.toolInputsVisibility.keywords": "ツール, 入力, 引数, 表示, 非表示, 展開, 折りたたみ, tool, inputs, arguments, visibility, hide, show, expand, collapse",
|
||||
|
||||
"commands.tokenUsageDisplay.label": "トークン使用量表示 · {state}",
|
||||
"commands.tokenUsageDisplay.description": "アシスタントメッセージのトークン/コスト統計を表示/非表示",
|
||||
"commands.tokenUsageDisplay.keywords": "トークン, 使用量, コスト, 統計, token, usage, cost, stats",
|
||||
|
||||
@@ -5,6 +5,14 @@ export const toolCallMessages = {
|
||||
"toolCall.header.copyTitle": "Copy tool call title",
|
||||
"toolCall.header.copyAriaLabel": "Copy tool call title",
|
||||
|
||||
"toolCall.header.showInputTitle": "Show Tool Arguments",
|
||||
"toolCall.header.showInputAriaLabel": "Show Tool Arguments",
|
||||
"toolCall.header.hideInputTitle": "Hide Tool Arguments",
|
||||
"toolCall.header.hideInputAriaLabel": "Hide Tool Arguments",
|
||||
|
||||
"toolCall.io.input": "Tool Input",
|
||||
"toolCall.io.output": "Tool Output",
|
||||
|
||||
"toolCall.diff.label": "Diff",
|
||||
"toolCall.diff.label.withPath": "Diff · {path}",
|
||||
"toolCall.diff.viewMode.ariaLabel": "diff 表示モード",
|
||||
|
||||
@@ -130,6 +130,10 @@ export const commandMessages = {
|
||||
"commands.diagnosticsDefault.description": "Переключить, разворачивать ли вывод диагностики по умолчанию",
|
||||
"commands.diagnosticsDefault.keywords": "diagnostics, развернуть, свернуть",
|
||||
|
||||
"commands.toolInputsVisibility.label": "Видимость входных данных инструмента · {state}",
|
||||
"commands.toolInputsVisibility.description": "Установить видимость аргументов входа вызовов инструментов по умолчанию",
|
||||
"commands.toolInputsVisibility.keywords": "инструмент, вход, аргументы, видимость, скрыть, показать, раскрыть, свернуть, tool, inputs, arguments, visibility, hide, show, expand, collapse",
|
||||
|
||||
"commands.tokenUsageDisplay.label": "Отображение token-статистики · {state}",
|
||||
"commands.tokenUsageDisplay.description": "Показать или скрыть статистику token и стоимости для сообщений ассистента",
|
||||
"commands.tokenUsageDisplay.keywords": "token, usage, cost, статистика",
|
||||
|
||||
@@ -5,6 +5,14 @@ export const toolCallMessages = {
|
||||
"toolCall.header.copyTitle": "Copy tool call title",
|
||||
"toolCall.header.copyAriaLabel": "Copy tool call title",
|
||||
|
||||
"toolCall.header.showInputTitle": "Show Tool Arguments",
|
||||
"toolCall.header.showInputAriaLabel": "Show Tool Arguments",
|
||||
"toolCall.header.hideInputTitle": "Hide Tool Arguments",
|
||||
"toolCall.header.hideInputAriaLabel": "Hide Tool Arguments",
|
||||
|
||||
"toolCall.io.input": "Tool Input",
|
||||
"toolCall.io.output": "Tool Output",
|
||||
|
||||
"toolCall.diff.label": "Diff",
|
||||
"toolCall.diff.label.withPath": "Diff · {path}",
|
||||
"toolCall.diff.viewMode.ariaLabel": "Режим просмотра diff",
|
||||
|
||||
@@ -130,6 +130,10 @@ export const commandMessages = {
|
||||
"commands.diagnosticsDefault.description": "切换诊断输出是否默认展开",
|
||||
"commands.diagnosticsDefault.keywords": "diagnostics, expand, collapse, 诊断, 展开, 折叠",
|
||||
|
||||
"commands.toolInputsVisibility.label": "工具输入可见性 · {state}",
|
||||
"commands.toolInputsVisibility.description": "设置工具调用输入参数的默认可见性",
|
||||
"commands.toolInputsVisibility.keywords": "工具, 输入, 参数, 可见性, 隐藏, 显示, 展开, 折叠, tool, inputs, arguments, visibility, hide, show, expand, collapse",
|
||||
|
||||
"commands.tokenUsageDisplay.label": "Token 使用显示 · {state}",
|
||||
"commands.tokenUsageDisplay.description": "显示或隐藏助手消息的 token 和费用统计",
|
||||
"commands.tokenUsageDisplay.keywords": "token, usage, cost, stats, 令牌, 用量, 费用, 统计",
|
||||
|
||||
@@ -5,6 +5,14 @@ export const toolCallMessages = {
|
||||
"toolCall.header.copyTitle": "Copy tool call title",
|
||||
"toolCall.header.copyAriaLabel": "Copy tool call title",
|
||||
|
||||
"toolCall.header.showInputTitle": "Show Tool Arguments",
|
||||
"toolCall.header.showInputAriaLabel": "Show Tool Arguments",
|
||||
"toolCall.header.hideInputTitle": "Hide Tool Arguments",
|
||||
"toolCall.header.hideInputAriaLabel": "Hide Tool Arguments",
|
||||
|
||||
"toolCall.io.input": "Tool Input",
|
||||
"toolCall.io.output": "Tool Output",
|
||||
|
||||
"toolCall.diff.label": "Diff",
|
||||
"toolCall.diff.label.withPath": "Diff · {path}",
|
||||
"toolCall.diff.viewMode.ariaLabel": "Diff 视图模式",
|
||||
|
||||
@@ -52,6 +52,8 @@ const permissionSessionCounts = new Map<string, Map<string, number>>()
|
||||
const permissionWorktreeSlugByInstance = new Map<string, Map<string, string>>()
|
||||
|
||||
const [questionQueues, setQuestionQueues] = createSignal<Map<string, QuestionRequest[]>>(new Map())
|
||||
// Track which worktree a question was enqueued under (by question request id).
|
||||
const questionWorktreeSlugByInstance = new Map<string, Map<string, string>>()
|
||||
const [activeQuestionId, setActiveQuestionId] = createSignal<Map<string, string | null>>(new Map())
|
||||
const questionSessionCounts = new Map<string, Map<string, number>>()
|
||||
const questionEnqueuedAt = new Map<string, number>()
|
||||
@@ -877,6 +879,16 @@ function addQuestionToQueue(instanceId: string, request: QuestionRequest): void
|
||||
if (sessionId) {
|
||||
incrementQuestionSessionPendingCount(instanceId, sessionId)
|
||||
setSessionPendingQuestion(instanceId, sessionId, true)
|
||||
|
||||
// Record the worktree slug at the time the question is enqueued.
|
||||
// This is used to respond in the same worktree context even from the global permission center.
|
||||
const slug = getWorktreeSlugForSession(instanceId, sessionId)
|
||||
let byQuestionId = questionWorktreeSlugByInstance.get(instanceId)
|
||||
if (!byQuestionId) {
|
||||
byQuestionId = new Map()
|
||||
questionWorktreeSlugByInstance.set(instanceId, byQuestionId)
|
||||
}
|
||||
byQuestionId.set(request.id, slug)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -897,6 +909,7 @@ function removeQuestionFromQueue(instanceId: string, requestId: string): void {
|
||||
})
|
||||
|
||||
questionEnqueuedAt.delete(requestId)
|
||||
questionWorktreeSlugByInstance.get(instanceId)?.delete(requestId)
|
||||
recomputeActiveInterruption(instanceId)
|
||||
|
||||
if (removedSessionId) {
|
||||
@@ -909,6 +922,7 @@ function clearQuestionQueue(instanceId: string): void {
|
||||
for (const request of getQuestionQueue(instanceId)) {
|
||||
questionEnqueuedAt.delete(request.id)
|
||||
}
|
||||
questionWorktreeSlugByInstance.delete(instanceId)
|
||||
|
||||
setQuestionQueues((prev) => {
|
||||
const next = new Map(prev)
|
||||
@@ -934,7 +948,7 @@ function setActiveQuestionIdForInstance(instanceId: string, requestId: string):
|
||||
|
||||
async function sendQuestionReply(
|
||||
instanceId: string,
|
||||
_sessionId: string,
|
||||
sessionId: string,
|
||||
requestId: string,
|
||||
answers: string[][],
|
||||
): Promise<void> {
|
||||
@@ -944,8 +958,13 @@ async function sendQuestionReply(
|
||||
}
|
||||
|
||||
try {
|
||||
const stored = questionWorktreeSlugByInstance.get(instanceId)?.get(requestId)
|
||||
const fallback = sessionId ? getWorktreeSlugForSession(instanceId, sessionId) : "root"
|
||||
const worktreeSlug = stored ?? fallback
|
||||
const client = getOrCreateWorktreeClient(instanceId, worktreeSlug)
|
||||
|
||||
await requestData(
|
||||
instance.client.question.reply({
|
||||
client.question.reply({
|
||||
requestID: requestId,
|
||||
answers,
|
||||
}),
|
||||
@@ -959,15 +978,20 @@ async function sendQuestionReply(
|
||||
}
|
||||
}
|
||||
|
||||
async function sendQuestionReject(instanceId: string, _sessionId: string, requestId: string): Promise<void> {
|
||||
async function sendQuestionReject(instanceId: string, sessionId: string, requestId: string): Promise<void> {
|
||||
const instance = instances().get(instanceId)
|
||||
if (!instance?.client) {
|
||||
throw new Error("Instance not ready")
|
||||
}
|
||||
|
||||
try {
|
||||
const stored = questionWorktreeSlugByInstance.get(instanceId)?.get(requestId)
|
||||
const fallback = sessionId ? getWorktreeSlugForSession(instanceId, sessionId) : "root"
|
||||
const worktreeSlug = stored ?? fallback
|
||||
const client = getOrCreateWorktreeClient(instanceId, worktreeSlug)
|
||||
|
||||
await requestData(
|
||||
instance.client.question.reject({
|
||||
client.question.reject({
|
||||
requestID: requestId,
|
||||
}),
|
||||
"question.reject",
|
||||
|
||||
@@ -25,6 +25,7 @@ export interface ModelPreference {
|
||||
|
||||
export type DiffViewMode = "split" | "unified"
|
||||
export type ExpansionPreference = "expanded" | "collapsed"
|
||||
export type ToolInputsVisibilityPreference = "hidden" | "collapsed" | "expanded"
|
||||
export type ListeningMode = "local" | "all"
|
||||
|
||||
export interface UiSettings {
|
||||
@@ -37,6 +38,7 @@ export interface UiSettings {
|
||||
diffViewMode: DiffViewMode
|
||||
toolOutputExpansion: ExpansionPreference
|
||||
diagnosticsExpansion: ExpansionPreference
|
||||
toolInputsVisibility: ToolInputsVisibilityPreference
|
||||
showUsageMetrics: boolean
|
||||
autoCleanupBlankSessions: boolean
|
||||
|
||||
@@ -108,6 +110,7 @@ const defaultUiSettings: UiSettings = {
|
||||
diffViewMode: "split",
|
||||
toolOutputExpansion: "expanded",
|
||||
diagnosticsExpansion: "expanded",
|
||||
toolInputsVisibility: "collapsed",
|
||||
showUsageMetrics: true,
|
||||
autoCleanupBlankSessions: true,
|
||||
|
||||
@@ -130,6 +133,10 @@ function normalizeUiSettings(input?: Partial<UiSettings> | null): UiSettings {
|
||||
diffViewMode: sanitized.diffViewMode ?? defaultUiSettings.diffViewMode,
|
||||
toolOutputExpansion: sanitized.toolOutputExpansion ?? defaultUiSettings.toolOutputExpansion,
|
||||
diagnosticsExpansion: sanitized.diagnosticsExpansion ?? defaultUiSettings.diagnosticsExpansion,
|
||||
toolInputsVisibility:
|
||||
sanitized.toolInputsVisibility === "hidden" || sanitized.toolInputsVisibility === "collapsed" || sanitized.toolInputsVisibility === "expanded"
|
||||
? sanitized.toolInputsVisibility
|
||||
: defaultUiSettings.toolInputsVisibility,
|
||||
showUsageMetrics: sanitized.showUsageMetrics ?? defaultUiSettings.showUsageMetrics,
|
||||
autoCleanupBlankSessions: sanitized.autoCleanupBlankSessions ?? defaultUiSettings.autoCleanupBlankSessions,
|
||||
osNotificationsEnabled: sanitized.osNotificationsEnabled ?? defaultUiSettings.osNotificationsEnabled,
|
||||
@@ -439,6 +446,11 @@ function setDiagnosticsExpansion(mode: ExpansionPreference): void {
|
||||
updateUiSettings({ diagnosticsExpansion: mode })
|
||||
}
|
||||
|
||||
function setToolInputsVisibility(mode: ToolInputsVisibilityPreference): void {
|
||||
if (preferences().toolInputsVisibility === mode) return
|
||||
updateUiSettings({ toolInputsVisibility: mode })
|
||||
}
|
||||
|
||||
function setThinkingBlocksExpansion(mode: ExpansionPreference): void {
|
||||
if (preferences().thinkingBlocksExpansion === mode) return
|
||||
updateUiSettings({ thinkingBlocksExpansion: mode })
|
||||
@@ -536,6 +548,7 @@ interface ConfigContextValue {
|
||||
setToolOutputExpansion: typeof setToolOutputExpansion
|
||||
setDiagnosticsExpansion: typeof setDiagnosticsExpansion
|
||||
setThinkingBlocksExpansion: typeof setThinkingBlocksExpansion
|
||||
setToolInputsVisibility: typeof setToolInputsVisibility
|
||||
|
||||
// instance scoped
|
||||
setAgentModelPreference: typeof setAgentModelPreference
|
||||
@@ -579,6 +592,7 @@ const configContextValue: ConfigContextValue = {
|
||||
setToolOutputExpansion,
|
||||
setDiagnosticsExpansion,
|
||||
setThinkingBlocksExpansion,
|
||||
setToolInputsVisibility,
|
||||
setAgentModelPreference,
|
||||
getAgentModelPreference,
|
||||
}
|
||||
|
||||
@@ -526,6 +526,7 @@ async function fetchAgents(instanceId: string): Promise<void> {
|
||||
name: agent.name,
|
||||
description: agent.description || "",
|
||||
mode: agent.mode,
|
||||
hidden: agent.hidden,
|
||||
model: agent.model?.modelID
|
||||
? {
|
||||
providerId: agent.model.providerID || "",
|
||||
|
||||
@@ -87,6 +87,7 @@
|
||||
@apply flex items-stretch w-full;
|
||||
background-color: transparent;
|
||||
color: var(--text-primary);
|
||||
border-bottom: 1px solid var(--tool-call-border-color);
|
||||
}
|
||||
|
||||
.tool-call-header:hover {
|
||||
@@ -127,11 +128,30 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tool-call-header-input {
|
||||
@apply inline-flex items-center justify-center;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
color: var(--text-secondary);
|
||||
padding: 0 0.5rem;
|
||||
border-radius: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tool-call-header-copy:hover {
|
||||
background-color: transparent;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.tool-call-header-input:hover {
|
||||
background-color: transparent;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.tool-call-header-input[aria-pressed="true"] {
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.tool-call-header-status {
|
||||
@apply inline-flex items-center justify-center;
|
||||
font-size: 0.95rem;
|
||||
@@ -213,6 +233,63 @@
|
||||
font-size: var(--font-size-xs);
|
||||
}
|
||||
|
||||
|
||||
.tool-call-io-sections {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-xs);
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.tool-call-io-section {
|
||||
border: 1px solid var(--tool-call-border-color);
|
||||
overflow: hidden;
|
||||
background-color: transparent;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.tool-call-io-toggle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
gap: 0.75rem;
|
||||
padding: 0.5rem;
|
||||
background-color: var(--surface-secondary);
|
||||
border: none;
|
||||
border-bottom: 1px solid var(--tool-call-border-color);
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
font-size: 0.875rem;
|
||||
font-weight: normal;
|
||||
color: var(--text-primary);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tool-call-io-toggle::before {
|
||||
content: "▶";
|
||||
font-size: 11px;
|
||||
margin-right: 0.35rem;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.tool-call-io-toggle[aria-expanded="true"]::before {
|
||||
content: "▼";
|
||||
}
|
||||
|
||||
.tool-call-io-title {
|
||||
font-weight: inherit;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.tool-call-io-body {
|
||||
background-color: var(--surface-code);
|
||||
}
|
||||
|
||||
/* IO sections provide the outer frame; avoid double borders on markdown frames. */
|
||||
.tool-call-io-body .tool-call-markdown {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.tool-call-markdown {
|
||||
background-color: var(--surface-code);
|
||||
/* Keep a visible frame around the scroll viewport (not the content). */
|
||||
|
||||
@@ -68,6 +68,7 @@ export interface Agent {
|
||||
name: string
|
||||
description: string
|
||||
mode: string
|
||||
hidden?: boolean
|
||||
model?: {
|
||||
providerId: string
|
||||
modelId: string
|
||||
|
||||
Reference in New Issue
Block a user