Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"pages": [
"listPausedExecutions",
"getPausedExecution",
"getPausedExecutionByResumePath",
"getPauseContext",
"resumeExecution"
]
}
1 change: 1 addition & 0 deletions apps/docs/content/docs/en/api-reference/meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"typescript",
"---Endpoints---",
"(generated)/workflows",
"(generated)/human-in-the-loop",
"(generated)/logs",
"(generated)/usage",
"(generated)/audit-logs",
Expand Down
35 changes: 8 additions & 27 deletions apps/sim/app/api/logs/cleanup/route.ts
Original file line number Diff line number Diff line change
@@ -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'
Expand All @@ -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,
Expand All @@ -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
Expand All @@ -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)
Expand Down
17 changes: 17 additions & 0 deletions apps/sim/blocks/blocks/jira.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -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': {
Expand Down Expand Up @@ -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' },
Expand Down
1 change: 1 addition & 0 deletions apps/sim/executor/handlers/agent/agent-handler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
Expand Down
3 changes: 2 additions & 1 deletion apps/sim/executor/handlers/agent/agent-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<any>
timing?: any
cost?: any
}) {
return {
model: result.model,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Metadata model field silently overwrites structured response data

Low Severity

Moving model into createResponseMetadata means it now gets spread over user-defined structured output in processStructuredResponse. Since metadata is spread after extractedJson, a user whose response schema includes a model field (e.g., product model, car model) will have that value silently overwritten by the provider's model identifier. Unlike the other metadata keys (tokens, toolCalls, providerTiming, cost), model is a common real-world field name, making collision more likely.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 3efbd1d. Configure here.

tokens: result.tokens || {
input: DEFAULTS.TOKENS.PROMPT,
output: DEFAULTS.TOKENS.COMPLETION,
Expand Down
29 changes: 26 additions & 3 deletions apps/sim/tools/jsm/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Comment on lines +53 to +76
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Non-TSDoc inline comments violate project standards

The added // comments (// JSM Service Desk: singular errorMessage, // Jira Platform: errorMessages array, etc.) are non-TSDoc comments. The project's global standards explicitly forbid non-TSDoc comments — all documentation should use TSDoc format or be removed.

Context Used: Global coding standards that apply to all files (source)

return errorData.message
}
} catch {
if (errorText) {
return `JSM Forms API error: ${errorText}`
return errorText
}
}
return `JSM Forms API error: ${status} ${statusText}`
return `${status} ${statusText}`
}
Loading