mirror of
https://github.com/simstudioai/sim.git
synced 2026-04-28 03:00:29 -04:00
v0.6.35: additional jira fields, HITL docs, logs cleanup efficiency
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"pages": [
|
||||
"listPausedExecutions",
|
||||
"getPausedExecution",
|
||||
"getPausedExecutionByResumePath",
|
||||
"getPauseContext",
|
||||
"resumeExecution"
|
||||
]
|
||||
}
|
||||
@@ -10,6 +10,7 @@
|
||||
"typescript",
|
||||
"---Endpoints---",
|
||||
"(generated)/workflows",
|
||||
"(generated)/human-in-the-loop",
|
||||
"(generated)/logs",
|
||||
"(generated)/usage",
|
||||
"(generated)/audit-logs",
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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' },
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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,
|
||||
tokens: result.tokens || {
|
||||
input: DEFAULTS.TOKENS.PROMPT,
|
||||
output: DEFAULTS.TOKENS.COMPLETION,
|
||||
|
||||
@@ -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}`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user