style: format assistant custom widget files

This commit is contained in:
ajnart committed 2026-08-30 23:06:58 +02:00
1 parent 288bbcff98
commit 135cd928ba
10 files changed
+33 -28

No files matched your search

@@ -28,7 +28,14 @@ The object key `default` is the required source ID; `default` is not a property
"requests": {
"summary": { "path": "/summary" },
"search": { "trigger": "manual", "path": "/search", "query": { "q": { "$param": "query" } } },
"create": { "kind": "action", "method": "POST", "path": "/items", "body": { "id": { "$param": "id" } }, "confirmation": "Create this item?", "invalidates": ["search"] }
"create": {
"kind": "action",
"method": "POST",
"path": "/items",
"body": { "id": { "$param": "id" } },
"confirmation": "Create this item?",
"invalidates": ["search"]
}
}
}
```
@@ -76,7 +76,11 @@ describe("repairAssistantToolInput", () => {
});
test.each([
["customWidget_previewQuery", { previewId: "preview-1", requestId: "search" }, { sessionId: "preview-1", requestId: "search" }],
[
"customWidget_previewQuery",
{ previewId: "preview-1", requestId: "search" },
{ sessionId: "preview-1", requestId: "search" },
],
[
"customWidget_previewAction",
{ previewSessionId: "preview-1", requestId: "requestMovie", params: { mediaId: 603 } },
@@ -125,10 +125,7 @@ const repairCustomWidgetLifecycleInput = <T extends AssistantToolCallInput>(tool
return null;
}
if (typeof input !== "object" || input === null || Array.isArray(input)) return null;
const normalized = normalizeCustomWidgetLifecycleToolInput(
toolCall.toolName,
input as Record<string, unknown>,
);
const normalized = normalizeCustomWidgetLifecycleToolInput(toolCall.toolName, input as Record<string, unknown>);
if (normalized === input) return null;
return { ...toolCall, input: JSON.stringify(normalized) };
};
@@ -101,12 +101,8 @@ export const createPreviewSession = (input: CreatePreviewSessionInput) => call((
export const getPreviewSession = (id: string, userId: string) => call(() => getService().get(id, userId));
export const setPreviewSessionLiveActions = (id: string, userId: string, enabled: boolean) =>
call(() => getService().setLiveActions(id, userId, enabled));
export const revisePreviewSessionTemplate = (
id: string,
userId: string,
template: string,
expectedRevision?: number,
) => call(() => getService().reviseTemplate(id, userId, template, expectedRevision));
export const revisePreviewSessionTemplate = (id: string, userId: string, template: string, expectedRevision?: number) =>
call(() => getService().reviseTemplate(id, userId, template, expectedRevision));
export const appendPreviewJournal = (
session: CustomWidgetPreviewSession,
entry: Omit<CustomWidgetPreviewJournalEntry, "id" | "sessionRevision" | "timestamp">,
@@ -110,7 +110,7 @@ describe("custom widget agent preview workflow", () => {
},
secrets: [],
});
const revisedTemplate = '<Stack><Text>{data.fixtures?.name}</Text><Badge>Ready</Badge></Stack>';
const revisedTemplate = "<Stack><Text>{data.fixtures?.name}</Text><Badge>Ready</Badge></Stack>";
const revised = await caller.previewReviseTemplate({
sessionId: preview.previewSession.id,
@@ -30,8 +30,7 @@ const harmlessCredentialSettings = new Set([
const commonCredentialLiteralPattern =
/\b(?:sk|pk|rk)-(?:[A-Za-z0-9][A-Za-z0-9._-]{7,})\b|\b(?:sk_(?:live|test)|github_pat|glpat|gh[pousr]|hf_|xox[baprs])-?[A-Za-z0-9._-]{8,}\b|\b(?:AKIA|ASIA)[A-Z0-9]{16}\b|\bAIza[0-9A-Za-z_-]{20,}\b|\beyJ[A-Za-z0-9_-]{8,}\.eyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/giu;
const authorizationSchemePattern =
/(^|[^A-Za-z0-9_-])(bearer|basic)([\s:_-]+)(["']?)([A-Za-z0-9._~+/%=-]{8,})/giu;
const authorizationSchemePattern = /(^|[^A-Za-z0-9_-])(bearer|basic)([\s:_-]+)(["']?)([A-Za-z0-9._~+/%=-]{8,})/giu;
const credentialAssignmentPattern =
/\b(authorization|auth(?:entication)?(?:[ _-]?(?:tokens?|keys?|credentials?))?|credentials?|api[ _-]?keys?|passwords?|passwds?|secrets?|tokens?|access[ _-]?(?:tokens?|keys?)|refresh[ _-]?tokens?|client[ _-]?secrets?|private[ _-]?keys?|signing[ _-]?keys?)((?:["']?\s*[:=]\s*["']?))([^\s,;"'}<>]+)/giu;
@@ -19,9 +19,7 @@ export function getScopedCustomJsxControlName(scopeId: string, name: string) {
export function getInvalidCustomJsxPropValueReason(componentName: string, propName: string, value: unknown) {
if (propName === "resetKey" && value !== null) {
const scalar =
typeof value === "string" ||
typeof value === "boolean" ||
(typeof value === "number" && Number.isFinite(value));
typeof value === "string" || typeof value === "boolean" || (typeof value === "number" && Number.isFinite(value));
if (!scalar) return "resetKey supports only a finite number, string, boolean, or null";
}
if (
@@ -14,7 +14,13 @@ export interface RefreshButtonProps {
size?: string;
}
export function RefreshButton({ requestId, label, color = "gray", variant = "subtle", size = "sm" }: RefreshButtonProps) {
export function RefreshButton({
requestId,
label,
color = "gray",
variant = "subtle",
size = "sm",
}: RefreshButtonProps) {
const runtime = useCustomWidgetRuntime();
const [loading, setLoading] = useState(false);
const refresh = async () => {
@@ -228,7 +228,7 @@ describe("preview sessions", () => {
const revised = await service.reviseTemplate(
"session",
"owner",
'<Stack><Text>{data.data?.name}</Text><Badge>Ready</Badge></Stack>',
"<Stack><Text>{data.data?.name}</Text><Badge>Ready</Badge></Stack>",
0,
);
const session = await service.get("session", "owner");
@@ -238,13 +238,11 @@ describe("preview sessions", () => {
expect(session.sources).toEqual(original.sources);
expect(session.requests).toEqual(original.requests);
expect(session.optionDefinitions).toEqual(original.optionDefinitions);
expect(await service.getJournal("session", "owner")).toEqual([
expect.objectContaining({ sessionRevision: 0 }),
]);
expect(await service.getJournal("session", "owner")).toEqual([expect.objectContaining({ sessionRevision: 0 })]);
await expect(service.reviseTemplate("session", "owner", session.template, 1)).rejects.toThrow("unchanged");
await expect(
service.reviseTemplate("session", "owner", "<Text>Stale edit</Text>", 0),
).rejects.toMatchObject({ code: "CONFLICT" });
await expect(service.reviseTemplate("session", "owner", "<Text>Stale edit</Text>", 0)).rejects.toMatchObject({
code: "CONFLICT",
});
await expect(
service.reviseTemplate("session", "owner", '<ActionButton requestId="missing">Run</ActionButton>', 1),
).rejects.toMatchObject({ code: "BAD_REQUEST" });
@@ -91,7 +91,7 @@ describe("lean Custom Widget schema", () => {
it("removes model-inserted zero-width spaces before JSX validation and persistence", () => {
const candidate = customWidgetDefinitionSchema.parse({
...CUSTOM_WIDGET_STARTER,
template: '<Stack>\u200b<Text>Cafe\u0301 {1 ?? \u03040}</Text>\u200b</Stack>',
template: "<Stack>\u200b<Text>Cafe\u0301 {1 ?? \u03040}</Text>\u200b</Stack>",
});
expect(candidate.template).toBe("<Stack><Text>Café {1 ?? 0}</Text></Stack>");
@@ -319,7 +319,7 @@ describe("lean Custom Widget schema", () => {
customWidgetDefinitionSchema.safeParse({
...CUSTOM_WIDGET_STARTER,
template:
'<Text>https://www.themoviedb.org/assets/2/v4/glyphicons/basic/glyphicons-basic-38-picture-grey-c8f8b4d9.svg</Text>',
"<Text>https://www.themoviedb.org/assets/2/v4/glyphicons/basic/glyphicons-basic-38-picture-grey-c8f8b4d9.svg</Text>",
}).success,
).toBe(true);
});