package core import ( "context" "errors" "testing" "ragflow/internal/harness/core/schema" ) // ---- Handler/middleware lifecycle tests ---- func TestBaseMiddleware_AllMethods(t *testing.T) { var b BaseMiddleware[*schema.Message] rc := &ReActAgentContext{} s := NewReActAgentState([]*schema.Message{}, nil, 10) mc := &ModelContext{} ctx, rc2, err := b.BeforeAgent(context.Background(), rc) if err != nil { t.Fatalf("BeforeAgent: %v", err) } if rc2 == nil { t.Error("nil rc returned") } _ = ctx ctx, err = b.AfterAgent(context.Background(), s) if err != nil { t.Fatalf("AfterAgent: %v", err) } _ = ctx ctx, s2, err := b.BeforeModelRewrite(context.Background(), s, mc) if err != nil { t.Fatalf("BeforeModelRewrite: %v", err) } if s2 == nil { t.Error("nil state returned") } _ = ctx ctx, s3, err := b.AfterModelRewrite(context.Background(), s, mc) if err != nil { t.Fatalf("AfterModelRewrite: %v", err) } if s3 == nil { t.Error("nil state returned") } _ = ctx m, err := b.WrapModel(context.Background(), nil, nil) if err != nil { t.Fatalf("WrapModel: %v", err) } if m != nil { _ = m } } func TestMiddleware_BeforeAgentCanModifyInstruction(t *testing.T) { mw := &testMiddleware{} mw.beforeAgent = func(ctx context.Context, rc *ReActAgentContext) (context.Context, *ReActAgentContext, error) { rc.Instruction = "MODIFIED: " + rc.Instruction return ctx, rc, nil } model := &mockModel{} model.addResp("modified") agent := NewReActAgent(&ReActConfig[*schema.Message]{ Model: model, Middlewares: []ReActMiddleware{mw}, }) agent.name = "mod_agent" iter := agent.Run(context.Background(), &AgentInput{ Messages: []Message{schema.UserMessage("test")}, }) for { ev, ok := iter.Next() if !ok { break } _ = ev } } func TestMiddleware_BeforeModelRewriteCanModifyState(t *testing.T) { mw := &testMiddleware{} mw.beforeModel = func(ctx context.Context, state *ReActAgentState, mc *ModelContext) (context.Context, *ReActAgentState, error) { state.RemainingIterations = 1 // force stop after 1 iteration return ctx, state, nil } model := &mockModel{} model.addResp("bmr-test") agent := NewReActAgent(&ReActConfig[*schema.Message]{ Model: model, Middlewares: []ReActMiddleware{mw}, }) agent.name = "bmr_agent" iter := agent.Run(context.Background(), &AgentInput{ Messages: []Message{schema.UserMessage("test")}, }) for { ev, ok := iter.Next() if !ok { break } _ = ev } } func TestMiddleware_AfterModelRewriteModifiesState(t *testing.T) { mw := &testMiddleware{} mw.afterModel = func(ctx context.Context, state *ReActAgentState, mc *ModelContext) (context.Context, *ReActAgentState, error) { if len(state.Messages) > 0 { state.Messages[len(state.Messages)-1] = schema.ToolMessage("rewritten", "call_override") } return ctx, state, nil } model := &mockModel{} model.addResp("original") agent := NewReActAgent(&ReActConfig[*schema.Message]{ Model: model, Middlewares: []ReActMiddleware{mw}, }) agent.name = "amr_agent" iter := agent.Run(context.Background(), &AgentInput{ Messages: []Message{schema.UserMessage("test")}, }) for { ev, ok := iter.Next() if !ok { break } _ = ev } } func TestMiddleware_MultipleMiddlewares(t *testing.T) { var order []string mw1 := &testMiddleware{} mw1.beforeAgent = func(ctx context.Context, rc *ReActAgentContext) (context.Context, *ReActAgentContext, error) { order = append(order, "mw1.BeforeAgent") return ctx, rc, nil } mw2 := &testMiddleware{} mw2.beforeAgent = func(ctx context.Context, rc *ReActAgentContext) (context.Context, *ReActAgentContext, error) { order = append(order, "mw2.BeforeAgent") return ctx, rc, nil } model := &mockModel{} model.addResp("multi") agent := NewReActAgent(&ReActConfig[*schema.Message]{ Model: model, Middlewares: []ReActMiddleware{mw1, mw2}, }) agent.name = "multi_mw" iter := agent.Run(context.Background(), &AgentInput{ Messages: []Message{schema.UserMessage("test")}, }) for { ev, ok := iter.Next() if !ok { break } _ = ev } if len(order) != 2 { t.Errorf("expected 2 calls, got %d: %v", len(order), order) } } func TestMiddleware_BeforeAgentError(t *testing.T) { expectedErr := errors.New("before agent error") mw := &testMiddleware{} mw.beforeAgent = func(ctx context.Context, rc *ReActAgentContext) (context.Context, *ReActAgentContext, error) { return ctx, nil, expectedErr } model := &mockModel{} agent := NewReActAgent(&ReActConfig[*schema.Message]{ Model: model, Middlewares: []ReActMiddleware{mw}, }) agent.name = "err_before" iter := agent.Run(context.Background(), &AgentInput{ Messages: []Message{schema.UserMessage("test")}, }) var lastErr error for { ev, ok := iter.Next() if !ok { break } if ev.Err != nil { lastErr = ev.Err } } if lastErr == nil { t.Error("expected error from BeforeAgent middleware") } } func TestMiddleware_BeforeModelRewriteError(t *testing.T) { expectedErr := errors.New("before model error") mw := &testMiddleware{} mw.beforeModel = func(ctx context.Context, state *ReActAgentState, mc *ModelContext) (context.Context, *ReActAgentState, error) { return ctx, nil, expectedErr } model := &mockModel{} agent := NewReActAgent(&ReActConfig[*schema.Message]{ Model: model, Middlewares: []ReActMiddleware{mw}, }) agent.name = "err_bmr" iter := agent.Run(context.Background(), &AgentInput{ Messages: []Message{schema.UserMessage("test")}, }) var lastErr error for { ev, ok := iter.Next() if !ok { break } if ev.Err != nil { lastErr = ev.Err } } if lastErr == nil { t.Error("expected error from BeforeModelRewrite middleware") } } func TestMiddleware_AfterModelRewriteError(t *testing.T) { expectedErr := errors.New("after model error") mw := &testMiddleware{} mw.afterModel = func(ctx context.Context, state *ReActAgentState, mc *ModelContext) (context.Context, *ReActAgentState, error) { return ctx, nil, expectedErr } model := &mockModel{} agent := NewReActAgent(&ReActConfig[*schema.Message]{ Model: model, Middlewares: []ReActMiddleware{mw}, }) agent.name = "err_amr" iter := agent.Run(context.Background(), &AgentInput{ Messages: []Message{schema.UserMessage("test")}, }) var lastErr error for { ev, ok := iter.Next() if !ok { break } if ev.Err != nil { lastErr = ev.Err } } if lastErr == nil { t.Error("expected error from AfterModelRewrite middleware") } } func TestMiddleware_AfterAgentError(t *testing.T) { expectedErr := errors.New("after agent error") mw := &testMiddleware{} mw.afterAgent = func(ctx context.Context, state *ReActAgentState) (context.Context, error) { return ctx, expectedErr } model := &mockModel{} agent := NewReActAgent(&ReActConfig[*schema.Message]{ Model: model, Middlewares: []ReActMiddleware{mw}, }) agent.name = "err_aa" iter := agent.Run(context.Background(), &AgentInput{ Messages: []Message{schema.UserMessage("test")}, }) var lastErr error for { ev, ok := iter.Next() if !ok { break } if ev.Err != nil { lastErr = ev.Err } } if lastErr == nil { t.Error("expected error from AfterAgent middleware") } } func TestMiddleware_WrapModelReturnsError(t *testing.T) { expectedErr := errors.New("wrap model error") mw := &testMiddleware{} mw.wrapModel = func(ctx context.Context, m Model[*schema.Message], mc *ModelContext) (Model[*schema.Message], error) { return nil, expectedErr } model := &mockModel{} agent := NewReActAgent(&ReActConfig[*schema.Message]{ Model: model, Middlewares: []ReActMiddleware{mw}, }) agent.name = "err_wm" iter := agent.Run(context.Background(), &AgentInput{ Messages: []Message{schema.UserMessage("test")}, }) var lastErr error for { ev, ok := iter.Next() if !ok { break } if ev.Err != nil { lastErr = ev.Err } } if lastErr == nil { t.Error("expected error from WrapModel middleware") } } // ---- Tool integration with middleware chain ----