@@ -36,15 +36,20 @@ import { getRequestContext } from './websockets/request-context'
3636import type { AgentResponseTrace } from '@codebuff/bigquery'
3737import type { CodebuffToolMessage } from '@codebuff/common/tools/list'
3838import type { AgentTemplate } from '@codebuff/common/types/agent-template'
39- import type { Message } from '@codebuff/common/types/messages/codebuff-message'
39+ import type {
40+ AssistantMessage ,
41+ Message ,
42+ } from '@codebuff/common/types/messages/codebuff-message'
4043import type { ToolResultPart } from '@codebuff/common/types/messages/content-part'
4144import type { PrintModeEvent } from '@codebuff/common/types/print-mode'
4245import type {
4346 AgentTemplateType ,
4447 AgentState ,
48+ AgentOutput ,
4549} from '@codebuff/common/types/session-state'
4650import type { ProjectFileContext } from '@codebuff/common/util/file'
4751import type { WebSocket } from 'ws'
52+ import { getErrorObject } from '@codebuff/common/util/error'
4853
4954export interface AgentOptions {
5055 userId : string | undefined
@@ -473,7 +478,10 @@ export const loopAgentSteps = async (
473478 clientSessionId : string
474479 onResponseChunk : ( chunk : string | PrintModeEvent ) => void
475480 } ,
476- ) => {
481+ ) : Promise < {
482+ agentState : AgentState
483+ output : AgentOutput
484+ } > => {
477485 const agentTemplate = await getAgentTemplate ( agentType , localAgentTemplates )
478486 if ( ! agentTemplate ) {
479487 throw new Error ( `Agent template not found for type: ${ agentType } ` )
@@ -539,7 +547,7 @@ export const loopAgentSteps = async (
539547 } ,
540548 )
541549
542- let currentAgentState = {
550+ let currentAgentState : AgentState = {
543551 ...agentState ,
544552 messageHistory : initialMessages ,
545553 }
@@ -584,15 +592,7 @@ export const loopAgentSteps = async (
584592
585593 // End turn if programmatic step ended turn, or if the previous runAgentStep ended turn
586594 if ( shouldEndTurn ) {
587- if ( clearUserPromptMessagesAfterResponse ) {
588- currentAgentState . messageHistory = expireMessages (
589- currentAgentState . messageHistory ,
590- 'userPrompt' ,
591- )
592- }
593- return {
594- agentState : currentAgentState ,
595- }
595+ break
596596 }
597597
598598 const { agentState : newAgentState , shouldEndTurn : llmShouldEndTurn } =
@@ -623,19 +623,67 @@ export const loopAgentSteps = async (
623623 'userPrompt' ,
624624 )
625625 }
626- return { agentState : currentAgentState }
626+
627+ return {
628+ agentState : currentAgentState ,
629+ output : getAgentOutput ( currentAgentState , agentTemplate ) ,
630+ }
627631 } catch ( error ) {
628- // Log the error but still return the state with partial costs
629632 logger . error (
630633 {
631- error,
634+ error : getErrorObject ( error ) ,
632635 agentId : currentAgentState . agentId ,
633636 creditsUsed : currentAgentState . creditsUsed ,
634637 } ,
635- 'Agent execution failed but returning state with partial costs ' ,
638+ 'Agent execution failed' ,
636639 )
637- throw error
638- } finally {
639- // Ensure costs are always captured, even on failure
640+ const errorObject = getErrorObject ( error )
641+ return {
642+ agentState : currentAgentState ,
643+ output : {
644+ type : 'error' ,
645+ message : `${ errorObject . name } : ${ errorObject . message } ${ errorObject . stack ? `\n${ errorObject . stack } ` : '' } ` ,
646+ } ,
647+ }
640648 }
641649}
650+
651+ function getAgentOutput (
652+ agentState : AgentState ,
653+ agentTemplate : AgentTemplate ,
654+ ) : AgentOutput {
655+ if ( agentTemplate . outputMode === 'structured_output' ) {
656+ return {
657+ type : 'structuredOutput' ,
658+ value : agentState . output ?? null ,
659+ }
660+ }
661+ if ( agentTemplate . outputMode === 'last_message' ) {
662+ const assistantMessages = agentState . messageHistory . filter (
663+ ( message ) : message is AssistantMessage => message . role === 'assistant' ,
664+ )
665+ const lastAssistantMessage = assistantMessages [ assistantMessages . length - 1 ]
666+ if ( ! lastAssistantMessage ) {
667+ return {
668+ type : 'error' ,
669+ message : 'No response from agent' ,
670+ }
671+ }
672+ return {
673+ type : 'lastMessage' ,
674+ value : lastAssistantMessage . content ,
675+ }
676+ }
677+ if ( agentTemplate . outputMode === 'all_messages' ) {
678+ // Remove the first message, which includes the previous conversation history.
679+ const agentMessages = agentState . messageHistory . slice ( 1 )
680+ return {
681+ type : 'allMessages' ,
682+ value : agentMessages ,
683+ }
684+ }
685+ agentTemplate . outputMode satisfies never
686+ throw new Error (
687+ `Unknown output mode: ${ 'outputMode' in agentTemplate ? agentTemplate . outputMode : 'undefined' } ` ,
688+ )
689+ }
0 commit comments