@@ -21,23 +21,60 @@ import (
2121 "errors"
2222
2323 "github.com/cloudwego/eino/adk"
24+ "github.com/cloudwego/eino/schema"
2425)
2526
2627type projectEinoAssistantEngine struct {
27- body projectAssistantEngine
28- runner * adk. Runner
28+ body projectEinoAssistantBody
29+ newRunner projectEinoAssistantRunnerFactory
2930}
3031
31- // NewEinoAssistantEngine returns an Eino-backed assistant engine construction
32- // proof. Later stack slices route normal assistant execution through this
33- // runtime.
32+ type projectEinoAssistantBody func (
33+ context.Context ,
34+ projectAssistantRunRequest ,
35+ projectAssistantEventSink ,
36+ ) (projectAssistantRunResult , error )
37+
38+ type projectEinoAssistantRunner interface {
39+ Run (context.Context , []adk.Message , ... adk.AgentRunOption ) * adk.AsyncIterator [* adk.AgentEvent ]
40+ }
41+
42+ type projectEinoAssistantRunnerFactory func (context.Context , adk.Agent ) projectEinoAssistantRunner
43+
44+ // NewEinoAssistantEngine returns the Eino-backed assistant engine. The App
45+ // Studio chat and tool loop runs as the body of an Eino ADK agent so execution
46+ // goes through Eino's runner pipeline.
3447func NewEinoAssistantEngine (server * Server ) projectAssistantEngine {
3548 return projectEinoAssistantEngine {
36- body : projectChatCompletionAssistantEngine { server : server } ,
37- runner : adk . NewRunner ( context . Background (), adk. RunnerConfig { EnableStreaming : true }) ,
49+ body : newProjectEinoAssistantBody ( server ) ,
50+ newRunner : newProjectEinoAssistantRunner ,
3851 }
3952}
4053
54+ func newProjectEinoAssistantBody (server * Server ) projectEinoAssistantBody {
55+ return func (ctx context.Context , req projectAssistantRunRequest , sink projectAssistantEventSink ) (projectAssistantRunResult , error ) {
56+ _ = sink
57+ if server == nil {
58+ return projectAssistantRunResult {}, errors .New ("server is not configured" )
59+ }
60+ if err := ctx .Err (); err != nil {
61+ return projectAssistantRunResult {}, err
62+ }
63+ reply , err := server .runProjectAssistantChatLoop (ctx , req )
64+ if err != nil {
65+ return projectAssistantRunResult {}, err
66+ }
67+ return projectAssistantRunResult {Content : reply }, nil
68+ }
69+ }
70+
71+ func newProjectEinoAssistantRunner (ctx context.Context , agent adk.Agent ) projectEinoAssistantRunner {
72+ return adk .NewRunner (ctx , adk.RunnerConfig {
73+ Agent : agent ,
74+ EnableStreaming : true ,
75+ })
76+ }
77+
4178func (e projectEinoAssistantEngine ) StreamProjectAssistant (
4279 ctx context.Context ,
4380 req projectAssistantRunRequest ,
@@ -46,11 +83,113 @@ func (e projectEinoAssistantEngine) StreamProjectAssistant(
4683 if req .Project == nil {
4784 return projectAssistantRunResult {}, errors .New ("project is required" )
4885 }
49- if e .runner == nil {
50- return projectAssistantRunResult {}, errors .New ("eino runner is not configured" )
51- }
5286 if e .body == nil {
5387 return projectAssistantRunResult {}, errors .New ("assistant body is not configured" )
5488 }
55- return e .body .StreamProjectAssistant (ctx , req , sink )
89+ if e .newRunner == nil {
90+ return projectAssistantRunResult {}, errors .New ("eino runner is not configured" )
91+ }
92+ agent := projectEinoAssistantAgent {
93+ body : e .body ,
94+ req : req ,
95+ sink : sink ,
96+ }
97+ runner := e .newRunner (ctx , agent )
98+ if runner == nil {
99+ return projectAssistantRunResult {}, errors .New ("eino runner is not configured" )
100+ }
101+ iter := runner .Run (ctx , []adk.Message {schema .UserMessage (projectEinoAssistantPrompt (req ))})
102+ if iter == nil {
103+ return projectAssistantRunResult {}, errors .New ("eino runner returned no event stream" )
104+ }
105+ var result projectAssistantRunResult
106+ receivedOutput := false
107+ for {
108+ event , ok := iter .Next ()
109+ if ! ok {
110+ break
111+ }
112+ if event == nil {
113+ continue
114+ }
115+ if event .Err != nil {
116+ return projectAssistantRunResult {}, event .Err
117+ }
118+ if event .Output == nil {
119+ continue
120+ }
121+ if runResult , ok := event .Output .CustomizedOutput .(projectAssistantRunResult ); ok {
122+ result = runResult
123+ receivedOutput = true
124+ continue
125+ }
126+ if event .Output .MessageOutput == nil {
127+ continue
128+ }
129+ msg , err := event .Output .MessageOutput .GetMessage ()
130+ if err != nil {
131+ return projectAssistantRunResult {}, err
132+ }
133+ if msg != nil {
134+ result .Content = msg .Content
135+ receivedOutput = true
136+ }
137+ }
138+ if ! receivedOutput {
139+ return projectAssistantRunResult {}, errors .New ("eino runner completed without assistant output" )
140+ }
141+ return result , nil
142+ }
143+
144+ type projectEinoAssistantAgent struct {
145+ body projectEinoAssistantBody
146+ req projectAssistantRunRequest
147+ sink projectAssistantEventSink
148+ }
149+
150+ func (a projectEinoAssistantAgent ) Name (context.Context ) string {
151+ return "app-studio-project-assistant"
152+ }
153+
154+ func (a projectEinoAssistantAgent ) Description (context.Context ) string {
155+ return "Runs App Studio project assistant turns."
156+ }
157+
158+ func (a projectEinoAssistantAgent ) Run (
159+ ctx context.Context ,
160+ input * adk.AgentInput ,
161+ options ... adk.AgentRunOption ,
162+ ) * adk.AsyncIterator [* adk.AgentEvent ] {
163+ _ = input
164+ _ = options
165+ iter , gen := adk .NewAsyncIteratorPair [* adk.AgentEvent ]()
166+ go func () {
167+ defer gen .Close ()
168+ if a .body == nil {
169+ gen .Send (& adk.AgentEvent {Err : errors .New ("assistant body is not configured" )})
170+ return
171+ }
172+ result , err := a .body (ctx , a .req , a .sink )
173+ if err != nil {
174+ gen .Send (& adk.AgentEvent {Err : err })
175+ return
176+ }
177+ gen .Send (& adk.AgentEvent {
178+ Output : & adk.AgentOutput {
179+ MessageOutput : & adk.MessageVariant {
180+ Message : schema .AssistantMessage (result .Content , nil ),
181+ Role : schema .Assistant ,
182+ },
183+ CustomizedOutput : result ,
184+ },
185+ })
186+ }()
187+ return iter
188+ }
189+
190+ func projectEinoAssistantPrompt (req projectAssistantRunRequest ) string {
191+ if req .Project != nil && req .Project .Name != "" {
192+ return "Run the App Studio project assistant for " + req .Project .Name + "."
193+ }
194+ return "Run the App Studio project assistant."
56195}
0 commit comments