diff --git a/src/agents/compaction.retry.test.ts b/src/agents/compaction.retry.test.ts index 31404e2e9b2..30f81ca6664 100644 --- a/src/agents/compaction.retry.test.ts +++ b/src/agents/compaction.retry.test.ts @@ -56,7 +56,7 @@ describe("compaction retry integration", () => { } as unknown as NonNullable; const invokeGenerateSummary = (signal = new AbortController().signal) => - mockGenerateSummary(testMessages, testModel, 1000, "test-api-key", signal); + mockGenerateSummary(testMessages, testModel, 1000, "test-api-key", undefined, signal); const runSummaryRetry = (options: Parameters[1]) => retryAsync(() => invokeGenerateSummary(), options); diff --git a/src/agents/compaction.ts b/src/agents/compaction.ts index a9ae165151f..b19f9bc92b1 100644 --- a/src/agents/compaction.ts +++ b/src/agents/compaction.ts @@ -257,6 +257,7 @@ async function summarizeChunks(params: { model, params.reserveTokens, params.apiKey, + params.headers, params.signal, effectiveInstructions, summary, @@ -283,6 +284,7 @@ export async function summarizeWithFallback(params: { messages: AgentMessage[]; model: NonNullable; apiKey: string; + headers?: Record; signal: AbortSignal; reserveTokens: number; maxChunkTokens: number; @@ -352,6 +354,7 @@ export async function summarizeInStages(params: { messages: AgentMessage[]; model: NonNullable; apiKey: string; + headers?: Record; signal: AbortSignal; reserveTokens: number; maxChunkTokens: number; diff --git a/src/agents/pi-extensions/compaction-safeguard.test.ts b/src/agents/pi-extensions/compaction-safeguard.test.ts index 2240d86d03f..6b3f253f543 100644 --- a/src/agents/pi-extensions/compaction-safeguard.test.ts +++ b/src/agents/pi-extensions/compaction-safeguard.test.ts @@ -131,13 +131,13 @@ const createCompactionEvent = (params: { messageText: string; tokensBefore: numb const createCompactionContext = (params: { sessionManager: ExtensionContext["sessionManager"]; - getApiKeyMock: ReturnType; + getApiKeyAndHeadersMock: ReturnType; }) => ({ model: undefined, sessionManager: params.sessionManager, modelRegistry: { - getApiKey: params.getApiKeyMock, + getApiKeyAndHeaders: params.getApiKeyAndHeadersMock, }, }) as unknown as Partial; @@ -147,10 +147,14 @@ async function runCompactionScenario(params: { apiKey: string | null; }) { const compactionHandler = createCompactionHandler(); - const getApiKeyMock = vi.fn().mockResolvedValue(params.apiKey); + const getApiKeyAndHeadersMock = vi + .fn() + .mockResolvedValue( + params.apiKey ? { ok: true, apiKey: params.apiKey } : { ok: false, error: "missing auth" }, + ); const mockContext = createCompactionContext({ sessionManager: params.sessionManager, - getApiKeyMock, + getApiKeyAndHeadersMock, }); const result = (await compactionHandler(params.event, mockContext)) as { cancel?: boolean; @@ -160,7 +164,7 @@ async function runCompactionScenario(params: { tokensBefore: number; }; }; - return { result, getApiKeyMock }; + return { result, getApiKeyAndHeadersMock }; } function expectCompactionResult(result: { @@ -1222,10 +1226,10 @@ describe("compaction-safeguard recent-turn preservation", () => { }); const compactionHandler = createCompactionHandler(); - const getApiKeyMock = vi.fn().mockResolvedValue("test-key"); + const getApiKeyAndHeadersMock = vi.fn().mockResolvedValue({ ok: true, apiKey: "test-key" }); const mockContext = createCompactionContext({ sessionManager, - getApiKeyMock, + getApiKeyAndHeadersMock, }); const messagesToSummarize: AgentMessage[] = Array.from({ length: 4 }, (_unused, index) => ({ role: "user", @@ -1278,10 +1282,10 @@ describe("compaction-safeguard recent-turn preservation", () => { }); const compactionHandler = createCompactionHandler(); - const getApiKeyMock = vi.fn().mockResolvedValue("test-key"); + const getApiKeyAndHeadersMock = vi.fn().mockResolvedValue({ ok: true, apiKey: "test-key" }); const mockContext = createCompactionContext({ sessionManager, - getApiKeyMock, + getApiKeyAndHeadersMock, }); const event = { preparation: { @@ -1343,10 +1347,10 @@ describe("compaction-safeguard recent-turn preservation", () => { }); const compactionHandler = createCompactionHandler(); - const getApiKeyMock = vi.fn().mockResolvedValue("test-key"); + const getApiKeyAndHeadersMock = vi.fn().mockResolvedValue({ ok: true, apiKey: "test-key" }); const mockContext = createCompactionContext({ sessionManager, - getApiKeyMock, + getApiKeyAndHeadersMock, }); const event = { preparation: { @@ -1446,10 +1450,10 @@ describe("compaction-safeguard recent-turn preservation", () => { }); const compactionHandler = createCompactionHandler(); - const getApiKeyMock = vi.fn().mockResolvedValue("test-key"); + const getApiKeyAndHeadersMock = vi.fn().mockResolvedValue({ ok: true, apiKey: "test-key" }); const mockContext = createCompactionContext({ sessionManager, - getApiKeyMock, + getApiKeyAndHeadersMock, }); const event = { preparation: { @@ -1509,10 +1513,10 @@ describe("compaction-safeguard recent-turn preservation", () => { }); const compactionHandler = createCompactionHandler(); - const getApiKeyMock = vi.fn().mockResolvedValue("test-key"); + const getApiKeyAndHeadersMock = vi.fn().mockResolvedValue({ ok: true, apiKey: "test-key" }); const mockContext = createCompactionContext({ sessionManager, - getApiKeyMock, + getApiKeyAndHeadersMock, }); const event = { preparation: { @@ -1572,10 +1576,10 @@ describe("compaction-safeguard recent-turn preservation", () => { }); const compactionHandler = createCompactionHandler(); - const getApiKeyMock = vi.fn().mockResolvedValue("test-key"); + const getApiKeyAndHeadersMock = vi.fn().mockResolvedValue({ ok: true, apiKey: "test-key" }); const mockContext = createCompactionContext({ sessionManager, - getApiKeyMock, + getApiKeyAndHeadersMock, }); const event = { preparation: { @@ -1634,7 +1638,7 @@ describe("compaction-safeguard extension model fallback", () => { messageText: "test message", tokensBefore: 1000, }); - const { result, getApiKeyMock } = await runCompactionScenario({ + const { result, getApiKeyAndHeadersMock } = await runCompactionScenario({ sessionManager, event: mockEvent, apiKey: null, @@ -1643,8 +1647,9 @@ describe("compaction-safeguard extension model fallback", () => { expect(result).toEqual({ cancel: true }); // KEY ASSERTION: Prove the fallback path was exercised - // The handler should have called getApiKey with runtime.model (via ctx.model ?? runtime?.model) - expect(getApiKeyMock).toHaveBeenCalledWith(model); + // The handler should have resolved request auth with runtime.model + // (via ctx.model ?? runtime?.model). + expect(getApiKeyAndHeadersMock).toHaveBeenCalledWith(model); // Verify runtime.model is still available (for completeness) const retrieved = getCompactionSafeguardRuntime(sessionManager); @@ -1660,7 +1665,7 @@ describe("compaction-safeguard extension model fallback", () => { messageText: "test", tokensBefore: 500, }); - const { result, getApiKeyMock } = await runCompactionScenario({ + const { result, getApiKeyAndHeadersMock } = await runCompactionScenario({ sessionManager, event: mockEvent, apiKey: null, @@ -1668,8 +1673,8 @@ describe("compaction-safeguard extension model fallback", () => { expect(result).toEqual({ cancel: true }); - // Verify early return: getApiKey should NOT have been called when both models are missing - expect(getApiKeyMock).not.toHaveBeenCalled(); + // Verify early return: request auth should NOT have been resolved when both models are missing. + expect(getApiKeyAndHeadersMock).not.toHaveBeenCalled(); }); }); @@ -1690,7 +1695,7 @@ describe("compaction-safeguard double-compaction guard", () => { customInstructions: "", signal: new AbortController().signal, }; - const { result, getApiKeyMock } = await runCompactionScenario({ + const { result, getApiKeyAndHeadersMock } = await runCompactionScenario({ sessionManager, event: mockEvent, apiKey: "sk-test", // pragma: allowlist secret @@ -1704,7 +1709,7 @@ describe("compaction-safeguard double-compaction guard", () => { expect(compaction.summary).toContain("## Open TODOs"); expect(compaction.firstKeptEntryId).toBe("entry-1"); expect(compaction.tokensBefore).toBe(1500); - expect(getApiKeyMock).not.toHaveBeenCalled(); + expect(getApiKeyAndHeadersMock).not.toHaveBeenCalled(); }); it("returns compaction result with structured fallback summary sections", async () => { @@ -1815,13 +1820,13 @@ describe("compaction-safeguard double-compaction guard", () => { messageText: "real message", tokensBefore: 1500, }); - const { result, getApiKeyMock } = await runCompactionScenario({ + const { result, getApiKeyAndHeadersMock } = await runCompactionScenario({ sessionManager, event: mockEvent, apiKey: null, }); expect(result).toEqual({ cancel: true }); - expect(getApiKeyMock).toHaveBeenCalled(); + expect(getApiKeyAndHeadersMock).toHaveBeenCalled(); }); it("treats tool results as real conversation only when linked to a meaningful user ask", async () => { diff --git a/src/agents/pi-extensions/compaction-safeguard.ts b/src/agents/pi-extensions/compaction-safeguard.ts index 3ac56c16462..61e5a2be0a6 100644 --- a/src/agents/pi-extensions/compaction-safeguard.ts +++ b/src/agents/pi-extensions/compaction-safeguard.ts @@ -614,11 +614,13 @@ export default function compactionSafeguardExtension(api: ExtensionAPI): void { return { cancel: true }; } - const apiKey = (await ctx.modelRegistry.getApiKey(model)) ?? ""; - const headers = + const fallbackHeaders = model.headers && typeof model.headers === "object" && !Array.isArray(model.headers) ? model.headers : undefined; + const requestAuth = await ctx.modelRegistry.getApiKeyAndHeaders(model); + const apiKey = requestAuth.ok ? (requestAuth.apiKey ?? "") : ""; + const headers = requestAuth.ok ? (requestAuth.headers ?? fallbackHeaders) : fallbackHeaders; if (!apiKey && !headers) { log.warn( "Compaction safeguard: no request auth available; cancelling compaction to preserve history.", @@ -692,6 +694,7 @@ export default function compactionSafeguardExtension(api: ExtensionAPI): void { messages: pruned.droppedMessagesList, model, apiKey, + headers, signal, reserveTokens: Math.max(1, Math.floor(preparation.settings.reserveTokens)), maxChunkTokens: droppedMaxChunkTokens, @@ -763,6 +766,7 @@ export default function compactionSafeguardExtension(api: ExtensionAPI): void { messages: messagesToSummarize, model, apiKey, + headers, signal, reserveTokens, maxChunkTokens, @@ -779,6 +783,7 @@ export default function compactionSafeguardExtension(api: ExtensionAPI): void { messages: turnPrefixMessages, model, apiKey, + headers, signal, reserveTokens, maxChunkTokens, diff --git a/src/agents/skills-install.download.test.ts b/src/agents/skills-install.download.test.ts index bd8559b60fe..49d20867fd1 100644 --- a/src/agents/skills-install.download.test.ts +++ b/src/agents/skills-install.download.test.ts @@ -60,7 +60,13 @@ function buildEntry(name: string): SkillEntry { description: `${name} test skill`, filePath: path.join(skillDir, "SKILL.md"), baseDir: skillDir, - source: "openclaw-workspace", + sourceInfo: { + path: path.join(skillDir, "SKILL.md"), + source: "openclaw-workspace", + scope: "project", + origin: "top-level", + baseDir: skillDir, + }, disableModelInvocation: false, }, frontmatter: {}, diff --git a/src/agents/skills-install.ts b/src/agents/skills-install.ts index ef6c334d0b6..8d38fda36c6 100644 --- a/src/agents/skills-install.ts +++ b/src/agents/skills-install.ts @@ -444,9 +444,10 @@ export async function installSkill(params: SkillInstallRequest): Promise { description: "test", filePath: "/tmp/os-scoped", baseDir: "/tmp", - source: "test", + sourceInfo: { + path: "/tmp/os-scoped", + source: "test", + scope: "project", + origin: "top-level", + baseDir: "/tmp", + }, disableModelInvocation: false, }, frontmatter: {}, diff --git a/src/agents/skills-status.ts b/src/agents/skills-status.ts index 02ff68e2efc..d9b52a1dac3 100644 --- a/src/agents/skills-status.ts +++ b/src/agents/skills-status.ts @@ -186,10 +186,11 @@ function buildSkillStatus( (skillConfig?.apiKey && entry.metadata?.primaryEnv === envName), ); const isConfigSatisfied = (pathStr: string) => isConfigPathTruthy(config, pathStr); + const skillSource = entry.skill.sourceInfo.source; const bundled = bundledNames && bundledNames.size > 0 ? bundledNames.has(entry.skill.name) - : entry.skill.source === "openclaw-bundled"; + : skillSource === "openclaw-bundled"; const { emoji, homepage, required, missing, requirementsSatisfied, configChecks } = evaluateEntryRequirementsForCurrentPlatform({ @@ -205,7 +206,7 @@ function buildSkillStatus( return { name: entry.skill.name, description: entry.skill.description, - source: entry.skill.source, + source: skillSource, bundled, filePath: entry.skill.filePath, baseDir: entry.skill.baseDir, diff --git a/src/agents/skills.buildworkspaceskillstatus.test.ts b/src/agents/skills.buildworkspaceskillstatus.test.ts index 4b3cca8808f..eb6e40ad279 100644 --- a/src/agents/skills.buildworkspaceskillstatus.test.ts +++ b/src/agents/skills.buildworkspaceskillstatus.test.ts @@ -24,7 +24,13 @@ function makeEntry(params: { description: `desc:${params.name}`, filePath: `/tmp/${params.name}/SKILL.md`, baseDir: `/tmp/${params.name}`, - source: params.source ?? "openclaw-workspace", + sourceInfo: { + path: `/tmp/${params.name}/SKILL.md`, + source: params.source ?? "openclaw-workspace", + scope: "project", + origin: "top-level", + baseDir: `/tmp/${params.name}`, + }, disableModelInvocation: false, }, frontmatter: {}, diff --git a/src/agents/skills.resolveskillspromptforrun.test.ts b/src/agents/skills.resolveskillspromptforrun.test.ts index 305e11f2f4e..d8cc67c461e 100644 --- a/src/agents/skills.resolveskillspromptforrun.test.ts +++ b/src/agents/skills.resolveskillspromptforrun.test.ts @@ -17,7 +17,13 @@ describe("resolveSkillsPromptForRun", () => { description: "Demo", filePath: "/app/skills/demo-skill/SKILL.md", baseDir: "/app/skills/demo-skill", - source: "openclaw-bundled", + sourceInfo: { + path: "/app/skills/demo-skill/SKILL.md", + source: "openclaw-bundled", + scope: "project", + origin: "top-level", + baseDir: "/app/skills/demo-skill", + }, disableModelInvocation: false, }, frontmatter: {}, diff --git a/src/agents/skills/compact-format.test.ts b/src/agents/skills/compact-format.test.ts index 20f3b8a256e..aa85779e94b 100644 --- a/src/agents/skills/compact-format.test.ts +++ b/src/agents/skills/compact-format.test.ts @@ -14,7 +14,13 @@ function makeSkill(name: string, desc = "A skill", filePath = `/skills/${name}/S description: desc, filePath, baseDir: `/skills/${name}`, - source: "workspace", + sourceInfo: { + path: filePath, + source: "workspace", + scope: "project", + origin: "top-level", + baseDir: `/skills/${name}`, + }, disableModelInvocation: false, }; } diff --git a/src/agents/skills/config.ts b/src/agents/skills/config.ts index 2dfe78acd5c..cf25b6fc50e 100644 --- a/src/agents/skills/config.ts +++ b/src/agents/skills/config.ts @@ -50,7 +50,7 @@ function normalizeAllowlist(input: unknown): string[] | undefined { const BUNDLED_SOURCES = new Set(["openclaw-bundled"]); function isBundledSkill(entry: SkillEntry): boolean { - return BUNDLED_SOURCES.has(entry.skill.source); + return BUNDLED_SOURCES.has(entry.skill.sourceInfo.source); } export function resolveBundledAllowlist(config?: OpenClawConfig): string[] | undefined { diff --git a/src/cli/skills-cli.formatting.test.ts b/src/cli/skills-cli.formatting.test.ts index 19d4ba0b2ed..57f6d3a50c6 100644 --- a/src/cli/skills-cli.formatting.test.ts +++ b/src/cli/skills-cli.formatting.test.ts @@ -38,7 +38,13 @@ describe("skills-cli (e2e)", () => { description: "Capture UI screenshots", filePath: path.join(baseDir, "SKILL.md"), baseDir, - source: "openclaw-bundled", + sourceInfo: { + path: path.join(baseDir, "SKILL.md"), + source: "openclaw-bundled", + scope: "project", + origin: "top-level", + baseDir, + }, disableModelInvocation: false, } as SkillEntry["skill"], frontmatter: {}, diff --git a/src/security/audit-extra.async.ts b/src/security/audit-extra.async.ts index 5e9c4036e09..55765b717ce 100644 --- a/src/security/audit-extra.async.ts +++ b/src/security/audit-extra.async.ts @@ -1261,7 +1261,7 @@ export async function collectInstalledSkillsCodeSafetyFindings(params: { for (const workspaceDir of workspaceDirs) { const entries = loadWorkspaceSkillEntries(workspaceDir, { config: params.cfg }); for (const entry of entries) { - if (entry.skill.source === "openclaw-bundled") { + if (entry.skill.sourceInfo.source === "openclaw-bundled") { continue; } diff --git a/ui/src/ui/app-render.helpers.ts b/ui/src/ui/app-render.helpers.ts index e0a097210fa..e85913dd46d 100644 --- a/ui/src/ui/app-render.helpers.ts +++ b/ui/src/ui/app-render.helpers.ts @@ -109,9 +109,8 @@ function renderCronFilterIcon(hiddenCount: number) { - ${ - hiddenCount > 0 - ? html` 0 + ? html`${hiddenCount}` - : "" - } + : ""} `; } @@ -313,13 +311,11 @@ export function renderChatControls(state: AppViewState) { state.sessionsHideCron = !hideCron; }} aria-pressed=${hideCron} - title=${ - hideCron - ? hiddenCronCount > 0 - ? t("chat.showCronSessionsHidden", { count: String(hiddenCronCount) }) - : t("chat.showCronSessions") - : t("chat.hideCronSessions") - } + title=${hideCron + ? hiddenCronCount > 0 + ? t("chat.showCronSessionsHidden", { count: String(hiddenCronCount) }) + : t("chat.showCronSessions") + : t("chat.hideCronSessions")} > ${renderCronFilterIcon(hiddenCronCount)} @@ -945,9 +941,9 @@ export function renderTopbarThemeModeToggle(state: AppViewState) { (opt) => html` ` - : nothing - } + : nothing}
- ${ - state.updateAvailable && - state.updateAvailable.latestVersion !== state.updateAvailable.currentVersion && - !isUpdateBannerDismissed(state.updateAvailable) - ? html`
${renderExecApprovalPrompt(state)} ${renderGatewayUrlConfirmation(state)} ${nothing} diff --git a/ui/src/ui/chat/grouped-render.ts b/ui/src/ui/chat/grouped-render.ts index d9a9edfb7e3..3dc1187ff86 100644 --- a/ui/src/ui/chat/grouped-render.ts +++ b/ui/src/ui/chat/grouped-render.ts @@ -177,11 +177,9 @@ export function renderMessageGroup( ${timestamp} ${renderMessageMeta(meta)} ${normalizedRole === "assistant" && isTtsSupported() ? renderTtsButton(group) : nothing} - ${ - opts.onDelete - ? renderDeleteButton(opts.onDelete, normalizedRole === "user" ? "left" : "right") - : nothing - } + ${opts.onDelete + ? renderDeleteButton(opts.onDelete, normalizedRole === "user" ? "left" : "right") + : nothing} @@ -697,84 +695,70 @@ function renderGroupedMessage( return html`
- ${ - hasActions - ? html`
+ ${hasActions + ? html`
${canExpand ? renderExpandButton(markdown!, onOpenSidebar!) : nothing} ${canCopyMarkdown ? renderCopyAsMarkdownButton(markdown!) : nothing}
` - : nothing - } - ${ - isToolMessage - ? html` + : nothing} + ${isToolMessage + ? html`
${icons.zap} Tool output - ${ - toolSummaryLabel - ? html`${toolSummaryLabel}` - : toolPreview - ? html`${toolPreview}` - : nothing - } + ${toolSummaryLabel + ? html`${toolSummaryLabel}` + : toolPreview + ? html`${toolPreview}` + : nothing}
${renderMessageImages(images)} - ${ - reasoningMarkdown - ? html`
+ ${reasoningMarkdown + ? html`
${unsafeHTML(toSanitizedMarkdownHtml(reasoningMarkdown))}
` - : nothing - } - ${ - jsonResult - ? html`
+ : nothing} + ${jsonResult + ? html`
JSON ${jsonSummaryLabel(jsonResult.parsed)}
${jsonResult.pretty}
` - : markdown - ? html`
+ : markdown + ? html`
${unsafeHTML(toSanitizedMarkdownHtml(markdown))}
` - : nothing - } + : nothing} ${hasToolCards ? renderCollapsedToolCards(toolCards, onOpenSidebar) : nothing}
` - : html` + : html` ${renderMessageImages(images)} - ${ - reasoningMarkdown - ? html`
+ ${reasoningMarkdown + ? html`
${unsafeHTML(toSanitizedMarkdownHtml(reasoningMarkdown))}
` - : nothing - } - ${ - jsonResult - ? html`
+ : nothing} + ${jsonResult + ? html`
JSON ${jsonSummaryLabel(jsonResult.parsed)}
${jsonResult.pretty}
` - : markdown - ? html`
+ : markdown + ? html`
${unsafeHTML(toSanitizedMarkdownHtml(markdown))}
` - : nothing - } + : nothing} ${hasToolCards ? renderCollapsedToolCards(toolCards, onOpenSidebar) : nothing} - ` - } + `}
`; } diff --git a/ui/src/ui/chat/tool-cards.ts b/ui/src/ui/chat/tool-cards.ts index 0a5d85542ca..2e79283fe88 100644 --- a/ui/src/ui/chat/tool-cards.ts +++ b/ui/src/ui/chat/tool-cards.ts @@ -81,49 +81,35 @@ export function renderToolCardSidebar(card: ToolCard, onOpenSidebar?: (content: @click=${handleClick} role=${canClick ? "button" : nothing} tabindex=${canClick ? "0" : nothing} - @keydown=${ - canClick - ? (e: KeyboardEvent) => { - if (e.key !== "Enter" && e.key !== " ") { - return; - } - e.preventDefault(); - handleClick?.(); + @keydown=${canClick + ? (e: KeyboardEvent) => { + if (e.key !== "Enter" && e.key !== " ") { + return; } - : nothing - } + e.preventDefault(); + handleClick?.(); + } + : nothing} >
${icons[display.icon]} ${display.label}
- ${ - canClick - ? html`${hasText ? "View" : ""} ${icons.check}` - : nothing - } - ${ - isEmpty && !canClick - ? html`${icons.check}` - : nothing - } + : nothing} + ${isEmpty && !canClick + ? html`${icons.check}` + : nothing}
${detail ? html`
${detail}
` : nothing} - ${ - isEmpty - ? html` -
Completed
- ` - : nothing - } - ${ - showCollapsed - ? html`
${getTruncatedPreview(card.text!)}
` - : nothing - } + ${isEmpty ? html`
Completed
` : nothing} + ${showCollapsed + ? html`
${getTruncatedPreview(card.text!)}
` + : nothing} ${showInline ? html`
${card.text}
` : nothing}
`; diff --git a/ui/src/ui/icons.ts b/ui/src/ui/icons.ts index 9cba6e36ef1..4c10abc1f6c 100644 --- a/ui/src/ui/icons.ts +++ b/ui/src/ui/icons.ts @@ -121,9 +121,7 @@ export const icons = { `, - check: html` - - `, + check: html` `, arrowDown: html` @@ -144,8 +142,12 @@ export const icons = { `, brain: html` - - + + @@ -236,9 +238,7 @@ export const icons = { `, - circle: html` - - `, + circle: html` `, puzzle: html` `, - stop: html` - - `, + stop: html` `, pin: html` diff --git a/ui/src/ui/views/agents-panels-overview.ts b/ui/src/ui/views/agents-panels-overview.ts index 2dafff0d28e..eefb35e2bcf 100644 --- a/ui/src/ui/views/agents-panels-overview.ts +++ b/ui/src/ui/views/agents-panels-overview.ts @@ -115,13 +115,13 @@ export function renderAgentOverview(params: {
- ${ - configDirty - ? html` -
You have unsaved config changes.
- ` - : nothing - } + ${configDirty + ? html` +
+ You have unsaved config changes. +
+ ` + : nothing}
Model Selection
@@ -134,17 +134,13 @@ export function renderAgentOverview(params: { @change=${(e: Event) => onModelChange(agent.id, (e.target as HTMLSelectElement).value || null)} > - ${ - isDefault - ? html` - - ` - : html` + ${isDefault + ? html` ` + : html` - ` - } + `} ${buildModelOptions(configForm, effectivePrimary ?? undefined, params.modelCatalog)} diff --git a/ui/src/ui/views/agents-panels-status-files.ts b/ui/src/ui/views/agents-panels-status-files.ts index 02f660171b2..634f1a753d4 100644 --- a/ui/src/ui/views/agents-panels-status-files.ts +++ b/ui/src/ui/views/agents-panels-status-files.ts @@ -179,24 +179,19 @@ export function renderAgentChannels(params: {
Last refresh: ${lastSuccessLabel}
- ${ - params.error - ? html`
${params.error}
` - : nothing - } - ${ - !params.snapshot - ? html` -
Load channels to see live status.
- ` - : nothing - } - ${ - entries.length === 0 - ? html` -
No channels found.
- ` - : html` + ${params.error + ? html`
${params.error}
` + : nothing} + ${!params.snapshot + ? html` +
+ Load channels to see live status. +
+ ` + : nothing} + ${entries.length === 0 + ? html`
No channels found.
` + : html`
${entries.map((entry) => { const summary = summarizeChannelAccounts(entry.accounts); @@ -222,33 +217,28 @@ export function renderAgentChannels(params: {
${status}
${configLabel}
${enabled}
- ${ - summary.configured === 0 - ? html` - - ` - : nothing - } - ${ - extras.length > 0 - ? extras.map((extra) => html`
${extra.label}: ${extra.value}
`) - : nothing - } + ${summary.configured === 0 + ? html` + + ` + : nothing} + ${extras.length > 0 + ? extras.map((extra) => html`
${extra.label}: ${extra.value}
`) + : nothing}
`; })}
- ` - } + `} `; @@ -299,33 +289,26 @@ export function renderAgentCron(params: {
${formatNextRun(params.status?.nextWakeAtMs ?? null)}
- ${ - params.error - ? html`
${params.error}
` - : nothing - } + ${params.error + ? html`
${params.error}
` + : nothing}
Agent Cron Jobs
Scheduled jobs targeting this agent.
- ${ - jobs.length === 0 - ? html` -
No jobs assigned.
- ` - : html` + ${jobs.length === 0 + ? html`
No jobs assigned.
` + : html`
${jobs.map( (job) => html`
${job.name}
- ${ - job.description - ? html`
${job.description}
` - : nothing - } + ${job.description + ? html`
${job.description}
` + : nothing}
${formatCronSchedule(job)} @@ -350,8 +333,7 @@ export function renderAgentCron(params: { `, )}
- ` - } + `}
`; } @@ -394,60 +376,46 @@ export function renderAgentFiles(params: { ${params.agentFilesLoading ? "Loading…" : "Refresh"} - ${ - list - ? html`
+ ${list + ? html`
Workspace: ${list.workspace}
` - : nothing - } - ${ - params.agentFilesError - ? html`
+ : nothing} + ${params.agentFilesError + ? html`
${params.agentFilesError}
` - : nothing - } - ${ - !list - ? html` -
- Load the agent workspace files to edit core instructions. -
- ` - : files.length === 0 - ? html` -
No files found.
- ` - : html` + : nothing} + ${!list + ? html` +
+ Load the agent workspace files to edit core instructions. +
+ ` + : files.length === 0 + ? html`
No files found.
` + : html`
${files.map((file) => { const isActive = active === file.name; const label = file.name.replace(/\.md$/i, ""); return html` `; })}
- ${ - !activeEntry - ? html` -
Select a file to edit.
- ` - : html` + ${!activeEntry + ? html`
Select a file to edit.
` + : html`
${activeEntry.path}
@@ -482,15 +450,13 @@ export function renderAgentFiles(params: {
- ${ - activeEntry.missing - ? html` -
- This file is missing. Saving will create it in the agent workspace. -
- ` - : nothing - } + ${activeEntry.missing + ? html` +
+ This file is missing. Saving will create it in the agent workspace. +
+ ` + : nothing}
`; @@ -130,9 +128,8 @@ export function renderNostrCard(params: { style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;" >
Profile
- ${ - summaryConfigured - ? html` + ${summaryConfigured + ? html` - ${ - vs.pinnedExpanded - ? html` + ${vs.pinnedExpanded + ? html`
${entries.map( ({ index, text, role }) => html` @@ -771,8 +768,7 @@ function renderPinnedSection( )}
` - : nothing - } + : nothing} `; } @@ -805,11 +801,9 @@ function renderSlashMenu( requestUpdate(); }} > - ${ - vs.slashMenuCommand?.icon - ? html`${icons[vs.slashMenuCommand.icon]}` - : nothing - } + ${vs.slashMenuCommand?.icon + ? html`${icons[vs.slashMenuCommand.icon]}` + : nothing} ${arg} /${vs.slashMenuCommand?.name} ${arg} @@ -851,9 +845,9 @@ function renderSlashMenu( ${entries.map( ({ cmd, globalIdx }) => html`
selectSlashCommand(cmd, props, requestUpdate)} @@ -866,15 +860,11 @@ function renderSlashMenu( /${cmd.name} ${cmd.args ? html`${cmd.args}` : nothing} ${cmd.description} - ${ - cmd.argOptions?.length - ? html`${cmd.argOptions.length} options` - : cmd.executeLocal && !cmd.args - ? html` - instant - ` - : nothing - } + ${cmd.argOptions?.length + ? html`${cmd.argOptions.length} options` + : cmd.executeLocal && !cmd.args + ? html` instant ` + : nothing}
`, )} @@ -954,46 +944,49 @@ export function renderChat(props: ChatProps) { @click=${handleCodeBlockCopy} >
- ${ - props.loading - ? html` -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ ${props.loading + ? html` +
+
+
+
+
+
+
- ` - : nothing - } +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ` + : nothing} ${isEmpty && !vs.searchOpen ? renderWelcomeState(props) : nothing} - ${ - isEmpty && vs.searchOpen - ? html` -
No matching messages
- ` - : nothing - } + ${isEmpty && vs.searchOpen + ? html`
No matching messages
` + : nothing} ${repeat( chatItems, (item) => item.key, @@ -1171,9 +1164,8 @@ export function renderChat(props: ChatProps) { > ${props.disabledReason ? html`
${props.disabledReason}
` : nothing} ${props.error ? html`
${props.error}
` : nothing} - ${ - props.focusMode - ? html` + ${props.focusMode + ? html`
` - : nothing - } + : nothing}
- ${ - props.queue.length - ? html` + ${props.queue.length + ? html`
Queued (${props.queue.length})
@@ -1231,10 +1219,8 @@ export function renderChat(props: ChatProps) { (item) => html`
- ${ - item.text || - (item.attachments?.length ? `Image (${item.attachments.length})` : "") - } + ${item.text || + (item.attachments?.length ? `Image (${item.attachments.length})` : "")}
` - : nothing - } + : nothing} ${renderFallbackIndicator(props.fallbackStatus)} ${renderCompactionIndicator(props.compactionStatus)} ${renderContextNotice(activeSession, props.sessions?.defaults?.contextTokens ?? null)} - ${ - props.showNewMessages - ? html` + ${props.showNewMessages + ? html` ` - : nothing - } + : nothing}
@@ -1277,11 +1260,9 @@ export function renderChat(props: ChatProps) { @change=${(e: Event) => handleFileSelect(e, props)} /> - ${ - vs.sttRecording && vs.sttInterimText - ? html`
${vs.sttInterimText}
` - : nothing - } + ${vs.sttRecording && vs.sttInterimText + ? html`
${vs.sttInterimText}
` + : nothing} - ` - } + `}
`; - })() - } + })()}
- ${ - props.issues.length > 0 - ? html`
+ ${props.issues.length > 0 + ? html`
${JSON.stringify(props.issues, null, 2)}
` - : nothing - } + : nothing}
`; diff --git a/ui/src/ui/views/cron.ts b/ui/src/ui/views/cron.ts index b6632b35667..3d19cdb6d64 100644 --- a/ui/src/ui/views/cron.ts +++ b/ui/src/ui/views/cron.ts @@ -341,14 +341,12 @@ function focusFormField(id: string) { function renderFieldLabel(text: string, required = false) { return html` ${text} - ${ - required - ? html` + ${required + ? html` ${t("cron.form.requiredSr")} ` - : nothing - } + : nothing} `; } @@ -402,13 +400,11 @@ export function renderCron(props: CronProps) {
${t("cron.summary.enabled")}
- ${ - props.status - ? props.status.enabled - ? t("cron.summary.yes") - : t("cron.summary.no") - : t("common.na") - } + ${props.status + ? props.status.enabled + ? t("cron.summary.yes") + : t("cron.summary.no") + : t("common.na")}
@@ -547,18 +543,15 @@ export function renderCron(props: CronProps) {
- ${ - props.jobs.length === 0 - ? html`
${t("cron.jobs.noMatching")}
` - : html` + ${props.jobs.length === 0 + ? html`
${t("cron.jobs.noMatching")}
` + : html`
${props.jobs.map((job) => renderJob(job, props))}
- ` - } - ${ - props.jobsHasMore - ? html` + `} + ${props.jobsHasMore + ? html`
` - : nothing - } + : nothing}
@@ -581,11 +573,9 @@ export function renderCron(props: CronProps) {
${t("cron.runs.title")}
- ${ - props.runsScope === "all" - ? t("cron.runs.subtitleAll") - : t("cron.runs.subtitleJob", { title: selectedRunTitle }) - } + ${props.runsScope === "all" + ? t("cron.runs.subtitleAll") + : t("cron.runs.subtitleJob", { title: selectedRunTitle })}
@@ -676,24 +666,21 @@ export function renderCron(props: CronProps) { })}
- ${ - props.runsScope === "job" && props.runsJobId == null - ? html` + ${props.runsScope === "job" && props.runsJobId == null + ? html`
${t("cron.runs.selectJobHint")}
` - : runs.length === 0 - ? html` + : runs.length === 0 + ? html`
${t("cron.runs.noMatching")}
` - : html` + : html`
${runs.map((entry) => renderRun(entry, props.basePath, props.onNavigateToChat))}
- ` - } - ${ - (props.runsScope === "all" || props.runsJobId != null) && props.runsHasMore - ? html` + `} + ${(props.runsScope === "all" || props.runsJobId != null) && props.runsHasMore + ? html`
` - : nothing - } + : nothing} @@ -847,16 +833,13 @@ export function renderCron(props: CronProps) {
- ${ - props.form.payloadKind === "systemEvent" - ? t("cron.form.systemEventHelp") - : t("cron.form.agentTurnHelp") - } + ${props.form.payloadKind === "systemEvent" + ? t("cron.form.systemEventHelp") + : t("cron.form.agentTurnHelp")}
- ${ - isAgentTurn - ? html` + ${isAgentTurn + ? html` - ${ - isCronSchedule - ? html` + ${isCronSchedule + ? html` - ${ - isTrustedProxy - ? "" - : html` + ${isTrustedProxy + ? "" + : html` - ` - } + `}