From 7da3eff3d1fae64190c81829aa304fcd40de1c9d Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 29 Mar 2026 20:29:29 +0000 Subject: [PATCH] Remove dropped ui artifact search columns Co-authored-by: Kent C. Dodds --- .../src/app/saved-ui-hosted-html.node.test.ts | 4 -- .../src/mcp/capabilities/apps/ui-get-app.ts | 6 +-- .../src/mcp/capabilities/apps/ui-list-apps.ts | 7 +--- .../src/mcp/capabilities/apps/ui-save-app.ts | 14 +------ .../mcp/capabilities/apps/ui-update-app.ts | 27 +------------ .../unified-search.workers.test.ts | 2 - .../worker/src/mcp/mcp-server.mcp-e2e.test.ts | 24 +++-------- .../infer-codemode-capabilities.node.test.ts | 3 +- .../worker/src/mcp/tools/search.node.test.ts | 3 +- packages/worker/src/mcp/ui-artifacts-embed.ts | 6 +-- packages/worker/src/mcp/ui-artifacts-repo.ts | 40 +++++-------------- .../worker/src/mcp/ui-artifacts-search.ts | 17 +------- packages/worker/src/mcp/ui-artifacts-types.ts | 2 - 13 files changed, 24 insertions(+), 131 deletions(-) diff --git a/packages/worker/src/app/saved-ui-hosted-html.node.test.ts b/packages/worker/src/app/saved-ui-hosted-html.node.test.ts index 1555389078..74cb6bc13a 100644 --- a/packages/worker/src/app/saved-ui-hosted-html.node.test.ts +++ b/packages/worker/src/app/saved-ui-hosted-html.node.test.ts @@ -20,11 +20,9 @@ test('renderHostedSavedUiHtml emits shared runtime assets for html apps', () => user_id: 'user-123', title: 'Hosted App', description: 'Hosted generated UI app', - keywords: 'hosted,generated-ui', code: '
Hello
', runtime: 'html', parameters: null, - search_text: null, created_at: '2026-03-27T00:00:00.000Z', updated_at: '2026-03-27T00:00:00.000Z', }, @@ -53,11 +51,9 @@ test('renderHostedSavedUiHtml keeps user javascript separate from runtime bootst user_id: 'user-123', title: 'Hosted JS App', description: 'Hosted generated UI javascript app', - keywords: 'hosted,generated-ui,javascript', code: 'document.querySelector("[data-generated-ui-root]")?.append("hello")', runtime: 'javascript', parameters: null, - search_text: null, created_at: '2026-03-27T00:00:00.000Z', updated_at: '2026-03-27T00:00:00.000Z', }, diff --git a/packages/worker/src/mcp/capabilities/apps/ui-get-app.ts b/packages/worker/src/mcp/capabilities/apps/ui-get-app.ts index 8473e820c7..c99de05700 100644 --- a/packages/worker/src/mcp/capabilities/apps/ui-get-app.ts +++ b/packages/worker/src/mcp/capabilities/apps/ui-get-app.ts @@ -2,7 +2,7 @@ import { z } from 'zod' import { defineDomainCapability } from '#mcp/capabilities/define-domain-capability.ts' import { capabilityDomainNames } from '#mcp/capabilities/domain-metadata.ts' import { type CapabilityContext } from '#mcp/capabilities/types.ts' -import { getUiArtifactById, parseStringArray } from '#mcp/ui-artifacts-repo.ts' +import { getUiArtifactById } from '#mcp/ui-artifacts-repo.ts' import { requireMcpUser } from '#mcp/capabilities/meta/require-user.ts' import { parseUiArtifactParameters, @@ -13,13 +13,11 @@ const outputSchema = z.object({ app_id: z.string(), title: z.string(), description: z.string(), - keywords: z.array(z.string()), parameters: z.array(uiArtifactParameterSchema).nullable(), code: z .string() .describe('Generated UI source code to render inside the generic shell.'), runtime: z.string(), - search_text: z.string().nullable(), created_at: z.string(), updated_at: z.string(), }) @@ -55,11 +53,9 @@ export const uiGetAppCapability = defineDomainCapability( app_id: row.id, title: row.title, description: row.description, - keywords: parseStringArray(row.keywords), parameters: parseUiArtifactParameters(row.parameters), code: row.code, runtime: row.runtime, - search_text: row.search_text, created_at: row.created_at, updated_at: row.updated_at, } diff --git a/packages/worker/src/mcp/capabilities/apps/ui-list-apps.ts b/packages/worker/src/mcp/capabilities/apps/ui-list-apps.ts index f7fbfa921f..d9f077a31c 100644 --- a/packages/worker/src/mcp/capabilities/apps/ui-list-apps.ts +++ b/packages/worker/src/mcp/capabilities/apps/ui-list-apps.ts @@ -6,10 +6,7 @@ import { parseUiArtifactParameters, uiArtifactParameterSchema, } from '#mcp/ui-artifact-parameters.ts' -import { - listUiArtifactsByUserId, - parseStringArray, -} from '#mcp/ui-artifacts-repo.ts' +import { listUiArtifactsByUserId } from '#mcp/ui-artifacts-repo.ts' import { requireMcpUser } from '#mcp/capabilities/meta/require-user.ts' const outputSchema = z.object({ @@ -18,7 +15,6 @@ const outputSchema = z.object({ app_id: z.string(), title: z.string(), description: z.string(), - keywords: z.array(z.string()), runtime: z.string(), parameters: z.array(uiArtifactParameterSchema).nullable(), created_at: z.string(), @@ -47,7 +43,6 @@ export const uiListAppsCapability = defineDomainCapability( app_id: row.id, title: row.title, description: row.description, - keywords: parseStringArray(row.keywords), runtime: row.runtime, parameters: parseUiArtifactParameters(row.parameters), created_at: row.created_at, diff --git a/packages/worker/src/mcp/capabilities/apps/ui-save-app.ts b/packages/worker/src/mcp/capabilities/apps/ui-save-app.ts index ff60a22d54..5e50099b5b 100644 --- a/packages/worker/src/mcp/capabilities/apps/ui-save-app.ts +++ b/packages/worker/src/mcp/capabilities/apps/ui-save-app.ts @@ -18,9 +18,6 @@ const inputSchema = z.object({ .string() .min(1) .describe('What the saved app does and when it is useful.'), - keywords: z - .array(z.string()) - .describe('Extra search keywords for discovery in the search tool.'), code: z .string() .min(1) @@ -33,12 +30,6 @@ const inputSchema = z.object({ .describe( 'Source format accepted by the generic UI shell. Prefer `html`; `javascript` is kept for legacy saved apps.', ), - search_text: z - .string() - .optional() - .describe( - 'Optional retrieval-only text that improves search recall without being part of the visible app description.', - ), parameters: z .array(uiArtifactParameterSchema) .optional() @@ -76,10 +67,8 @@ export const uiSaveAppCapability = defineDomainCapability( user_id: user.userId, title: args.title, description: args.description, - keywords: JSON.stringify(args.keywords), code: args.code, runtime: args.runtime, - search_text: args.search_text ?? null, parameters: parameters ? JSON.stringify(parameters) : null, created_at: now, updated_at: now, @@ -92,8 +81,7 @@ export const uiSaveAppCapability = defineDomainCapability( embedText: buildUiArtifactEmbedText({ title: args.title, description: args.description, - keywords: args.keywords, - searchText: args.search_text ?? null, + code: args.code, runtime: args.runtime, parameters, }), diff --git a/packages/worker/src/mcp/capabilities/apps/ui-update-app.ts b/packages/worker/src/mcp/capabilities/apps/ui-update-app.ts index f7d6bb4feb..caad3ae8ae 100644 --- a/packages/worker/src/mcp/capabilities/apps/ui-update-app.ts +++ b/packages/worker/src/mcp/capabilities/apps/ui-update-app.ts @@ -5,11 +5,7 @@ import { capabilityDomainNames } from '#mcp/capabilities/domain-metadata.ts' import { type CapabilityContext } from '#mcp/capabilities/types.ts' import { requireMcpUser } from '#mcp/capabilities/meta/require-user.ts' import { buildUiArtifactEmbedText } from '#mcp/ui-artifacts-embed.ts' -import { - getUiArtifactById, - parseStringArray, - updateUiArtifact, -} from '#mcp/ui-artifacts-repo.ts' +import { getUiArtifactById, updateUiArtifact } from '#mcp/ui-artifacts-repo.ts' import { upsertUiArtifactVector } from '#mcp/ui-artifacts-vectorize.ts' import { normalizeUiArtifactParameters, @@ -33,10 +29,6 @@ const inputSchema = z .min(1) .optional() .describe('What the saved app does and when it is useful.'), - keywords: z - .array(z.string()) - .optional() - .describe('Extra search keywords for discovery in the search tool.'), code: z .string() .min(1) @@ -50,12 +42,6 @@ const inputSchema = z .describe( 'Source format accepted by the generic UI shell. Prefer `html`; `javascript` is kept for legacy saved apps.', ), - search_text: z - .string() - .optional() - .describe( - 'Optional retrieval-only text that improves search recall without being part of the visible app description.', - ), parameters: z .array(uiArtifactParameterSchema) .optional() @@ -67,10 +53,8 @@ const inputSchema = z (value) => value.title !== undefined || value.description !== undefined || - value.keywords !== undefined || value.code !== undefined || value.runtime !== undefined || - value.search_text !== undefined || value.parameters !== undefined, { message: 'Provide at least one field to update.', @@ -106,18 +90,12 @@ export const uiUpdateAppCapability = defineDomainCapability( if (args.description !== undefined) { updates.description = args.description } - if (args.keywords !== undefined) { - updates.keywords = JSON.stringify(args.keywords) - } if (args.code !== undefined) { updates.code = args.code } if (args.runtime !== undefined) { updates.runtime = args.runtime } - if (args.search_text !== undefined) { - updates.search_text = args.search_text - } if (args.parameters !== undefined) { const parameters = normalizeUiArtifactParameters(args.parameters) updates.parameters = parameters ? JSON.stringify(parameters) : null @@ -149,8 +127,7 @@ export const uiUpdateAppCapability = defineDomainCapability( embedText: buildUiArtifactEmbedText({ title: refreshed.title, description: refreshed.description, - keywords: parseStringArray(refreshed.keywords), - searchText: refreshed.search_text, + code: refreshed.code, runtime: refreshed.runtime, parameters: parseUiArtifactParameters(refreshed.parameters), }), diff --git a/packages/worker/src/mcp/capabilities/unified-search.workers.test.ts b/packages/worker/src/mcp/capabilities/unified-search.workers.test.ts index e7fcbafe94..18ad9a320a 100644 --- a/packages/worker/src/mcp/capabilities/unified-search.workers.test.ts +++ b/packages/worker/src/mcp/capabilities/unified-search.workers.test.ts @@ -31,7 +31,6 @@ function createUiArtifactRow(appId: string): UiArtifactRow { user_id: 'user-123', title: 'Cloudflare deploy app', description: 'Saved UI for deploying a Worker', - keywords: JSON.stringify(['cloudflare', 'deploy']), code: '
Deploy
', runtime: 'html', parameters: JSON.stringify([ @@ -42,7 +41,6 @@ function createUiArtifactRow(appId: string): UiArtifactRow { required: true, }, ]), - search_text: 'deploy worker ui', created_at: '2026-03-20T00:00:00.000Z', updated_at: '2026-03-20T00:00:00.000Z', } diff --git a/packages/worker/src/mcp/mcp-server.mcp-e2e.test.ts b/packages/worker/src/mcp/mcp-server.mcp-e2e.test.ts index 664dbe1da1..1c8a31d9fb 100644 --- a/packages/worker/src/mcp/mcp-server.mcp-e2e.test.ts +++ b/packages/worker/src/mcp/mcp-server.mcp-e2e.test.ts @@ -586,7 +586,6 @@ test('mcp server searches capabilities', async () => { expect(saveApp?.requiredInputFields).toEqual([ 'title', 'description', - 'keywords', 'code', ]) expect(saveApp?.readOnly).toBeUndefined() @@ -725,7 +724,6 @@ test('mcp server executes ui_save_app via execute tool', async () => { await codemode.ui_save_app({ title: 'Execute generated app', description: 'Saved through execute.', - keywords: ['execute', 'ui'], code: '

Execute App

', })`, }, @@ -919,10 +917,8 @@ test('mcp server saves app, search returns app hit, and open_generated_ui suppor code: `async () => await codemode.ui_save_app({ title: 'Saved Searchable App', - description: 'Saved generated UI artifact for search and reopen.', - keywords: ['saved', 'searchable', 'ui'], - code: '

Saved Searchable App

', - search_text: 'searchable saved ui artifact demo', + description: 'Saved generated UI artifact demo for search and reopen.', + code: '

Saved Searchable App Demo

', })`, }, }) @@ -993,8 +989,7 @@ test('mcp server supports parameterized saved apps with resolved runtime params' code: `async () => await codemode.ui_save_app({ title: 'Parameterized Greeting App', - description: 'Reusable greeting UI with runtime params.', - keywords: ['greeting', 'parameterized', 'ui'], + description: 'Parameterized greeting UI app with runtime params.', parameters: [ { name: 'name', @@ -1010,7 +1005,6 @@ test('mcp server supports parameterized saved apps with resolved runtime params' }, ], code: '

Greeting App

', - search_text: 'parameterized greeting ui app', })`, }, }) @@ -1214,10 +1208,8 @@ test('generated ui sessions support secret storage, execute-time resolution, and code: `async () => await codemode.ui_save_app({ title: 'Secrets App', - description: 'Generated UI for secret-backed deployments.', - keywords: ['secret', 'deploy'], - code: '

Secrets App

', - search_text: 'cloudflare deploy secret app', + description: 'Cloudflare deploy secret app for secret-backed deployments.', + code: '

Secrets App

Cloudflare deploy

', })`, }, }) @@ -1799,7 +1791,6 @@ test('mcp server deletes saved ui app artifacts', async () => { await codemode.ui_save_app({ title: 'Delete Me App', description: 'Saved app to delete.', - keywords: ['delete', 'ui'], code: '

Delete Me

', })`, }, @@ -1861,7 +1852,6 @@ test('mcp server updates saved ui app artifacts', async () => { await codemode.ui_save_app({ title: 'Original App', description: 'Original app description.', - keywords: ['original', 'ui'], code: '

Original

', })`, }, @@ -1883,10 +1873,8 @@ test('mcp server updates saved ui app artifacts', async () => { app_id: ${JSON.stringify(appId)}, title: 'Updated App', description: 'Updated description.', - keywords: ['updated', 'ui'], code: '

Updated

', runtime: 'javascript', - search_text: 'updated searchable text', })`, }, }) @@ -1919,8 +1907,6 @@ test('mcp server updates saved ui app artifacts', async () => { | undefined expect(getPayload?.title).toBe('Updated App') expect(getPayload?.description).toBe('Updated description.') - expect(getPayload?.keywords).toEqual(['updated', 'ui']) expect(getPayload?.code).toBe('

Updated

') expect(getPayload?.runtime).toBe('javascript') - expect(getPayload?.search_text).toBe('updated searchable text') }) diff --git a/packages/worker/src/mcp/skills/infer-codemode-capabilities.node.test.ts b/packages/worker/src/mcp/skills/infer-codemode-capabilities.node.test.ts index 2ad8036692..2b015a806a 100644 --- a/packages/worker/src/mcp/skills/infer-codemode-capabilities.node.test.ts +++ b/packages/worker/src/mcp/skills/infer-codemode-capabilities.node.test.ts @@ -10,8 +10,7 @@ test('infers static codemode member names', () => { return await codemode.ui_save_app({ title: 'Demo', description: 'Demo app', - keywords: ['demo'], - source: '
demo
', + code: '
demo
', }) }` const { staticNames, inferencePartial } = inferCodemodeCapabilities(src) diff --git a/packages/worker/src/mcp/tools/search.node.test.ts b/packages/worker/src/mcp/tools/search.node.test.ts index 47d7977f39..4a766783fa 100644 --- a/packages/worker/src/mcp/tools/search.node.test.ts +++ b/packages/worker/src/mcp/tools/search.node.test.ts @@ -16,10 +16,9 @@ test('optional search rows fall back when saved skills lookup fails', async () = user_id: 'user-123', title: 'Roku remote', description: 'Saved remote UI', - keywords: 'roku remote', code: '
', runtime: 'html', - search_text: 'roku remote', + parameters: null, created_at: '2026-03-24T00:00:00.000Z', updated_at: '2026-03-24T00:00:00.000Z', }, diff --git a/packages/worker/src/mcp/ui-artifacts-embed.ts b/packages/worker/src/mcp/ui-artifacts-embed.ts index fff15b2b2f..ae08796971 100644 --- a/packages/worker/src/mcp/ui-artifacts-embed.ts +++ b/packages/worker/src/mcp/ui-artifacts-embed.ts @@ -4,9 +4,8 @@ export function buildUiArtifactEmbedText( input: { title: string description: string - keywords: Array + code: string runtime: string - searchText: string | null parameters?: Array<{ name: string description: string @@ -39,12 +38,11 @@ export function buildUiArtifactEmbedText( const text = [ input.title, input.description, - input.keywords.join(' '), + input.code, input.runtime, 'mcp app', 'ui artifact', ...(parameterText ? [parameterText] : []), - ...(input.searchText ? [input.searchText] : []), ].join('\n') return text.slice(0, maxChars) } diff --git a/packages/worker/src/mcp/ui-artifacts-repo.ts b/packages/worker/src/mcp/ui-artifacts-repo.ts index 0b4f76b2ee..653237da67 100644 --- a/packages/worker/src/mcp/ui-artifacts-repo.ts +++ b/packages/worker/src/mcp/ui-artifacts-repo.ts @@ -1,15 +1,5 @@ import { type UiArtifactRow } from './ui-artifacts-types.ts' -export function parseStringArray(raw: string): Array { - try { - const value = JSON.parse(raw) as unknown - if (!Array.isArray(value)) return [] - return value.filter((entry): entry is string => typeof entry === 'string') - } catch { - return [] - } -} - export function uiArtifactVectorId(artifactId: string): string { return `ui_artifact_${artifactId}` } @@ -25,19 +15,17 @@ export async function insertUiArtifact( await db .prepare( `INSERT INTO ui_artifacts ( - id, user_id, title, description, keywords, source_code, source_type, - search_text, parameters, created_at, updated_at - ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, + id, user_id, title, description, source_code, source_type, + parameters, created_at, updated_at + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, ) .bind( row.id, row.user_id, row.title, row.description, - row.keywords, row.code, row.runtime, - row.search_text ?? null, row.parameters ?? null, row.created_at ?? now, row.updated_at ?? now, @@ -52,8 +40,8 @@ export async function getUiArtifactById( ): Promise { const result = await db .prepare( - `SELECT id, user_id, title, description, keywords, source_code, source_type, - search_text, parameters, created_at, updated_at + `SELECT id, user_id, title, description, source_code, source_type, + parameters, created_at, updated_at FROM ui_artifacts WHERE id = ? AND user_id = ?`, ) .bind(artifactId, userId) @@ -73,8 +61,8 @@ export async function getUiArtifactByOwnerIds( const placeholders = ownerIds.map(() => '?').join(', ') const result = await db .prepare( - `SELECT id, user_id, title, description, keywords, source_code, source_type, - search_text, parameters, created_at, updated_at + `SELECT id, user_id, title, description, source_code, source_type, + parameters, created_at, updated_at FROM ui_artifacts WHERE id = ? AND user_id IN (${placeholders}) LIMIT 1`, @@ -106,10 +94,8 @@ export async function updateUiArtifact( UiArtifactRow, | 'title' | 'description' - | 'keywords' | 'code' | 'runtime' - | 'search_text' | 'parameters' > >, @@ -127,18 +113,12 @@ export async function updateUiArtifact( if (updates.description !== undefined) { addAssignment('description', updates.description) } - if (updates.keywords !== undefined) { - addAssignment('keywords', updates.keywords) - } if (updates.code !== undefined) { addAssignment('source_code', updates.code) } if (updates.runtime !== undefined) { addAssignment('source_type', updates.runtime) } - if (updates.search_text !== undefined) { - addAssignment('search_text', updates.search_text ?? null) - } if (updates.parameters !== undefined) { addAssignment('parameters', updates.parameters ?? null) } @@ -160,8 +140,8 @@ export async function listUiArtifactsByUserId( ): Promise> { const { results } = await db .prepare( - `SELECT id, user_id, title, description, keywords, source_code, source_type, - search_text, parameters, created_at, updated_at + `SELECT id, user_id, title, description, source_code, source_type, + parameters, created_at, updated_at FROM ui_artifacts WHERE user_id = ?`, ) .bind(userId) @@ -175,10 +155,8 @@ function mapRow(row: Record): UiArtifactRow { user_id: String(row['user_id']), title: String(row['title']), description: String(row['description']), - keywords: String(row['keywords']), code: String(row['source_code']), runtime: String(row['source_type']) as UiArtifactRow['runtime'], - search_text: row['search_text'] == null ? null : String(row['search_text']), parameters: row['parameters'] == null ? null : String(row['parameters']), created_at: String(row['created_at']), updated_at: String(row['updated_at']), diff --git a/packages/worker/src/mcp/ui-artifacts-search.ts b/packages/worker/src/mcp/ui-artifacts-search.ts index b725c96705..6b5f26d7c2 100644 --- a/packages/worker/src/mcp/ui-artifacts-search.ts +++ b/packages/worker/src/mcp/ui-artifacts-search.ts @@ -14,16 +14,6 @@ import { parseUiArtifactParameters } from '#mcp/ui-artifact-parameters.ts' import { buildUiArtifactEmbedText } from '#mcp/ui-artifacts-embed.ts' import { type UiArtifactRow } from './ui-artifacts-types.ts' -function parseJsonStringArray(raw: string): Array { - try { - const value = JSON.parse(raw) as unknown - if (!Array.isArray(value)) return [] - return value.filter((item): item is string => typeof item === 'string') - } catch { - return [] - } -} - function rowToEmbedDoc(row: UiArtifactRow, appSecrets: Array) { const secretText = appSecrets.length > 0 @@ -34,8 +24,7 @@ function rowToEmbedDoc(row: UiArtifactRow, appSecrets: Array) { return `${buildUiArtifactEmbedText({ title: row.title, description: row.description, - keywords: parseJsonStringArray(row.keywords), - searchText: row.search_text, + code: row.code, runtime: row.runtime, parameters: parseUiArtifactParameters(row.parameters), })}${secretText}` @@ -75,7 +64,6 @@ export type UiArtifactSearchHitSummary = { domain: 'apps' title: string description: string - keywords: Array runtime: string parameters: Array<{ name: string @@ -95,7 +83,6 @@ export type UiArtifactSearchHitSummary = { } export type UiArtifactSearchHitDetail = UiArtifactSearchHitSummary & { - searchText: string | null createdAt: string updatedAt: string } @@ -119,7 +106,6 @@ function rowToUiArtifactHit( domain: 'apps', title: row.title, description: row.description, - keywords: parseJsonStringArray(row.keywords), runtime: row.runtime, parameters, usage: buildUsage(row), @@ -134,7 +120,6 @@ function rowToUiArtifactHit( if (detail) { return { ...base, - searchText: row.search_text, createdAt: row.created_at, updatedAt: row.updated_at, } diff --git a/packages/worker/src/mcp/ui-artifacts-types.ts b/packages/worker/src/mcp/ui-artifacts-types.ts index d7a832a3a7..e8d4640ad4 100644 --- a/packages/worker/src/mcp/ui-artifacts-types.ts +++ b/packages/worker/src/mcp/ui-artifacts-types.ts @@ -5,11 +5,9 @@ export type UiArtifactRow = { user_id: string title: string description: string - keywords: string code: string runtime: UiArtifactRuntime parameters: string | null - search_text: string | null created_at: string updated_at: string }