@@ -19,6 +19,7 @@ import { type NextRequest, NextResponse } from 'next/server'
1919import { validateOAuthAccessToken } from '@/lib/auth/oauth-token'
2020import { getHighestPrioritySubscription } from '@/lib/billing/core/subscription'
2121import { ORCHESTRATION_TIMEOUT_MS , SIM_AGENT_API_URL } from '@/lib/copilot/constants'
22+ import { orchestrateCopilotStream } from '@/lib/copilot/orchestrator'
2223import { orchestrateSubagentStream } from '@/lib/copilot/orchestrator/subagent'
2324import {
2425 executeToolServerSide ,
@@ -28,6 +29,10 @@ import { DIRECT_TOOL_DEFS, SUBAGENT_TOOL_DEFS } from '@/lib/copilot/tools/mcp/de
2829import { env } from '@/lib/core/config/env'
2930import { RateLimiter } from '@/lib/core/rate-limiter'
3031import { getBaseUrl } from '@/lib/core/utils/urls'
32+ import {
33+ authorizeWorkflowByWorkspacePermission ,
34+ resolveWorkflowIdForUser ,
35+ } from '@/lib/workflows/utils'
3136
3237const logger = createLogger ( 'CopilotMcpAPI' )
3338const mcpRateLimiter = new RateLimiter ( )
@@ -660,12 +665,110 @@ async function handleDirectToolCall(
660665 }
661666}
662667
668+ /**
669+ * Build mode uses the main chat orchestrator with the 'fast' command instead of
670+ * the subagent endpoint. In Go, 'build' is not a registered subagent — it's a mode
671+ * (ModeFast) on the main chat processor that bypasses subagent orchestration and
672+ * executes all tools directly.
673+ */
674+ async function handleBuildToolCall (
675+ args : Record < string , unknown > ,
676+ userId : string ,
677+ abortSignal ?: AbortSignal
678+ ) : Promise < CallToolResult > {
679+ try {
680+ const requestText = ( args . request as string ) || JSON . stringify ( args )
681+ const workflowId = args . workflowId as string | undefined
682+
683+ const resolved = workflowId
684+ ? await ( async ( ) => {
685+ const authorization = await authorizeWorkflowByWorkspacePermission ( {
686+ workflowId,
687+ userId,
688+ action : 'read' ,
689+ } )
690+ return authorization . allowed ? { workflowId } : null
691+ } ) ( )
692+ : await resolveWorkflowIdForUser ( userId )
693+
694+ if ( ! resolved ?. workflowId ) {
695+ return {
696+ content : [
697+ {
698+ type : 'text' ,
699+ text : JSON . stringify (
700+ {
701+ success : false ,
702+ error : 'workflowId is required for build. Call create_workflow first.' ,
703+ } ,
704+ null ,
705+ 2
706+ ) ,
707+ } ,
708+ ] ,
709+ isError : true ,
710+ }
711+ }
712+
713+ const chatId = randomUUID ( )
714+
715+ const requestPayload = {
716+ message : requestText ,
717+ workflowId : resolved . workflowId ,
718+ userId,
719+ model : DEFAULT_COPILOT_MODEL ,
720+ mode : 'agent' ,
721+ commands : [ 'fast' ] ,
722+ messageId : randomUUID ( ) ,
723+ chatId,
724+ }
725+
726+ const result = await orchestrateCopilotStream ( requestPayload , {
727+ userId,
728+ workflowId : resolved . workflowId ,
729+ chatId,
730+ goRoute : '/api/mcp' ,
731+ autoExecuteTools : true ,
732+ timeout : 300000 ,
733+ interactive : false ,
734+ abortSignal,
735+ } )
736+
737+ const responseData = {
738+ success : result . success ,
739+ content : result . content ,
740+ toolCalls : result . toolCalls ,
741+ error : result . error ,
742+ }
743+
744+ return {
745+ content : [ { type : 'text' , text : JSON . stringify ( responseData , null , 2 ) } ] ,
746+ isError : ! result . success ,
747+ }
748+ } catch ( error ) {
749+ logger . error ( 'Build tool call failed' , { error } )
750+ return {
751+ content : [
752+ {
753+ type : 'text' ,
754+ text : `Build failed: ${ error instanceof Error ? error . message : String ( error ) } ` ,
755+ } ,
756+ ] ,
757+ isError : true ,
758+ }
759+ }
760+ }
761+
663762async function handleSubagentToolCall (
664763 toolDef : ( typeof SUBAGENT_TOOL_DEFS ) [ number ] ,
665764 args : Record < string , unknown > ,
666765 userId : string ,
667766 abortSignal ?: AbortSignal
668767) : Promise < CallToolResult > {
768+ if ( toolDef . agentId === 'build' ) {
769+ return handleBuildToolCall ( args , userId , abortSignal )
770+ }
771+
669772 try {
670773 const requestText =
671774 ( args . request as string ) ||
0 commit comments