11"use server" ;
22import { ChatOpenAI } from "@langchain/openai" ;
3- import { ChatPromptTemplate , HumanMessagePromptTemplate , MessagesPlaceholder , PromptTemplate } from "@langchain/core/prompts" ;
4- import { architectureModificationPrompt , BASE_DEVILDEV_AGENT_PROMPT , DevilDevAgentAfterInterviewRole , DevilDevAgentBeforeInterviewRole } from "../prompts/dev/Chatbot" ;
3+ import { ChatPromptTemplate , HumanMessagePromptTemplate , MessagesPlaceholder } from "@langchain/core/prompts" ;
4+ import { architectureModificationAgentPrompt , BASE_DEVILDEV_AGENT_PROMPT , DevilDevAgentAfterInterviewRole , DevilDevAgentBeforeInterviewRole } from "../prompts/dev/Chatbot" ;
55import { deductCredits , getCredits } from "./credits" ;
66import { minSoulsToSendMessage } from "../Limits" ;
7- import { extractTextContent } from "@/lib/ai/extractTextContent" ;
87import { interviewTool } from "../tools/ptoA-tools/interview" ;
98import { generalResTool } from "../tools/ptoA-tools/general_res" ;
109import { AgentExecutor , createToolCallingAgent } from "langchain/agents" ;
1110import { TokenUsageCallbackHandler } from "../common/TokenUsageHandler" ;
1211import { TERMINATING_TOOLS , TerminatingTools } from "../types/pToA/tools" ;
1312import { tier1Tool } from "../tools/ptoA-tools/tier-1" ;
1413import { tier2Tool } from "../tools/ptoA-tools/tier-2" ;
14+ import { updateArchitectureTool } from "../tools/ptoA-tools/update_architecture" ;
15+ import { DynamicStructuredTool } from "langchain/tools" ;
16+ import { z } from "zod" ;
1517
1618// Return type for agent flow functions
1719export type AgentFlowResult = {
@@ -132,49 +134,96 @@ export async function chatbot(userInput: string, conversationHistory: any[] = []
132134
133135export async function architectureModificationBot ( userInput : string , conversationHistory : any [ ] = [ ] , architectureData : any , userId : string | null = null ) {
134136 // Check credits before running the agent
135- if ( userId ) {
137+ if ( userId ) {
136138 const creditsResult = await getCredits ( userId ) ;
137139 if ( creditsResult . success && creditsResult . credits !== undefined && creditsResult . credits < minSoulsToSendMessage ) {
138140 return { error : 'INSUFFICIENT_CREDITS' , remainingCredits : creditsResult . credits } ;
139141 }
140142 }
141143
142- const template = architectureModificationPrompt ;
143-
144144 // Format conversation history for the prompt
145- const formattedHistory = conversationHistory . map ( msg =>
145+ const formattedHistory = conversationHistory . map ( msg =>
146146 `${ msg . type === 'user' ? 'User' : 'Assistant' } : ${ msg . content } `
147147 ) . join ( '\n' ) ;
148148
149- const prompt = PromptTemplate . fromTemplate ( template ) ;
150- const chain = prompt . pipe ( llm ) ;
151- const result = await chain . invoke ( {
152- userInput : userInput ,
153- conversationHistory : formattedHistory ,
154- architecture_data : JSON . stringify ( architectureData )
149+ const get_architecture = new DynamicStructuredTool ( {
150+ name : "get_architecture" ,
151+ description :
152+ "Use this when you need to inspect the current architecture. It returns the full architecture JSON as a string. This does NOT close the agent." ,
153+ schema : z . object ( { } ) ,
154+ func : async ( ) : Promise < string > => {
155+ return JSON . stringify ( architectureData ) ;
156+ } ,
155157 } ) ;
156-
157- // Extract text content - handle both string and complex content types
158- const textContent = extractTextContent ( result . content ) ;
159-
160- // Deduct credits if userId is provided
158+
159+ const tools = [ get_architecture , generalResTool , interviewTool , updateArchitectureTool ] ;
160+
161+ const prompt = ChatPromptTemplate . fromMessages ( [
162+ [ "system" , architectureModificationAgentPrompt ] ,
163+ HumanMessagePromptTemplate . fromTemplate ( "{userInput}" ) ,
164+ new MessagesPlaceholder ( "agent_scratchpad" ) ,
165+ ] ) ;
166+
167+ const agent = await createToolCallingAgent ( { llm, tools, prompt } ) ;
168+
169+ const agentExecutor = new AgentExecutor ( {
170+ agent,
171+ tools,
172+ verbose : true ,
173+ maxIterations : 10 ,
174+ } ) ;
175+
176+ const inputs = {
177+ userInput,
178+ conversationHistory : formattedHistory ,
179+ } ;
180+
181+ const tokenUsageHandler = new TokenUsageCallbackHandler ( ) ;
182+
183+ const stream = ( agentExecutor as any ) . _streamIterator ( inputs , { callbacks : [ tokenUsageHandler ] } ) ;
184+
185+ let result : { output ?: string ; terminatingTool ?: TerminatingTools } | undefined ;
186+
187+ for await ( const step of stream ) {
188+ if ( ! step ) continue ;
189+
190+ if ( step . output !== undefined ) {
191+ result = { output : step . output , terminatingTool : step . terminatingTool } ;
192+ break ;
193+ }
194+
195+ const steps = step . intermediateSteps as Array < { action : { tool : string } ; observation : string } > | undefined ;
196+ if ( steps ?. length ) {
197+ const last = steps [ steps . length - 1 ] ;
198+ const toolName = last ?. action ?. tool ?. toLowerCase ( ) ;
199+ if ( toolName && TERMINATING_TOOLS . has ( toolName ) ) {
200+ result = { output : last . observation , terminatingTool : toolName as TerminatingTools } ;
201+ break ;
202+ }
203+ }
204+ }
205+
206+ console . log ( "architectureModificationBot result:" , result ) ;
207+ const tokenUsage = tokenUsageHandler . getUsage ( ) ;
208+
161209 if ( userId ) {
162- const inputTokens = result . usage_metadata ?. input_tokens ?? 0 ;
163- const outputTokens = result . usage_metadata ?. output_tokens ?? 0 ;
164-
165- const creditResult = await deductCredits ( userId , inputTokens , outputTokens ) ;
210+ const inputTokens = tokenUsage . inputTokens ;
211+ const outputTokens = tokenUsage . outputTokens ;
212+
213+ const creditResult = await deductCredits ( userId , inputTokens , outputTokens , true ) ;
166214 if ( ! creditResult . success ) {
167215 console . error ( "Failed to deduct credits:" , creditResult . error ) ;
168- return { textContent } ;
216+ return { response : result ?. output , terminatingTool : result ?. terminatingTool } ;
169217 } else {
170218 console . log ( `Credits deducted: ${ creditResult . deducted } , remaining: ${ creditResult . remaining } ` ) ;
171219 return {
172- textContent,
220+ response : result ?. output ,
221+ terminatingTool : result ?. terminatingTool ,
173222 remainingCredits : creditResult . remaining ,
174223 deducted : creditResult . deducted
175224 } ;
176225 }
177226 }
178-
179- return { textContent } ;
227+
228+ return { response : result ?. output , terminatingTool : result ?. terminatingTool } ;
180229}
0 commit comments