@@ -94,26 +94,9 @@ func (p *REPLPool) Stats() (poolSize, totalCreated int) {
9494 return len (p .pool ), p .created
9595}
9696
97- // interpreterPool is a simple sync.Pool for basic interpreter reuse.
98- // Note: Due to Yaegi limitations, interpreters can't be fully reset,
99- // so this primarily helps with pre-warming the GC and memory allocation.
100- var interpreterPool = sync.Pool {
101- New : func () interface {} {
102- stdout := new (bytes.Buffer )
103- stderr := new (bytes.Buffer )
104-
105- i := interp .New (interp.Options {
106- Stdout : stdout ,
107- Stderr : stderr ,
108- })
109-
110- if err := i .Use (stdlib .Symbols ); err != nil {
111- panic (fmt .Sprintf ("failed to load stdlib: %v" , err ))
112- }
113-
114- return i
115- },
116- }
97+ // Note: Yaegi interpreters cannot be reset to a clean state, so traditional
98+ // pooling (reusing the same interpreter across requests) is not possible.
99+ // See REPLPool for a pre-creation approach that helps with startup latency.
117100
118101// QueryResponse contains the LLM response with usage metadata.
119102type QueryResponse struct {
@@ -205,49 +188,13 @@ func New(client LLMClient, opts ...REPLOption) *REPL {
205188 return r
206189}
207190
208- // NewPooled creates a new REPL instance using the interpreter pool.
209- // This eliminates the 10-50ms startup overhead per REPL instance.
210- // Call Close() when done to return the interpreter to the pool.
191+ // NewPooled creates a new REPL instance with pooling flags set.
192+ // Note: Due to Yaegi interpreter limitations (can't be reset to clean state),
193+ // this function simply creates a fresh REPL each time. The pooling flags are
194+ // preserved for compatibility, but actual interpreter reuse is not possible.
195+ // Consider using REPLPool for pre-created REPL instances if startup time matters.
211196func NewPooled (client LLMClient ) * REPL {
212- stdout := new (bytes.Buffer )
213- stderr := new (bytes.Buffer )
214-
215- // Get interpreter from pool (will be created if pool is empty)
216- pooledInterp := interpreterPool .Get ().(* interp.Interpreter )
217-
218- // Create a new interpreter with fresh buffers
219- // Note: We can't reuse the pooled interpreter's buffers as they may contain stale data
220- // and we can't safely redirect them. Instead, we create a fresh interpreter.
221- i := interp .New (interp.Options {
222- Stdout : stdout ,
223- Stderr : stderr ,
224- })
225-
226- // Load standard library
227- if err := i .Use (stdlib .Symbols ); err != nil {
228- panic (fmt .Sprintf ("failed to load stdlib: %v" , err ))
229- }
230-
231- // Return the pooled interpreter since we can't fully reuse it
232- interpreterPool .Put (pooledInterp )
233-
234- r := & REPL {
235- interp : i ,
236- stdout : stdout ,
237- stderr : stderr ,
238- llmClient : client ,
239- ctx : context .Background (),
240- fromPool : true ,
241- usePooling : true ,
242- asyncQueries : make (map [string ]* AsyncQueryHandle ),
243- }
244-
245- // Inject RLM functions
246- if err := r .injectBuiltins (); err != nil {
247- panic (fmt .Sprintf ("failed to inject builtins: %v" , err ))
248- }
249-
250- return r
197+ return New (client , WithPooling (true ))
251198}
252199
253200// Close releases resources and returns the interpreter to the pool if applicable.
0 commit comments