diff --git a/apps/docs/content/docs/en/api-reference/(generated)/human-in-the-loop/meta.json b/apps/docs/content/docs/en/api-reference/(generated)/human-in-the-loop/meta.json new file mode 100644 index 00000000000..9abb7f2e363 --- /dev/null +++ b/apps/docs/content/docs/en/api-reference/(generated)/human-in-the-loop/meta.json @@ -0,0 +1,9 @@ +{ + "pages": [ + "listPausedExecutions", + "getPausedExecution", + "getPausedExecutionByResumePath", + "getPauseContext", + "resumeExecution" + ] +} diff --git a/apps/docs/content/docs/en/api-reference/meta.json b/apps/docs/content/docs/en/api-reference/meta.json index 8581f6f1572..c99ab8eb13f 100644 --- a/apps/docs/content/docs/en/api-reference/meta.json +++ b/apps/docs/content/docs/en/api-reference/meta.json @@ -10,6 +10,7 @@ "typescript", "---Endpoints---", "(generated)/workflows", + "(generated)/human-in-the-loop", "(generated)/logs", "(generated)/usage", "(generated)/audit-logs", diff --git a/apps/sim/app/api/logs/cleanup/route.ts b/apps/sim/app/api/logs/cleanup/route.ts index 25a0acabf55..85623e7d2a8 100644 --- a/apps/sim/app/api/logs/cleanup/route.ts +++ b/apps/sim/app/api/logs/cleanup/route.ts @@ -1,5 +1,5 @@ import { db } from '@sim/db' -import { subscription, user, workflowExecutionLogs, workspace } from '@sim/db/schema' +import { subscription, workflowExecutionLogs, workspace } from '@sim/db/schema' import { createLogger } from '@sim/logger' import { and, eq, inArray, isNull, lt } from 'drizzle-orm' import { type NextRequest, NextResponse } from 'next/server' @@ -26,38 +26,19 @@ export async function GET(request: NextRequest) { const retentionDate = new Date() retentionDate.setDate(retentionDate.getDate() - Number(env.FREE_PLAN_LOG_RETENTION_DAYS || '7')) - const freeUsers = await db - .select({ userId: user.id }) - .from(user) + const freeWorkspacesSubquery = db + .select({ id: workspace.id }) + .from(workspace) .leftJoin( subscription, and( - eq(user.id, subscription.referenceId), + eq(subscription.referenceId, workspace.billedAccountUserId), inArray(subscription.status, ENTITLED_SUBSCRIPTION_STATUSES), sqlIsPaid(subscription.plan) ) ) .where(isNull(subscription.id)) - if (freeUsers.length === 0) { - logger.info('No free users found for log cleanup') - return NextResponse.json({ message: 'No free users found for cleanup' }) - } - - const freeUserIds = freeUsers.map((u) => u.userId) - - const workspacesQuery = await db - .select({ id: workspace.id }) - .from(workspace) - .where(inArray(workspace.billedAccountUserId, freeUserIds)) - - if (workspacesQuery.length === 0) { - logger.info('No workspaces found for free users') - return NextResponse.json({ message: 'No workspaces found for cleanup' }) - } - - const workspaceIds = workspacesQuery.map((w) => w.id) - const results = { enhancedLogs: { total: 0, @@ -83,7 +64,7 @@ export async function GET(request: NextRequest) { let batchesProcessed = 0 let hasMoreLogs = true - logger.info(`Starting enhanced logs cleanup for ${workspaceIds.length} workspaces`) + logger.info('Starting enhanced logs cleanup for free-plan workspaces') while (hasMoreLogs && batchesProcessed < MAX_BATCHES) { const oldEnhancedLogs = await db @@ -105,8 +86,8 @@ export async function GET(request: NextRequest) { .from(workflowExecutionLogs) .where( and( - inArray(workflowExecutionLogs.workspaceId, workspaceIds), - lt(workflowExecutionLogs.createdAt, retentionDate) + inArray(workflowExecutionLogs.workspaceId, freeWorkspacesSubquery), + lt(workflowExecutionLogs.startedAt, retentionDate) ) ) .limit(BATCH_SIZE) diff --git a/apps/sim/blocks/blocks/jira.ts b/apps/sim/blocks/blocks/jira.ts index 092677ab904..c6c93e4b3d2 100644 --- a/apps/sim/blocks/blocks/jira.ts +++ b/apps/sim/blocks/blocks/jira.ts @@ -479,6 +479,13 @@ Return ONLY the JQL query - no explanations or markdown formatting.`, placeholder: 'Maximum results to return (default: 50)', condition: { field: 'operation', value: ['search', 'get_comments', 'get_worklogs'] }, }, + { + id: 'fields', + title: 'Fields', + type: 'short-input', + placeholder: 'Comma-separated fields to return (e.g., key,summary,status)', + condition: { field: 'operation', value: 'search' }, + }, // Comment fields { id: 'commentBody', @@ -922,6 +929,12 @@ Return ONLY the comment text - no explanations.`, jql: params.jql, nextPageToken: params.nextPageToken || undefined, maxResults: params.maxResults ? Number.parseInt(params.maxResults) : undefined, + fields: params.fields + ? params.fields + .split(',') + .map((f: string) => f.trim()) + .filter(Boolean) + : undefined, } } case 'add_comment': { @@ -1114,6 +1127,10 @@ Return ONLY the comment text - no explanations.`, startAt: { type: 'string', description: 'Pagination start index' }, jql: { type: 'string', description: 'JQL (Jira Query Language) search query' }, maxResults: { type: 'string', description: 'Maximum number of results to return' }, + fields: { + type: 'string', + description: 'Comma-separated field names to return (e.g., key,summary,status)', + }, // Comment operation inputs commentBody: { type: 'string', description: 'Text content for comment operations' }, commentId: { type: 'string', description: 'Comment ID for update/delete operations' }, diff --git a/apps/sim/executor/handlers/agent/agent-handler.test.ts b/apps/sim/executor/handlers/agent/agent-handler.test.ts index d4987de9606..437dc69121d 100644 --- a/apps/sim/executor/handlers/agent/agent-handler.test.ts +++ b/apps/sim/executor/handlers/agent/agent-handler.test.ts @@ -667,6 +667,7 @@ describe('AgentBlockHandler', () => { expect(result).toEqual({ result: 'Success', score: 0.95, + model: 'mock-model', tokens: { input: 10, output: 20, total: 30 }, toolCalls: { list: [], count: 0 }, providerTiming: { total: 100 }, diff --git a/apps/sim/executor/handlers/agent/agent-handler.ts b/apps/sim/executor/handlers/agent/agent-handler.ts index 9926e4d5b14..6df3c7e9c6f 100644 --- a/apps/sim/executor/handlers/agent/agent-handler.ts +++ b/apps/sim/executor/handlers/agent/agent-handler.ts @@ -1070,19 +1070,20 @@ export class AgentBlockHandler implements BlockHandler { private processStandardResponse(result: any): BlockOutput { return { content: result.content, - model: result.model, ...this.createResponseMetadata(result), ...(result.interactionId && { interactionId: result.interactionId }), } } private createResponseMetadata(result: { + model?: string tokens?: { input?: number; output?: number; total?: number } toolCalls?: Array timing?: any cost?: any }) { return { + model: result.model, tokens: result.tokens || { input: DEFAULTS.TOKENS.PROMPT, output: DEFAULTS.TOKENS.COMPLETION, diff --git a/apps/sim/tools/jsm/utils.ts b/apps/sim/tools/jsm/utils.ts index 00815472585..d02c794a34e 100644 --- a/apps/sim/tools/jsm/utils.ts +++ b/apps/sim/tools/jsm/utils.ts @@ -50,13 +50,36 @@ export function parseJsmErrorMessage( ): string { try { const errorData = JSON.parse(errorText) + // JSM Service Desk: singular errorMessage if (errorData.errorMessage) { - return `JSM Forms API error: ${errorData.errorMessage}` + return errorData.errorMessage + } + // Jira Platform: errorMessages array + if (Array.isArray(errorData.errorMessages) && errorData.errorMessages.length > 0) { + return errorData.errorMessages.join(', ') + } + // Confluence v2 / Forms API: RFC 7807 errors array + if (Array.isArray(errorData.errors) && errorData.errors.length > 0) { + const err = errorData.errors[0] + if (err?.title) { + return err.detail ? `${err.title}: ${err.detail}` : err.title + } + } + // Jira Platform field-level errors object + if (errorData.errors && !Array.isArray(errorData.errors)) { + const fieldErrors = Object.entries(errorData.errors) + .map(([field, msg]) => `${field}: ${msg}`) + .join(', ') + if (fieldErrors) return fieldErrors + } + // Generic message fallback + if (errorData.message) { + return errorData.message } } catch { if (errorText) { - return `JSM Forms API error: ${errorText}` + return errorText } } - return `JSM Forms API error: ${status} ${statusText}` + return `${status} ${statusText}` }