diff --git a/apps/sim/app/api/table/[tableId]/route.ts b/apps/sim/app/api/table/[tableId]/route.ts index 7715cceff..c73f8b299 100644 --- a/apps/sim/app/api/table/[tableId]/route.ts +++ b/apps/sim/app/api/table/[tableId]/route.ts @@ -64,7 +64,14 @@ export async function GET( id: table.id, name: table.name, description: table.description, - schema: table.schema, + schema: { + columns: (table.schema as any).columns.map((col: any) => ({ + name: col.name, + type: col.type, + required: col.required ?? false, + unique: col.unique ?? false, + })), + }, rowCount: table.rowCount, maxRows: table.maxRows, createdAt: table.createdAt.toISOString(), diff --git a/apps/sim/app/api/table/route.ts b/apps/sim/app/api/table/route.ts index a2ea2680c..774fc2391 100644 --- a/apps/sim/app/api/table/route.ts +++ b/apps/sim/app/api/table/route.ts @@ -172,6 +172,16 @@ export async function POST(request: NextRequest) { ) } + // Normalize schema to ensure all fields have explicit defaults + const normalizedSchema = { + columns: params.schema.columns.map((col) => ({ + name: col.name, + type: col.type, + required: col.required ?? false, + unique: col.unique ?? false, + })), + } + // Create table const tableId = `tbl_${crypto.randomUUID().replace(/-/g, '')}` const now = new Date() @@ -183,7 +193,7 @@ export async function POST(request: NextRequest) { workspaceId: params.workspaceId, name: params.name, description: params.description, - schema: params.schema, + schema: normalizedSchema, maxRows: TABLE_LIMITS.MAX_ROWS_PER_TABLE, rowCount: 0, createdBy: authResult.userId, @@ -279,6 +289,14 @@ export async function GET(request: NextRequest) { return NextResponse.json({ tables: tables.map((t) => ({ ...t, + schema: { + columns: (t.schema as any).columns.map((col: any) => ({ + name: col.name, + type: col.type, + required: col.required ?? false, + unique: col.unique ?? false, + })), + }, createdAt: t.createdAt.toISOString(), updatedAt: t.updatedAt.toISOString(), })), diff --git a/apps/sim/blocks/blocks/table.ts b/apps/sim/blocks/blocks/table.ts index de24790ce..8130af3a3 100644 --- a/apps/sim/blocks/blocks/table.ts +++ b/apps/sim/blocks/blocks/table.ts @@ -28,6 +28,7 @@ export const TableBlock: BlockConfig = { { label: 'Update Row by ID', id: 'updateRow' }, { label: 'Delete Row by ID', id: 'deleteRow' }, { label: 'Get Row by ID', id: 'getRow' }, + { label: 'Get Schema', id: 'getSchema' }, ], value: () => 'queryRows', }, @@ -449,6 +450,7 @@ Return ONLY the sort JSON:`, 'table_delete_rows_by_filter', 'table_query_rows', 'table_get_row', + 'table_get_schema', ], config: { tool: (params) => { @@ -462,6 +464,7 @@ Return ONLY the sort JSON:`, deleteRowsByFilter: 'table_delete_rows_by_filter', queryRows: 'table_query_rows', getRow: 'table_get_row', + getSchema: 'table_get_schema', } return toolMap[params.operation] || 'table_query_rows' }, @@ -583,6 +586,13 @@ Return ONLY the sort JSON:`, } } + // Get Schema + if (operation === 'getSchema') { + return { + tableId: rest.tableId, + } + } + // Query Rows if (operation === 'queryRows') { let filter: any @@ -695,6 +705,16 @@ Return ONLY the sort JSON:`, description: 'IDs of deleted rows', condition: { field: 'operation', value: 'deleteRowsByFilter' }, }, + name: { + type: 'string', + description: 'Table name', + condition: { field: 'operation', value: 'getSchema' }, + }, + columns: { + type: 'array', + description: 'Column definitions', + condition: { field: 'operation', value: 'getSchema' }, + }, message: { type: 'string', description: 'Operation status message' }, }, } diff --git a/apps/sim/tools/registry.ts b/apps/sim/tools/registry.ts index 0e36b5e75..f4e9306ac 100644 --- a/apps/sim/tools/registry.ts +++ b/apps/sim/tools/registry.ts @@ -1376,6 +1376,7 @@ import { tableDeleteRowsByFilterTool, tableDeleteRowTool, tableGetRowTool, + tableGetSchemaTool, tableInsertRowTool, tableListTool, tableQueryRowsTool, @@ -2726,6 +2727,7 @@ export const tools: Record = { table_delete_rows_by_filter: tableDeleteRowsByFilterTool, table_query_rows: tableQueryRowsTool, table_get_row: tableGetRowTool, + table_get_schema: tableGetSchemaTool, mailchimp_get_audiences: mailchimpGetAudiencesTool, mailchimp_get_audience: mailchimpGetAudienceTool, mailchimp_create_audience: mailchimpCreateAudienceTool, diff --git a/apps/sim/tools/table/batch-insert-rows.ts b/apps/sim/tools/table/batch-insert-rows.ts index 7f8344654..fdca819fc 100644 --- a/apps/sim/tools/table/batch-insert-rows.ts +++ b/apps/sim/tools/table/batch-insert-rows.ts @@ -47,33 +47,6 @@ export const tableBatchInsertRowsTool: ToolConfig< transformResponse: async (response): Promise => { const data = await response.json() - if (!response.ok) { - let errorMessage = data.error || 'Failed to batch insert rows' - - // Include details if present - if (data.details) { - if (Array.isArray(data.details) && data.details.length > 0) { - // Check if details is array of error objects with row numbers - if (typeof data.details[0] === 'object' && 'row' in data.details[0]) { - const errorSummary = data.details - .map((detail: { row: number; errors: string[] }) => { - const rowErrors = detail.errors.join(', ') - return `Row ${detail.row}: ${rowErrors}` - }) - .join('; ') - errorMessage = `${errorMessage}: ${errorSummary}` - } else { - // Simple array of strings - errorMessage = `${errorMessage}: ${data.details.join('; ')}` - } - } else if (typeof data.details === 'string') { - errorMessage = `${errorMessage}: ${data.details}` - } - } - - throw new Error(errorMessage) - } - return { success: true, output: { diff --git a/apps/sim/tools/table/create.ts b/apps/sim/tools/table/create.ts index 7dd1fdc04..186c11e1a 100644 --- a/apps/sim/tools/table/create.ts +++ b/apps/sim/tools/table/create.ts @@ -52,10 +52,6 @@ export const tableCreateTool: ToolConfig transformResponse: async (response): Promise => { const data = await response.json() - if (!response.ok) { - throw new Error(data.error || 'Failed to create table') - } - return { success: true, output: { diff --git a/apps/sim/tools/table/delete-row.ts b/apps/sim/tools/table/delete-row.ts index 24903e453..896e20a7e 100644 --- a/apps/sim/tools/table/delete-row.ts +++ b/apps/sim/tools/table/delete-row.ts @@ -43,10 +43,6 @@ export const tableDeleteRowTool: ToolConfig => { const data = await response.json() - if (!response.ok) { - throw new Error(data.error || 'Failed to delete row') - } - return { success: true, output: { diff --git a/apps/sim/tools/table/delete-rows-by-filter.ts b/apps/sim/tools/table/delete-rows-by-filter.ts index fb2d03aa4..2f14460bb 100644 --- a/apps/sim/tools/table/delete-rows-by-filter.ts +++ b/apps/sim/tools/table/delete-rows-by-filter.ts @@ -55,10 +55,6 @@ export const tableDeleteRowsByFilterTool: ToolConfig< transformResponse: async (response): Promise => { const data = await response.json() - if (!response.ok) { - throw new Error(data.error || 'Failed to delete rows') - } - return { success: true, output: { diff --git a/apps/sim/tools/table/get-row.ts b/apps/sim/tools/table/get-row.ts index 0dce54a28..7cb50af2f 100644 --- a/apps/sim/tools/table/get-row.ts +++ b/apps/sim/tools/table/get-row.ts @@ -40,10 +40,6 @@ export const tableGetRowTool: ToolConfig = transformResponse: async (response): Promise => { const data = await response.json() - if (!response.ok) { - throw new Error(data.error || 'Failed to get row') - } - return { success: true, output: { diff --git a/apps/sim/tools/table/get-schema.ts b/apps/sim/tools/table/get-schema.ts new file mode 100644 index 000000000..113bfae48 --- /dev/null +++ b/apps/sim/tools/table/get-schema.ts @@ -0,0 +1,53 @@ +import type { ToolConfig } from '@/tools/types' +import type { TableGetSchemaParams, TableGetSchemaResponse } from './types' + +export const tableGetSchemaTool: ToolConfig = { + id: 'table_get_schema', + name: 'Get Schema', + description: 'Get the schema configuration of a table', + version: '1.0.0', + + params: { + tableId: { + type: 'string', + required: true, + description: 'Table ID', + visibility: 'user-or-llm', + }, + }, + + request: { + url: (params: any) => { + const workspaceId = params._context?.workspaceId + if (!workspaceId) { + throw new Error('workspaceId is required in execution context') + } + + return `/api/table/${params.tableId}?workspaceId=${encodeURIComponent(workspaceId)}` + }, + method: 'GET', + headers: () => ({ + 'Content-Type': 'application/json', + }), + }, + + transformResponse: async (response): Promise => { + const data = await response.json() + + return { + success: true, + output: { + name: data.table.name, + columns: data.table.schema.columns, + message: 'Schema retrieved successfully', + }, + } + }, + + outputs: { + success: { type: 'boolean', description: 'Whether schema was retrieved' }, + name: { type: 'string', description: 'Table name' }, + columns: { type: 'array', description: 'Column definitions' }, + message: { type: 'string', description: 'Status message' }, + }, +} diff --git a/apps/sim/tools/table/index.ts b/apps/sim/tools/table/index.ts index 5f8303fc7..ec8a0ae0e 100644 --- a/apps/sim/tools/table/index.ts +++ b/apps/sim/tools/table/index.ts @@ -3,6 +3,7 @@ export * from './create' export * from './delete-row' export * from './delete-rows-by-filter' export * from './get-row' +export * from './get-schema' export * from './insert-row' export * from './list' export * from './query-rows' diff --git a/apps/sim/tools/table/insert-row.ts b/apps/sim/tools/table/insert-row.ts index 9a153f107..c1718aa94 100644 --- a/apps/sim/tools/table/insert-row.ts +++ b/apps/sim/tools/table/insert-row.ts @@ -44,22 +44,6 @@ export const tableInsertRowTool: ToolConfig => { const data = await response.json() - if (!response.ok) { - let errorMessage = data.error || 'Failed to insert row' - - // Include details array if present - if (data.details) { - if (Array.isArray(data.details) && data.details.length > 0) { - const detailsStr = data.details.join('; ') - errorMessage = `${errorMessage}: ${detailsStr}` - } else if (typeof data.details === 'string') { - errorMessage = `${errorMessage}: ${data.details}` - } - } - - throw new Error(errorMessage) - } - return { success: true, output: { diff --git a/apps/sim/tools/table/list.ts b/apps/sim/tools/table/list.ts index 69437f4f2..b0bb80a3b 100644 --- a/apps/sim/tools/table/list.ts +++ b/apps/sim/tools/table/list.ts @@ -26,10 +26,6 @@ export const tableListTool: ToolConfig = { transformResponse: async (response): Promise => { const data = await response.json() - if (!response.ok) { - throw new Error(data.error || 'Failed to list tables') - } - return { success: true, output: { diff --git a/apps/sim/tools/table/query-rows.ts b/apps/sim/tools/table/query-rows.ts index 467222978..f2dd5db15 100644 --- a/apps/sim/tools/table/query-rows.ts +++ b/apps/sim/tools/table/query-rows.ts @@ -76,10 +76,6 @@ export const tableQueryRowsTool: ToolConfig => { const data = await response.json() - if (!response.ok) { - throw new Error(data.error || 'Failed to query rows') - } - return { success: true, output: { diff --git a/apps/sim/tools/table/types.ts b/apps/sim/tools/table/types.ts index 388a33bae..ade20e783 100644 --- a/apps/sim/tools/table/types.ts +++ b/apps/sim/tools/table/types.ts @@ -185,3 +185,16 @@ export interface TableBulkOperationResponse extends ToolResponse { message: string } } + +export interface TableGetSchemaParams extends ToolParamsWithContext { + tableId: string + workspaceId?: string +} + +export interface TableGetSchemaResponse extends ToolResponse { + output: { + name: string + columns: ColumnDefinition[] + message: string + } +} diff --git a/apps/sim/tools/table/update-row.ts b/apps/sim/tools/table/update-row.ts index b320602f6..41a796863 100644 --- a/apps/sim/tools/table/update-row.ts +++ b/apps/sim/tools/table/update-row.ts @@ -50,22 +50,6 @@ export const tableUpdateRowTool: ToolConfig => { const data = await response.json() - if (!response.ok) { - let errorMessage = data.error || 'Failed to update row' - - // Include details array if present - if (data.details) { - if (Array.isArray(data.details) && data.details.length > 0) { - const detailsStr = data.details.join('; ') - errorMessage = `${errorMessage}: ${detailsStr}` - } else if (typeof data.details === 'string') { - errorMessage = `${errorMessage}: ${data.details}` - } - } - - throw new Error(errorMessage) - } - return { success: true, output: { diff --git a/apps/sim/tools/table/update-rows-by-filter.ts b/apps/sim/tools/table/update-rows-by-filter.ts index afa8df842..685ac0d10 100644 --- a/apps/sim/tools/table/update-rows-by-filter.ts +++ b/apps/sim/tools/table/update-rows-by-filter.ts @@ -62,22 +62,6 @@ export const tableUpdateRowsByFilterTool: ToolConfig< transformResponse: async (response): Promise => { const data = await response.json() - if (!response.ok) { - let errorMessage = data.error || 'Failed to update rows' - - // Include details array if present - if (data.details) { - if (Array.isArray(data.details) && data.details.length > 0) { - const detailsStr = data.details.join('; ') - errorMessage = `${errorMessage}: ${detailsStr}` - } else if (typeof data.details === 'string') { - errorMessage = `${errorMessage}: ${data.details}` - } - } - - throw new Error(errorMessage) - } - return { success: true, output: { diff --git a/apps/sim/tools/table/upsert-row.ts b/apps/sim/tools/table/upsert-row.ts index c6823efbb..29ecbc6bd 100644 --- a/apps/sim/tools/table/upsert-row.ts +++ b/apps/sim/tools/table/upsert-row.ts @@ -49,22 +49,6 @@ export const tableUpsertRowTool: ToolConfig => { const data = await response.json() - if (!response.ok) { - let errorMessage = data.error || 'Failed to upsert row' - - // Include details array if present - if (data.details) { - if (Array.isArray(data.details) && data.details.length > 0) { - const detailsStr = data.details.join('; ') - errorMessage = `${errorMessage}: ${detailsStr}` - } else if (typeof data.details === 'string') { - errorMessage = `${errorMessage}: ${data.details}` - } - } - - throw new Error(errorMessage) - } - return { success: true, output: {