Files
langchaingo/agents/executor_test.go
T
Travis Cline c544fb77bd all: add broad httprr coverage, update dependencies, organize go.mod file, bump to 1.23 (#1299)
* all: add broad httprr coverage, update dependencies, organize go.mod file, bump to 1.23

update go version to 1.23
add lots of test coverage via httprr recordings
update dependencies and organize go.mod
add testutil/testctr which helps work around a testcontainers-go+colima bug
expand the huggingface implementation and tests
expand capabilities of the ollama package
2025-06-04 11:41:45 -07:00

164 lines
4.2 KiB
Go

package agents_test
import (
"context"
"net/http"
"strings"
"testing"
"github.com/stretchr/testify/require"
"github.com/tmc/langchaingo/agents"
"github.com/tmc/langchaingo/chains"
"github.com/tmc/langchaingo/internal/httprr"
"github.com/tmc/langchaingo/llms/openai"
"github.com/tmc/langchaingo/prompts"
"github.com/tmc/langchaingo/schema"
"github.com/tmc/langchaingo/tools"
"github.com/tmc/langchaingo/tools/serpapi"
)
type testAgent struct {
actions []schema.AgentAction
finish *schema.AgentFinish
err error
inputKeys []string
outputKeys []string
recordedIntermediateSteps []schema.AgentStep
recordedInputs map[string]string
numPlanCalls int
}
func (a *testAgent) Plan(
_ context.Context,
intermediateSteps []schema.AgentStep,
inputs map[string]string,
) ([]schema.AgentAction, *schema.AgentFinish, error) {
a.recordedIntermediateSteps = intermediateSteps
a.recordedInputs = inputs
a.numPlanCalls++
return a.actions, a.finish, a.err
}
func (a testAgent) GetInputKeys() []string {
return a.inputKeys
}
func (a testAgent) GetOutputKeys() []string {
return a.outputKeys
}
func (a *testAgent) GetTools() []tools.Tool {
return nil
}
func TestExecutorWithErrorHandler(t *testing.T) {
t.Parallel()
ctx := context.Background()
a := &testAgent{
err: agents.ErrUnableToParseOutput,
}
executor := agents.NewExecutor(
a,
agents.WithMaxIterations(3),
agents.WithParserErrorHandler(agents.NewParserErrorHandler(nil)),
)
_, err := chains.Call(ctx, executor, nil)
require.ErrorIs(t, err, agents.ErrNotFinished)
require.Equal(t, 3, a.numPlanCalls)
require.Equal(t, []schema.AgentStep{
{Observation: agents.ErrUnableToParseOutput.Error()},
{Observation: agents.ErrUnableToParseOutput.Error()},
}, a.recordedIntermediateSteps)
}
func TestExecutorWithMRKLAgent(t *testing.T) {
t.Parallel()
ctx := context.Background()
httprr.SkipIfNoCredentialsAndRecordingMissing(t, "OPENAI_API_KEY")
httprr.SkipIfNoCredentialsAndRecordingMissing(t, "SERPAPI_API_KEY")
rr := httprr.OpenForTest(t, http.DefaultTransport)
t.Cleanup(func() { rr.Close() })
// Configure OpenAI client with httprr
opts := []openai.Option{
openai.WithModel("gpt-4"),
openai.WithHTTPClient(rr.Client()),
}
// httprr handles credentials automatically
llm, err := openai.New(opts...)
require.NoError(t, err)
searchTool, err := serpapi.New(serpapi.WithHTTPClient(rr.Client()))
require.NoError(t, err)
calculator := tools.Calculator{}
a, err := agents.Initialize(
llm,
[]tools.Tool{searchTool, calculator},
agents.ZeroShotReactDescription,
)
require.NoError(t, err)
result, err := chains.Run(ctx, a, "What is 5 plus 3? Please calculate this.") //nolint:lll
require.NoError(t, err)
t.Logf("MRKL Agent response: %s", result)
// Simple calculation: 5 + 3 = 8
require.True(t, strings.Contains(result, "8"), "expected calculation result 8 in response")
}
func TestExecutorWithOpenAIFunctionAgent(t *testing.T) {
t.Parallel()
ctx := context.Background()
httprr.SkipIfNoCredentialsAndRecordingMissing(t, "OPENAI_API_KEY")
httprr.SkipIfNoCredentialsAndRecordingMissing(t, "SERPAPI_API_KEY")
rr := httprr.OpenForTest(t, http.DefaultTransport)
t.Cleanup(func() { rr.Close() })
// Configure OpenAI client with httprr
opts := []openai.Option{
openai.WithModel("gpt-4"),
openai.WithHTTPClient(rr.Client()),
}
// httprr handles credentials automatically
llm, err := openai.New(opts...)
require.NoError(t, err)
searchTool, err := serpapi.New(serpapi.WithHTTPClient(rr.Client()))
require.NoError(t, err)
calculator := tools.Calculator{}
toolList := []tools.Tool{searchTool, calculator}
a := agents.NewOpenAIFunctionsAgent(llm,
toolList,
agents.NewOpenAIOption().WithSystemMessage("you are a helpful assistant"),
agents.NewOpenAIOption().WithExtraMessages([]prompts.MessageFormatter{
prompts.NewHumanMessagePromptTemplate("please be strict", nil),
}),
)
e := agents.NewExecutor(a)
require.NoError(t, err)
result, err := chains.Run(ctx, e, "when was the Go programming language tagged version 1.0?") //nolint:lll
require.NoError(t, err)
t.Logf("Result: %s", result)
require.True(t, strings.Contains(result, "2012") || strings.Contains(result, "March"),
"correct answer 2012 or March not in response")
}