MCPcopy
hub / github.com/opactorai/Claudable / POST

Function POST

app/api/chat/[project_id]/act/route.ts:231–470  ·  view source on GitHub ↗
(request: NextRequest, { params }: RouteContext)

Source from the content-addressed store, hash-verified

229 * Execute AI command
230 */
231export async function POST(request: NextRequest, { params }: RouteContext) {
232 try {
233 const { project_id } = await params;
234 const rawBody = await request.json().catch(() => ({}));
235 const body = (rawBody && typeof rawBody === 'object' ? rawBody : {}) as ChatActRequest &
236 Record<string, unknown>;
237
238 const project = await getProjectById(project_id);
239 if (!project) {
240 return NextResponse.json(
241 { success: false, error: 'Project not found' },
242 { status: 404 },
243 );
244 }
245
246 const legacyBody = body as Record<string, unknown>;
247 const projectRoot = resolveProjectRoot(project_id, project.repoPath);
248 const rawInstruction = typeof body.instruction === 'string' ? body.instruction : '';
249 const instructionWithoutLegacyPaths = rawInstruction.replace(/\n*Image #\d+ path: [^\n]+/g, '').trim();
250
251 const rawImages: RawImageAttachment[] = Array.isArray((body as Record<string, unknown>).images)
252 ? ((body as Record<string, unknown>).images as RawImageAttachment[])
253 : Array.isArray(legacyBody['images'])
254 ? (legacyBody['images'] as RawImageAttachment[])
255 : [];
256
257 const processedImages: { name: string; path: string; url: string; publicUrl?: string }[] = [];
258 for (let index = 0; index < rawImages.length; index += 1) {
259 const normalized = await normalizeImageAttachment(project_id, projectRoot, rawImages[index], index);
260 if (normalized) {
261 processedImages.push(normalized);
262 }
263 }
264
265 const imageLines = processedImages.map((image, idx) => `Image #${idx + 1} path: ${image.path}`);
266 const finalInstruction = [instructionWithoutLegacyPaths, imageLines.join('\n')]
267 .filter((segment) => segment && segment.trim().length > 0)
268 .join('\n\n')
269 .trim();
270
271 if (!finalInstruction) {
272 return NextResponse.json(
273 { success: false, error: 'instruction or images are required' },
274 { status: 400 },
275 );
276 }
277
278 const cliPreferenceRaw =
279 coerceString((body as Record<string, unknown>).cliPreference) ??
280 coerceString(legacyBody['cli_preference']) ??
281 project.preferredCli ??
282 'claude';
283 const cliPreference = cliPreferenceRaw.toLowerCase();
284
285 const selectedModelRaw =
286 coerceString(body.selectedModel) ??
287 coerceString(legacyBody['selected_model']) ??
288 project.selectedModel ??

Callers

nothing calls this directly

Calls 15

getProjectByIdFunction · 0.90
getDefaultModelForCliFunction · 0.90
normalizeModelIdFunction · 0.90
generateProjectIdFunction · 0.90
createMessageFunction · 0.90
upsertUserRequestFunction · 0.90
serializeMessageFunction · 0.90
updateProjectActivityFunction · 0.90
updateProjectFunction · 0.90
resolveProjectRootFunction · 0.85
normalizeImageAttachmentFunction · 0.85

Tested by

no test coverage detected