@@ -30,6 +30,8 @@ type stepExecutionResult struct {
3030// StopCondition defines a function that determines when an agent should stop executing.
3131type StopCondition = func (steps []StepResult ) bool
3232
33+ type responseGenerator = func (ctx context.Context , model LanguageModel , call Call ) (* Response , error )
34+
3335// StepCountIs returns a stop condition that stops after the specified number of steps.
3436func StepCountIs (stepCount int ) StopCondition {
3537 return func (steps []StepResult ) bool {
@@ -304,6 +306,7 @@ type AgentResult struct {
304306// Agent represents an AI agent that can generate responses and stream responses.
305307type Agent interface {
306308 Generate (context.Context , AgentCall ) (* AgentResult , error )
309+ GenerateObject (context.Context , schema.Schema , AgentCall ) (* AgentResult , error )
307310 Stream (context.Context , AgentStreamCall ) (* AgentResult , error )
308311}
309312
@@ -367,13 +370,12 @@ func (a *agent) prepareCall(call AgentCall) AgentCall {
367370 return call
368371}
369372
370- // Generate implements Agent.
371- func (a * agent ) Generate (ctx context.Context , opts AgentCall ) (* AgentResult , error ) {
372- opts = a .prepareCall (opts )
373- initialPrompt , err := a .createPrompt (a .settings .systemPrompt , opts .Prompt , opts .Messages , opts .Files ... )
374- if err != nil {
375- return nil , err
376- }
373+ func (a * agent ) executeLoop (
374+ ctx context.Context ,
375+ initialPrompt Prompt ,
376+ gen responseGenerator ,
377+ opts AgentCall ,
378+ ) ([]StepResult , error ) {
377379 var responseMessages []Message
378380 var steps []StepResult
379381
@@ -446,7 +448,7 @@ func (a *agent) Generate(ctx context.Context, opts AgentCall) (*AgentResult, err
446448 retryOptions .OnRetry = opts .OnRetry
447449 retry := RetryWithExponentialBackoffRespectingRetryHeaders [* Response ](retryOptions )
448450 result , err := retry (ctx , func () (* Response , error ) {
449- return stepModel . Generate (ctx , Call {
451+ return gen (ctx , stepModel , Call {
450452 Prompt : stepInputMessages ,
451453 MaxOutputTokens : opts .MaxOutputTokens ,
452454 Temperature : opts .Temperature ,
@@ -485,7 +487,7 @@ func (a *agent) Generate(ctx context.Context, opts AgentCall) (*AgentResult, err
485487
486488 toolResults , err := a .executeTools (ctx , stepTools , stepExecProviderTools , stepToolCalls , nil )
487489
488- // Build step content with validated tool calls and tool results. // Provider-executed tool calls are kept as-is.
490+ // Build step content with validated tool calls and tool results. Provider-executed tool calls are kept as-is.
489491 stepContent := []Content {}
490492 toolCallIndex := 0
491493 for _ , content := range result .Content {
@@ -528,8 +530,11 @@ func (a *agent) Generate(ctx context.Context, opts AgentCall) (*AgentResult, err
528530 }
529531 }
530532
531- totalUsage := Usage {}
533+ return steps , nil
534+ }
532535
536+ func toAgentResult (steps []StepResult ) * AgentResult {
537+ totalUsage := Usage {}
533538 for _ , step := range steps {
534539 usage := step .Usage
535540 totalUsage .InputTokens += usage .InputTokens
@@ -540,12 +545,89 @@ func (a *agent) Generate(ctx context.Context, opts AgentCall) (*AgentResult, err
540545 totalUsage .TotalTokens += usage .TotalTokens
541546 }
542547
543- agentResult := & AgentResult {
548+ return & AgentResult {
544549 Steps : steps ,
545550 Response : steps [len (steps )- 1 ].Response ,
546551 TotalUsage : totalUsage ,
547552 }
548- return agentResult , nil
553+ }
554+
555+ // Generate implements Agent.
556+ func (a * agent ) Generate (ctx context.Context , opts AgentCall ) (* AgentResult , error ) {
557+ opts = a .prepareCall (opts )
558+ initialPrompt , err := a .createPrompt (a .settings .systemPrompt , opts .Prompt , opts .Messages , opts .Files ... )
559+ if err != nil {
560+ return nil , err
561+ }
562+ steps , err := a .executeLoop (
563+ ctx ,
564+ initialPrompt ,
565+ func (ctx context.Context , stepModel LanguageModel , call Call ) (* Response , error ) {
566+ return stepModel .Generate (ctx , call )
567+ },
568+ opts ,
569+ )
570+ if err != nil {
571+ return nil , err
572+ }
573+
574+ return toAgentResult (steps ), nil
575+ }
576+
577+ func (a * agent ) GenerateObject (ctx context.Context , s schema.Schema , opts AgentCall ) (* AgentResult , error ) {
578+ opts = a .prepareCall (opts )
579+ initialPrompt , err := a .createPrompt (a .settings .systemPrompt , opts .Prompt , opts .Messages , opts .Files ... )
580+ if err != nil {
581+ return nil , err
582+ }
583+
584+ steps , err := a .executeLoop (
585+ ctx ,
586+ initialPrompt ,
587+ func (ctx context.Context , model LanguageModel , call Call ) (* Response , error ) {
588+ res , err := model .GenerateObject (ctx , ObjectCall {
589+ Prompt : call .Prompt ,
590+ Schema : s ,
591+ MaxOutputTokens : call .MaxOutputTokens ,
592+ Temperature : call .Temperature ,
593+ TopP : call .TopP ,
594+ TopK : call .TopK ,
595+ PresencePenalty : call .PresencePenalty ,
596+ FrequencyPenalty : call .FrequencyPenalty ,
597+ UserAgent : call .UserAgent ,
598+ ProviderOptions : call .ProviderOptions ,
599+ RepairText : nil ,
600+ Tools : call .Tools ,
601+ ToolChoice : call .ToolChoice ,
602+ })
603+ if err != nil {
604+ return nil , err
605+ }
606+
607+ var content ResponseContent
608+ for _ , toolCall := range res .ToolCalls {
609+ content = append (content , toolCall )
610+ }
611+
612+ if res .RawText != "" {
613+ content = append (content , TextContent {Text : res .RawText })
614+ }
615+
616+ return & Response {
617+ Content : content ,
618+ FinishReason : res .FinishReason ,
619+ Usage : res .Usage ,
620+ Warnings : res .Warnings ,
621+ ProviderMetadata : res .ProviderMetadata ,
622+ }, nil
623+ },
624+ opts ,
625+ )
626+ if err != nil {
627+ return nil , err
628+ }
629+
630+ return toAgentResult (steps ), nil
549631}
550632
551633func isStopConditionMet (conditions []StopCondition , steps []StepResult ) bool {
0 commit comments