Fix LLM validation and dashboard health hot paths

This commit is contained in:
2026-03-15 13:18:51 +03:00
parent 3928455189
commit a8563a8369
24 changed files with 1398 additions and 83 deletions

View File

@@ -142,10 +142,15 @@
togglingProviderIds = new Set(togglingProviderIds);
try {
await requestApi(`/llm/providers/${provider.id}`, "PUT", {
...provider,
const updatePayload = {
id: provider.id,
name: provider.name,
provider_type: provider.provider_type,
base_url: provider.base_url,
default_model: provider.default_model,
is_active: provider.is_active,
});
};
await requestApi(`/llm/providers/${provider.id}`, "PUT", updatePayload);
} catch (err) {
provider.is_active = previousState;
providers = [...providers];

View File

@@ -46,6 +46,15 @@ describe('ProviderConfig edit interaction contract', () => {
expect(source).toContain('await requestApi(`/llm/providers/${provider.id}`, "DELETE")');
expect(source).toContain('onclick={() => handleDelete(provider)}');
});
it('does not forward masked api_key when toggling provider activation', () => {
const source = fs.readFileSync(COMPONENT_PATH, 'utf-8');
expect(source).toContain('const updatePayload = {');
expect(source).toContain('provider_type: provider.provider_type');
expect(source).toContain('default_model: provider.default_model');
expect(source).not.toContain('await requestApi(`/llm/providers/${provider.id}`, "PUT", {\n ...provider,');
});
});
// [/DEF:provider_config_edit_contract_tests:Function]
// [/DEF:frontend.src.components.llm.__tests__.provider_config_integration:Module]

View File

@@ -27,7 +27,7 @@
* @TEST_FIXTURE init_state -> {"taskId": "task-1"}
* @TEST_INVARIANT correct_fetch -> verifies: [init_state]
*/
import { onDestroy, onMount } from "svelte";
import { onDestroy, onMount, untrack } from "svelte";
import { page } from "$app/state";
import { goto } from "$app/navigation";
import { api } from "$lib/api.js";
@@ -171,7 +171,10 @@
);
$effect(() => {
void loadScreenshotBlobUrls(screenshotPaths);
const paths = screenshotPaths;
untrack(() => {
void loadScreenshotBlobUrls(paths);
});
});
</script>

View File

@@ -0,0 +1,32 @@
// [DEF:frontend.src.routes.reports.llm.taskid.report_page_contract_test:Module]
// @TIER: STANDARD
// @SEMANTICS: llm-report, svelte-effect, screenshot-loading, regression-test
// @PURPOSE: Protect the LLM report page from self-triggering screenshot load effects.
// @LAYER: UI Tests
// @RELATION: VERIFIES -> frontend/src/routes/reports/llm/[taskId]/+page.svelte
import { describe, it, expect } from "vitest";
import fs from "node:fs";
import path from "node:path";
const PAGE_PATH = path.resolve(
process.cwd(),
"src/routes/reports/llm/[taskId]/+page.svelte",
);
// [DEF:llm_report_screenshot_effect_contract:Function]
// @TIER: STANDARD
// @PURPOSE: Ensure screenshot loading stays untracked from blob-url mutation state.
// @PRE: Report page source exists.
// @POST: Contract fails if screenshot loading effect can subscribe to screenshotBlobUrls updates.
describe("LLM report screenshot effect contract", () => {
it("uses untrack around screenshot blob loading side effect", () => {
const source = fs.readFileSync(PAGE_PATH, "utf-8");
expect(source).toContain('import { onDestroy, onMount, untrack } from "svelte";');
expect(source).toContain("untrack(() => {");
expect(source).toContain("void loadScreenshotBlobUrls(paths);");
});
});
// [/DEF:llm_report_screenshot_effect_contract:Function]
// [/DEF:frontend.src.routes.reports.llm.taskid.report_page_contract_test:Module]