mirror of
https://github.com/simstudioai/sim.git
synced 2026-02-15 00:44:56 -05:00
* v0 * v1 * Basic ss tes * Ss tests * Stuff * Add mcp * mcp v1 * Improvement * Fix * BROKEN * Checkpoint * Streaming * Fix abort * Things are broken * Streaming seems to work but copilot is dumb * Fix edge issue * LUAAAA * Fix stream buffer * Fix lint * Checkpoint * Initial temp state, in the middle of a refactor * Initial test shows diff store still working * Tool refactor * First cleanup pass complete - untested * Continued cleanup * Refactor * Refactor complete - no testing yet * Fix - cursor makes me sad * Fix mcp * Clean up mcp * Updated mcp * Add respond to subagents * Fix definitions * Add tools * Add tools * Add copilot mcp tracking * Fix lint * Fix mcp * Fix * Updates * Clean up mcp * Fix copilot mcp tool names to be sim prefixed * Add opus 4.6 * Fix discovery tool * Fix * Remove logs * Fix go side tool rendering * Update docs * Fix hydration * Fix tool call resolution * Fix * Fix lint * Fix superagent and autoallow integrations * Fix always allow * Update block * Remove plan docs * Fix hardcoded ff * Fix dropped provider * Fix lint * Fix tests * Fix dead messages array * Fix discovery * Fix run workflow * Fix run block * Fix run from block in copilot * Fix lint * Fix skip and mtb * Fix typing * Fix tool call * Bump api version * Fix bun lock * Nuke bad files
125 lines
3.7 KiB
TypeScript
125 lines
3.7 KiB
TypeScript
import { createLogger } from '@sim/logger'
|
|
import { type NextRequest, NextResponse } from 'next/server'
|
|
import { z } from 'zod'
|
|
import { REDIS_TOOL_CALL_PREFIX, REDIS_TOOL_CALL_TTL_SECONDS } from '@/lib/copilot/constants'
|
|
import {
|
|
authenticateCopilotRequestSessionOnly,
|
|
createBadRequestResponse,
|
|
createInternalServerErrorResponse,
|
|
createRequestTracker,
|
|
createUnauthorizedResponse,
|
|
type NotificationStatus,
|
|
} from '@/lib/copilot/request-helpers'
|
|
import { getRedisClient } from '@/lib/core/config/redis'
|
|
|
|
const logger = createLogger('CopilotConfirmAPI')
|
|
|
|
// Schema for confirmation request
|
|
const ConfirmationSchema = z.object({
|
|
toolCallId: z.string().min(1, 'Tool call ID is required'),
|
|
status: z.enum(['success', 'error', 'accepted', 'rejected', 'background'] as const, {
|
|
errorMap: () => ({ message: 'Invalid notification status' }),
|
|
}),
|
|
message: z.string().optional(), // Optional message for background moves or additional context
|
|
})
|
|
|
|
/**
|
|
* Write the user's tool decision to Redis. The server-side orchestrator's
|
|
* waitForToolDecision() polls Redis for this value.
|
|
*/
|
|
async function updateToolCallStatus(
|
|
toolCallId: string,
|
|
status: NotificationStatus,
|
|
message?: string
|
|
): Promise<boolean> {
|
|
const redis = getRedisClient()
|
|
if (!redis) {
|
|
logger.warn('Redis client not available for tool confirmation')
|
|
return false
|
|
}
|
|
|
|
try {
|
|
const key = `${REDIS_TOOL_CALL_PREFIX}${toolCallId}`
|
|
const payload = {
|
|
status,
|
|
message: message || null,
|
|
timestamp: new Date().toISOString(),
|
|
}
|
|
await redis.set(key, JSON.stringify(payload), 'EX', REDIS_TOOL_CALL_TTL_SECONDS)
|
|
return true
|
|
} catch (error) {
|
|
logger.error('Failed to update tool call status', {
|
|
toolCallId,
|
|
status,
|
|
error: error instanceof Error ? error.message : String(error),
|
|
})
|
|
return false
|
|
}
|
|
}
|
|
|
|
/**
|
|
* POST /api/copilot/confirm
|
|
* Update tool call status (Accept/Reject)
|
|
*/
|
|
export async function POST(req: NextRequest) {
|
|
const tracker = createRequestTracker()
|
|
|
|
try {
|
|
// Authenticate user using consolidated helper
|
|
const { userId: authenticatedUserId, isAuthenticated } =
|
|
await authenticateCopilotRequestSessionOnly()
|
|
|
|
if (!isAuthenticated) {
|
|
return createUnauthorizedResponse()
|
|
}
|
|
|
|
const body = await req.json()
|
|
const { toolCallId, status, message } = ConfirmationSchema.parse(body)
|
|
|
|
// Update the tool call status in Redis
|
|
const updated = await updateToolCallStatus(toolCallId, status, message)
|
|
|
|
if (!updated) {
|
|
logger.error(`[${tracker.requestId}] Failed to update tool call status`, {
|
|
userId: authenticatedUserId,
|
|
toolCallId,
|
|
status,
|
|
internalStatus: status,
|
|
message,
|
|
})
|
|
return createBadRequestResponse('Failed to update tool call status or tool call not found')
|
|
}
|
|
|
|
const duration = tracker.getDuration()
|
|
|
|
return NextResponse.json({
|
|
success: true,
|
|
message: message || `Tool call ${toolCallId} has been ${status.toLowerCase()}`,
|
|
toolCallId,
|
|
status,
|
|
})
|
|
} catch (error) {
|
|
const duration = tracker.getDuration()
|
|
|
|
if (error instanceof z.ZodError) {
|
|
logger.error(`[${tracker.requestId}] Request validation error:`, {
|
|
duration,
|
|
errors: error.errors,
|
|
})
|
|
return createBadRequestResponse(
|
|
`Invalid request data: ${error.errors.map((e) => e.message).join(', ')}`
|
|
)
|
|
}
|
|
|
|
logger.error(`[${tracker.requestId}] Unexpected error:`, {
|
|
duration,
|
|
error: error instanceof Error ? error.message : 'Unknown error',
|
|
stack: error instanceof Error ? error.stack : undefined,
|
|
})
|
|
|
|
return createInternalServerErrorResponse(
|
|
error instanceof Error ? error.message : 'Internal server error'
|
|
)
|
|
}
|
|
}
|