Repository: tmc/langchaingo
Pull request #123 (2023-06-12 19:38:53)

tools: add wikipedia
This adds the wikipedia tool.
https://github.com/hwchase17/langchain/blob/master/langchain/tools/wikipedia/tool.py

### PR Checklist

- [x] Read the [Contributing documentation](https://github.com/tmc/langchaingo/blob/main/CONTRIBUTING.md).
- [x] Read the [Code of conduct documentation](https://github.com/tmc/langchaingo/blob/main/CODE_OF_CONDUCT.md).
- [x] Name your Pull Request title clearly, concisely, and prefixed with the name of primarily affected package you changed according to [Good commit messages](https://go.dev/doc/contribute#commit_messages) (such as `memory: add interfaces for X, Y` or `util: add whizzbang helpers`).
- [x] Check that there isn't already a PR that solves the problem the same way to avoid creating a duplicate.
- [x] Provide a description in this PR that addresses **what** the PR is solving, or reference the issue that it solves (e.g. `fixes #123`).
- [x] Describes source of new concepts.
- [x] References existing implementations as appropriate.
- [x] Contains test coverage for new functions.
- [x] Passes all [`golangci-lint`](https://golangci-lint.run/) checks.
- [x]  I am an existing contributor.



Patch:
diff --git a/agents/agents.go b/agents/agents.go
index 24221bff..18bed11f 100644
--- a/agents/agents.go
+++ b/agents/agents.go
@@ -1,3 +1,4 @@
+// Package agents defines the types for langchaingo Agent.
 package agents
 
 import (
diff --git a/agents/doc.go b/agents/doc.go
index 363dc39a..b65a944b 100644
--- a/agents/doc.go
+++ b/agents/doc.go
@@ -1,22 +1,7 @@
-// Package agent contains the standard interface all agents must implement,
-// implementations of this interface, and an agent executor.
+// Package agent contains the standard interface all agents must implement.
 //
 // An Agent is a wrapper around a model, which takes in user input and returns
 // a response corresponding to an “action” to take and a corresponding
 // “action input”. Alternatively the agent can return a finish with the
-// finished answer to the query. This package contains and standard interface
-// for such agents.
-//
-// Package agents provides and implementation of the agent interface called
-// OneShotZeroAgent. This agent uses the ReAct Framework (based on the
-// descriptions of tools) to decide what action to take. This agent is
-// optimized to be used with LLMs.
-//
-// To make agents more powerful we need to make them iterative, ie. call the
-// model multiple times until they arrive at the final answer. That's the job of
-// the Executor. The Executor is an Agent and set of Tools. The agent executor is
-// responsible for calling the agent, getting back and action and action input,
-// calling the tool that the action references with the corresponding input,
-// getting the output of the tool, and then passing all that information back
-// into the Agent to get the next action it should take.
+// finished answer to the query.
 package agents
diff --git a/agents/executor/doc.go b/agents/executor/doc.go
new file mode 100644
index 00000000..ee9818e5
--- /dev/null
+++ b/agents/executor/doc.go
@@ -0,0 +1,21 @@
+// Package executor provides a standard chain for executing agent queries.
+//
+// The Executor is an Agent and set of Tools. The agent executor is
+// responsible for calling the agent, getting back and action and action input,
+// calling the tool that the action references with the corresponding input,
+// getting the output of the tool, and then passing all that information back
+// into the Agent to get the next action it should take.
+//
+// The package also contains functions to initialize executors with agents and
+// supports different agent types and options to customize the agent's behavior.
+//
+// AgentType is a string type representing the type of agent to create.
+// The package currently supports the "zeroShotReactDescription" agent type.
+//
+// Options is a type alias for a map of string keys to any value,
+// representing the options for the agent and the executor.
+//
+// Option is a function type that can be used to modify the Options,
+// such as the WithVerbosity function, which sets the verbosity option
+// for the agent.
+package executor
diff --git a/agents/errors.go b/agents/executor/errors.go
similarity index 68%
rename from agents/errors.go
rename to agents/executor/errors.go
index 917ddbf3..6ee0d077 100644
--- a/agents/errors.go
+++ b/agents/executor/errors.go
@@ -1,4 +1,4 @@
-package agents
+package executor
 
 import "errors"
 
@@ -14,10 +14,4 @@ var (
 	ErrUnknownAgentType = errors.New("unknown agent type")
 	// ErrInvalidOptions is returned if the options given to the initializer is invalid.
 	ErrInvalidOptions = errors.New("invalid options")
-
-	// ErrUnableToParseOutput is returned if the output of the llm is unparsable.
-	ErrUnableToParseOutput = errors.New("unable to parse agent output")
-	// ErrInvalidChainReturnType is returned if the internal chain of the agent eturns a value in the
-	// "text" filed that is not a string.
-	ErrInvalidChainReturnType = errors.New("agent chain did not return a string")
 )
diff --git a/agents/executor.go b/agents/executor/executor.go
similarity index 94%
rename from agents/executor.go
rename to agents/executor/executor.go
index f0969c93..4aae897c 100644
--- a/agents/executor.go
+++ b/agents/executor/executor.go
@@ -1,9 +1,10 @@
-package agents
+package executor
 
 import (
 	"context"
 	"fmt"
 
+	"github.com/tmc/langchaingo/agents"
 	"github.com/tmc/langchaingo/chains"
 	"github.com/tmc/langchaingo/memory"
 	"github.com/tmc/langchaingo/schema"
@@ -12,7 +13,7 @@ import (
 
 // Executor is the chain responsible for running agents.
 type Executor struct {
-	Agent Agent
+	Agent agents.Agent
 	Tools []tools.Tool
 
 	MaxIterations int
@@ -22,7 +23,7 @@ var _ chains.Chain = Executor{}
 
 // New creates a new agent executor with a agent, the tools the agent can use
 // and the max number of iterations.
-func New(agent Agent, tools []tools.Tool, maxIterations int) Executor {
+func New(agent agents.Agent, tools []tools.Tool, maxIterations int) Executor {
 	return Executor{
 		Agent:         agent,
 		Tools:         tools,
diff --git a/agents/executor/initialize.go b/agents/executor/initialize.go
new file mode 100644
index 00000000..e45de890
--- /dev/null
+++ b/agents/executor/initialize.go
@@ -0,0 +1,81 @@
+package executor
+
+import (
+	"github.com/tmc/langchaingo/agents"
+	"github.com/tmc/langchaingo/agents/mrkl"
+	"github.com/tmc/langchaingo/llms"
+	"github.com/tmc/langchaingo/tools"
+)
+
+const _defaultMaxIterations = 5
+
+// AgentType is a string type representing the type of agent to create.
+type AgentType string
+
+const (
+	// ZeroShotReactDescription is an AgentType constant that represents
+	// the "zeroShotReactDescription" agent type.
+	ZeroShotReactDescription AgentType = "zeroShotReactDescription"
+)
+
+// options is a type alias for a map of string keys to any value,
+// representing the options for the agent and the executor.
+type options map[string]any
+
+// Option is a function type that can be used to modify the creation of the
+// executor and agent.
+type Option func(p *options)
+
+func defaultOptions() options {
+	return options{
+		"verbose":       false,
+		"maxIterations": _defaultMaxIterations,
+	}
+}
+
+// WithVerbosity is a function that sets the verbosity option for the agent.
+func WithVerbosity() Option {
+	return func(p *options) {
+		(*p)["verbose"] = true
+	}
+}
+
+// WithMaxIterations is a function that sets the max iterations for the executor.
+func WithMaxIterations(maxIterations int) Option {
+	return func(p *options) {
+		(*p)["maxIterations"] = maxIterations
+	}
+}
+
+// Initialize is a function that creates a new executor with the specified LLM
+// model, tools, agent type, and options. It returns an Executor or an error
+// if there is any issues during the creation process.
+func Initialize(
+	llm llms.LLM,
+	tools []tools.Tool,
+	agentType AgentType,
+	opts ...Option,
+) (Executor, error) {
+	options := defaultOptions()
+	for _, opt := range opts {
+		opt(&options)
+	}
+	maxIterations, ok := options["maxIterations"].(int)
+	if !ok {
+		return Executor{}, ErrInvalidOptions
+	}
+
+	var agent agents.Agent
+	switch agentType {
+	case ZeroShotReactDescription:
+		agent = mrkl.NewOneShotAgent(llm, tools, options)
+	default:
+		return Executor{}, ErrUnknownAgentType
+	}
+
+	return Executor{
+		Agent:         agent,
+		Tools:         tools,
+		MaxIterations: maxIterations,
+	}, nil
+}
diff --git a/agents/initialize.go b/agents/initialize.go
deleted file mode 100644
index 1b4c8a14..00000000
--- a/agents/initialize.go
+++ /dev/null
@@ -1,46 +0,0 @@
-package agents
-
-import (
-	"github.com/tmc/langchaingo/llms"
-	"github.com/tmc/langchaingo/tools"
-)
-
-const _defaultMaxIterations = 5
-
-// AgentType is a string type representing the type of agent to create.
-type AgentType string
-
-const (
-	// ZeroShotReactDescription is an AgentType constant that represents
-	// the "zeroShotReactDescription" agent type.
-	ZeroShotReactDescription AgentType = "zeroShotReactDescription"
-)
-
-// Initialize is a function that creates a new executor with the specified LLM
-// model, tools, agent type, and options. It returns an Executor or an error
-// if there is any issues during the creation process.
-func Initialize(
-	llm llms.LLM,
-	tools []tools.Tool,
-	agentType AgentType,
-	opts ...CreationOption,
-) (Executor, error) {
-	options := executorDefaultOptions()
-	for _, opt := range opts {
-		opt(&options)
-	}
-
-	var agent Agent
-	switch agentType {
-	case ZeroShotReactDescription:
-		agent = NewOneShotAgent(llm, tools, opts...)
-	default:
-		return Executor{}, ErrUnknownAgentType
-	}
-
-	return Executor{
-		Agent:         agent,
-		Tools:         tools,
-		MaxIterations: options.maxIterations,
-	}, nil
-}
diff --git a/agents/mrkl/doc.go b/agents/mrkl/doc.go
new file mode 100644
index 00000000..e6155740
--- /dev/null
+++ b/agents/mrkl/doc.go
@@ -0,0 +1,4 @@
+// Package mrkl provides and implementation of the agent interface that
+// uses the ReAct Framework (based on the descriptions of tools) to
+// decide what action to take. This agent is optimized to be used with LLMs.
+package mrkl
diff --git a/agents/mrkl.go b/agents/mrkl/mrkl.go
similarity index 73%
rename from agents/mrkl.go
rename to agents/mrkl/mrkl.go
index 40f6c335..1ce8a39d 100644
--- a/agents/mrkl.go
+++ b/agents/mrkl/mrkl.go
@@ -1,18 +1,31 @@
-package agents
+package mrkl
 
 import (
 	"context"
+	"errors"
 	"fmt"
 	"regexp"
 	"strings"
 	"time"
 
+	"github.com/tmc/langchaingo/agents"
 	"github.com/tmc/langchaingo/chains"
 	"github.com/tmc/langchaingo/llms"
 	"github.com/tmc/langchaingo/schema"
 	"github.com/tmc/langchaingo/tools"
 )
 
+var (
+	// ErrUnableToParseOutput is returned if the output of the llm is unparsable.
+	ErrUnableToParseOutput = errors.New("unable to parse agent output")
+	// ErrInvalidChainReturnType is returned if the internal chain of the agent
+	// returns a value in the "text" filed that is not a string.
+	ErrInvalidChainReturnType = errors.New("agent chain did not return a string")
+	// ErrInvalidOptions is returned if the options given to the NewOneShotAgent
+	// function is invalid.
+	ErrInvalidOptions = errors.New("options given are invalid")
+)
+
 const (
 	_finalAnswerAction = "Final Answer:"
 	_defaultOutputKey  = "output"
@@ -33,19 +46,31 @@ type OneShotZeroAgent struct {
 	OutputKey string
 }
 
-var _ Agent = (*OneShotZeroAgent)(nil)
+var _ agents.Agent = (*OneShotZeroAgent)(nil)
+
+type OneShotZeroAgentOptions struct {
+	outputKey string
+}
+
+func checkOptions(opts map[string]any) OneShotZeroAgentOptions {
+	options := OneShotZeroAgentOptions{
+		outputKey: _defaultOutputKey,
+	}
+	if outputKey, ok := opts["outputKey"].(string); ok {
+		options.outputKey = outputKey
+	}
+	return options
+}
 
 // NewOneShotAgent creates a new OneShotZeroAgent with the given LLM model, tools,
 // and options. It returns a pointer to the created agent. The opts parameter
-// represents the options for the agent.
-func NewOneShotAgent(llm llms.LLM, tools []tools.Tool, opts ...CreationOption) *OneShotZeroAgent {
-	options := mrklDefaultOptions()
-	for _, opt := range opts {
-		opt(&options)
-	}
+// represents the options for the agent. "outputKey" sets the output key of the
+// agent.
+func NewOneShotAgent(llm llms.LLM, tools []tools.Tool, opts map[string]any) *OneShotZeroAgent {
+	options := checkOptions(opts)
 
 	return &OneShotZeroAgent{
-		Chain:     chains.NewLLMChain(llm, options.getMrklPrompt(tools)),
+		Chain:     chains.NewLLMChain(llm, CreatePrompt(tools)),
 		Tools:     tools,
 		OutputKey: options.outputKey,
 	}
diff --git a/agents/mrkl/prompt.go b/agents/mrkl/prompt.go
new file mode 100644
index 00000000..6e3d9f9b
--- /dev/null
+++ b/agents/mrkl/prompt.go
@@ -0,0 +1,129 @@
+package mrkl
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/tmc/langchaingo/prompts"
+	"github.com/tmc/langchaingo/tools"
+)
+
+const (
+	Prefix = `Today is {{.today}} and you can use tools to get new information.
+Answer the following questions as best you can using the following tools:
+
+{{.tool_descriptions}}`
+
+	FormatInstructions = `Use the following format:
+
+Question: the input question you must answer
+Thought: you should always think about what to do
+Action: the action to take, should be one of [ {{.tool_names}} ]
+Action Input: the input to the action
+Observation: the result of the action
+... (this Thought/Action/Action Input/Observation can repeat N times)
+Thought: I now know the final answer
+Final Answer: the final answer to the original input question`
+
+	Suffix = `Begin!
+
+Question: {{.input}}
+Thought:{{.agent_scratchpad}}`
+)
+
+// CreatePromptOptions is a struct that holds options for creating a prompt template.
+type CreatePromptOptions struct {
+	Prefix             string
+	Suffix             string
+	FormatInstructions string
+	InputVariables     []string
+}
+
+// PromptTemplateOption is a function type that can be used to modify the CreatePromptOptions.
+type PromptTemplateOption func(p *CreatePromptOptions)
+
+// WithPrefix is a function that sets a custom prefix for the prompt template.
+func WithPrefix(prefix string) PromptTemplateOption {
+	return func(p *CreatePromptOptions) {
+		p.Prefix = prefix
+	}
+}
+
+// WithSuffix is a function that sets a custom suffix for the prompt template.
+func WithSuffix(suffix string) PromptTemplateOption {
+	return func(p *CreatePromptOptions) {
+		p.Suffix = suffix
+	}
+}
+
+// WithFormatInstructions is a function that sets custom format instructions for the prompt template.
+func WithFormatInstructions(formatInstructions string) PromptTemplateOption {
+	return func(p *CreatePromptOptions) {
+		p.FormatInstructions = formatInstructions
+	}
+}
+
+// WithInputVariables is a function that sets custom input variables for the prompt template.
+func WithInputVariables(inputVariables []string) PromptTemplateOption {
+	return func(p *CreatePromptOptions) {
+		p.InputVariables = inputVariables
+	}
+}
+
+func (options *CreatePromptOptions) handleDefaultValues() {
+	if options.Prefix == "" {
+		options.Prefix = Prefix
+	}
+
+	if options.Suffix == "" {
+		options.Suffix = Suffix
+	}
+
+	if options.FormatInstructions == "" {
+		options.FormatInstructions = FormatInstructions
+	}
+}
+
+func toolNames(tools []tools.Tool) string {
+	var tn strings.Builder
+	for i, tool := range tools {
+		if i > 0 {
+			tn.WriteString(", ")
+		}
+		tn.WriteString(tool.Name())
+	}
+
+	return tn.String()
+}
+
+func toolDescriptions(tools []tools.Tool) string {
+	var ts strings.Builder
+	for _, tool := range tools {
+		ts.WriteString(fmt.Sprintf("- %s: %s\n", tool.Name(), tool.Description()))
+	}
+
+	return ts.String()
+}
+
+// CreatePrompt is a function that takes a slice of tools and a variadic list of prompt
+// template options, and returns a prompt template used by the agent with the specified
+// options.
+func CreatePrompt(tools []tools.Tool, options ...PromptTemplateOption) prompts.PromptTemplate {
+	opts := &CreatePromptOptions{}
+	for _, option := range options {
+		option(opts)
+	}
+	opts.handleDefaultValues()
+
+	template := strings.Join([]string{opts.Prefix, opts.FormatInstructions, opts.Suffix}, "\n\n")
+
+	return prompts.PromptTemplate{
+		Template:       template,
+		TemplateFormat: prompts.TemplateFormatGoTemplate,
+		InputVariables: []string{"input", "agent_scratchpad", "today"},
+		PartialVariables: map[string]any{
+			"tool_names":        toolNames(tools),
+			"tool_descriptions": toolDescriptions(tools),
+		},
+	}
+}
diff --git a/agents/mrkl_prompt.go b/agents/mrkl_prompt.go
deleted file mode 100644
index bec902bc..00000000
--- a/agents/mrkl_prompt.go
+++ /dev/null
@@ -1,67 +0,0 @@
-package agents
-
-import (
-	"fmt"
-	"strings"
-
-	"github.com/tmc/langchaingo/prompts"
-	"github.com/tmc/langchaingo/tools"
-)
-
-const (
-	_defaultMrklPrefix = `Today is {{.today}} and you can use tools to get new information.
-Answer the following questions as best you can using the following tools:
-
-{{.tool_descriptions}}`
-
-	_defaultMrklFormatInstructions = `Use the following format:
-
-Question: the input question you must answer
-Thought: you should always think about what to do
-Action: the action to take, should be one of [ {{.tool_names}} ]
-Action Input: the input to the action
-Observation: the result of the action
-... (this Thought/Action/Action Input/Observation can repeat N times)
-Thought: I now know the final answer
-Final Answer: the final answer to the original input question`
-
-	_defaultMrklSuffix = `Begin!
-
-Question: {{.input}}
-Thought:{{.agent_scratchpad}}`
-)
-
-func createMRKLPrompt(tools []tools.Tool, prefix, instructions, suffix string) prompts.PromptTemplate {
-	template := strings.Join([]string{prefix, instructions, suffix}, "\n\n")
-
-	return prompts.PromptTemplate{
-		Template:       template,
-		TemplateFormat: prompts.TemplateFormatGoTemplate,
-		InputVariables: []string{"input", "agent_scratchpad", "today"},
-		PartialVariables: map[string]any{
-			"tool_names":        toolNames(tools),
-			"tool_descriptions": toolDescriptions(tools),
-		},
-	}
-}
-
-func toolNames(tools []tools.Tool) string {
-	var tn strings.Builder
-	for i, tool := range tools {
-		if i > 0 {
-			tn.WriteString(", ")
-		}
-		tn.WriteString(tool.Name())
-	}
-
-	return tn.String()
-}
-
-func toolDescriptions(tools []tools.Tool) string {
-	var ts strings.Builder
-	for _, tool := range tools {
-		ts.WriteString(fmt.Sprintf("- %s: %s\n", tool.Name(), tool.Description()))
-	}
-
-	return ts.String()
-}
diff --git a/agents/options.go b/agents/options.go
deleted file mode 100644
index 7aac5291..00000000
--- a/agents/options.go
+++ /dev/null
@@ -1,92 +0,0 @@
-package agents
-
-import (
-	"github.com/tmc/langchaingo/prompts"
-	"github.com/tmc/langchaingo/tools"
-)
-
-type creationOptions struct {
-	maxIterations      int
-	outputKey          string
-	promptPrefix       string
-	formatInstructions string
-	promptSuffix       string
-	prompt             prompts.PromptTemplate
-}
-
-// CreationOption is a function type that can be used to modify the creation of the agents
-// and executors.
-type CreationOption func(*creationOptions)
-
-func (co creationOptions) getMrklPrompt(tools []tools.Tool) prompts.PromptTemplate {
-	if co.prompt.Template != "" {
-		return co.prompt
-	}
-
-	return createMRKLPrompt(
-		tools,
-		co.promptPrefix,
-		co.formatInstructions,
-		co.promptSuffix,
-	)
-}
-
-func executorDefaultOptions() creationOptions {
-	return creationOptions{
-		maxIterations: _defaultMaxIterations,
-		outputKey:     _defaultOutputKey,
-	}
-}
-
-func mrklDefaultOptions() creationOptions {
-	return creationOptions{
-		promptPrefix:       _defaultMrklPrefix,
-		formatInstructions: _defaultMrklFormatInstructions,
-		promptSuffix:       _defaultMrklSuffix,
-		outputKey:          _defaultOutputKey,
-	}
-}
-
-// WithMaxIterations is an option for setting the max number of iterations the executor
-// will complete.
-func WithMaxIterations(iterations int) CreationOption {
-	return func(co *creationOptions) {
-		co.maxIterations = iterations
-	}
-}
-
-// WithOutputKey is an option for setting the output key of the agent.
-func WithOutputKey(outputKey string) CreationOption {
-	return func(co *creationOptions) {
-		co.outputKey = outputKey
-	}
-}
-
-// WithPromptPrefix is an option for setting the prefix of the prompt used by the agent.
-func WithPromptPrefix(prefix string) CreationOption {
-	return func(co *creationOptions) {
-		co.promptPrefix = prefix
-	}
-}
-
-// WithPromptFormatInstructions is an option for setting the format instructions of the
-// prompt used by the agent.
-func WithPromptFormatInstructions(instructions string) CreationOption {
-	return func(co *creationOptions) {
-		co.formatInstructions = instructions
-	}
-}
-
-// WithPromptFormatInstructions is an option for setting the suffix of the prompt used by the agent.
-func WithPromptSuffix(suffix string) CreationOption {
-	return func(co *creationOptions) {
-		co.promptSuffix = suffix
-	}
-}
-
-// WithPrompt is an option for setting the prompt the agent will use.
-func WithPrompt(prompt prompts.PromptTemplate) CreationOption {
-	return func(co *creationOptions) {
-		co.prompt = prompt
-	}
-}
diff --git a/examples/huggingface-llm-example/huggingface_example.go b/examples/huggingface-llm-example/huggingface_example.go
index f793a21c..5955aa87 100644
--- a/examples/huggingface-llm-example/huggingface_example.go
+++ b/examples/huggingface-llm-example/huggingface_example.go
@@ -10,14 +10,6 @@ import (
 )
 
 func main() {
-	// You may instantiate a client with a custom token and/or custom model
-	// clientOptions := []huggingface.Option{
-	// 	huggingface.WithToken("HF_1234"),
-	// 	huggingface.WithModel("ZZZ"),
-	// }
-	// llm, err := huggingface.New(clientOptions...)
-
-	// Or you may instantiate a client with a default model and use token from environment variable
 	llm, err := huggingface.New()
 	if err != nil {
 		log.Fatal(err)
@@ -28,12 +20,7 @@ func main() {
 	// completion, err := llm.Call(ctx, "What would be a good company name be for name a company that makes colorful socks?")
 
 	// Or override default model to another one
-	generateOptions := []llms.CallOption{
-		llms.WithModel("gpt2"),
-		//llms.WithTopK(10),
-		//llms.WithTopP(0.95),
-		//llms.WithSeed(13),
-	}
+	generateOptions := []llms.CallOption{llms.WithModel("gpt2")}
 	completion, err := llm.Call(ctx, "What would be a good company name be for name a company that makes colorful socks?", generateOptions...)
 
 	// Check for errors
diff --git a/llms/huggingface/huggingfacellm.go b/llms/huggingface/huggingfacellm.go
index e77fb8c4..00ed7b0e 100644
--- a/llms/huggingface/huggingfacellm.go
+++ b/llms/huggingface/huggingfacellm.go
@@ -9,6 +9,11 @@ import (
 	"github.com/tmc/langchaingo/llms/huggingface/internal/huggingfaceclient"
 )
 
+const (
+	tokenEnvVarName = "HUGGINGFACEHUB_API_TOKEN"
+	defaultModel    = "gpt2"
+)
+
 var (
 	ErrEmptyResponse = errors.New("empty response")
 	ErrMissingToken  = errors.New("missing the Hugging Face API token. Set it in the HUGGINGFACEHUB_API_TOKEN environment variable") //nolint:lll
@@ -37,16 +42,9 @@ func (o *LLM) Generate(ctx context.Context, prompts []string, options ...llms.Ca
 		opt(opts)
 	}
 	result, err := o.client.RunInference(ctx, &huggingfaceclient.InferenceRequest{
-		Model:             o.client.Model,
-		Prompt:            prompts[0],
-		Task:              huggingfaceclient.InferenceTaskTextGeneration,
-		Temperature:       opts.Temperature,
-		TopP:              opts.TopP,
-		TopK:              opts.TopK,
-		MinLength:         opts.MinLength,
-		MaxLength:         opts.MaxLength,
-		RepetitionPenalty: opts.RepetitionPenalty,
-		Seed:              opts.Seed,
+		RepoID: opts.Model,
+		Prompt: prompts[0],
+		Task:   huggingfaceclient.InferenceTaskTextGeneration,
 	})
 	if err != nil {
 		return nil, err
@@ -56,26 +54,14 @@ func (o *LLM) Generate(ctx context.Context, prompts []string, options ...llms.Ca
 	}, nil
 }
 
-func New(opts ...Option) (*LLM, error) {
-	options := &options{
-		token: os.Getenv(tokenEnvVarName),
-		model: defaultModel,
-	}
-
-	for _, opt := range opts {
-		opt(options)
-	}
-
-	if len(options.token) == 0 {
+func New() (*LLM, error) {
+	token := os.Getenv(tokenEnvVarName)
+	if token == "" {
 		return nil, ErrMissingToken
 	}
-
-	c, err := huggingfaceclient.New(options.token, options.model)
-	if err != nil {
-		return nil, err
-	}
+	c, err := huggingfaceclient.New(token)
 
 	return &LLM{
 		client: c,
-	}, nil
+	}, err
 }
diff --git a/llms/huggingface/huggingfacellm_option.go b/llms/huggingface/huggingfacellm_option.go
deleted file mode 100644
index 41a68768..00000000
--- a/llms/huggingface/huggingfacellm_option.go
+++ /dev/null
@@ -1,29 +0,0 @@
-package huggingface
-
-const (
-	tokenEnvVarName = "HUGGINGFACEHUB_API_TOKEN"
-	defaultModel    = "gpt2"
-)
-
-type options struct {
-	token string
-	model string
-}
-
-type Option func(*options)
-
-// WithToken passes the HuggingFace API token to the client. If not set, the token
-// is read from the HUGGINGFACEHUB_API_TOKEN environment variable.
-func WithToken(token string) Option {
-	return func(opts *options) {
-		opts.token = token
-	}
-}
-
-// WithModel passes the HuggingFace model to the client. If not set, then will be
-// used default model.
-func WithModel(model string) Option {
-	return func(opts *options) {
-		opts.model = model
-	}
-}
diff --git a/llms/huggingface/internal/huggingfaceclient/huggingfaceclient.go b/llms/huggingface/internal/huggingfaceclient/huggingfaceclient.go
index 6a4dc9b8..e7fa83b2 100644
--- a/llms/huggingface/internal/huggingfaceclient/huggingfaceclient.go
+++ b/llms/huggingface/internal/huggingfaceclient/huggingfaceclient.go
@@ -12,31 +12,22 @@ var (
 )
 
 type Client struct {
-	Token string
-	Model string
+	token string
 }
 
-func New(token string, model string) (*Client, error) {
+func New(token string) (*Client, error) {
 	if token == "" {
 		return nil, ErrInvalidToken
 	}
 	return &Client{
-		Token: token,
-		Model: model,
+		token: token,
 	}, nil
 }
 
 type InferenceRequest struct {
-	Model             string        `json:"repositoryId"`
-	Prompt            string        `json:"prompt"`
-	Task              InferenceTask `json:"task"`
-	Temperature       float64       `json:"temperature,omitempty"`
-	TopP              float64       `json:"top_p,omitempty"`
-	TopK              int           `json:"top_k,omitempty"`
-	MinLength         int           `json:"min_length,omitempty"`
-	MaxLength         int           `json:"max_length,omitempty"`
-	RepetitionPenalty float64       `json:"repetition_penalty,omitempty"`
-	Seed              int           `json:"seed,omitempty"`
+	RepoID string        `json:"repositoryId"`
+	Prompt string        `json:"prompt"`
+	Task   InferenceTask `json:"task"`
 }
 
 type InferenceResponse struct {
@@ -44,18 +35,10 @@ type InferenceResponse struct {
 }
 
 func (c *Client) RunInference(ctx context.Context, request *InferenceRequest) (*InferenceResponse, error) {
-	payload := &inferencePayload{
-		Model:             request.Model,
-		Inputs:            request.Prompt,
-		Temperature:       request.Temperature,
-		TopP:              request.TopP,
-		TopK:              request.TopK,
-		MinLength:         request.MinLength,
-		MaxLength:         request.MaxLength,
-		RepetitionPenalty: request.RepetitionPenalty,
-		Seed:              request.Seed,
-	}
-	resp, err := c.runInference(ctx, payload)
+	resp, err := c.runInference(ctx, &inferencePayload{
+		Model:  request.RepoID,
+		Inputs: request.Prompt,
+	})
 	if err != nil {
 		return nil, fmt.Errorf("failed to run inference: %w", err)
 	}
diff --git a/llms/huggingface/internal/huggingfaceclient/inference.go b/llms/huggingface/internal/huggingfaceclient/inference.go
index 2d9d1c3e..f959f35e 100644
--- a/llms/huggingface/internal/huggingfaceclient/inference.go
+++ b/llms/huggingface/internal/huggingfaceclient/inference.go
@@ -17,15 +17,8 @@ const (
 )
 
 type inferencePayload struct {
-	Model             string  `json:"-"`
-	Inputs            string  `json:"inputs"`
-	Temperature       float64 `json:"temperature,omitempty"`
-	TopP              float64 `json:"top_p,omitempty"`
-	TopK              int     `json:"top_k,omitempty"`
-	MinLength         int     `json:"min_length,omitempty"`
-	MaxLength         int     `json:"max_length,omitempty"`
-	RepetitionPenalty float64 `json:"repetition_penalty,omitempty"`
-	Seed              int     `json:"seed,omitempty"`
+	Model  string `json:"-"`
+	Inputs string `json:"inputs"`
 }
 
 type (
@@ -47,7 +40,7 @@ func (c *Client) runInference(ctx context.Context, payload *inferencePayload) (i
 	if err != nil {
 		return nil, err
 	}
-	req.Header.Set("Authorization", "Bearer "+c.Token)
+	req.Header.Set("Authorization", "Bearer "+c.token)
 	req.Header.Set("Content-Type", "application/json")
 
 	// debug print the http request with httputil:
diff --git a/llms/openai/internal/openaiclient/chat.go b/llms/openai/internal/openaiclient/chat.go
index 05e80c65..f0b4a2b5 100644
--- a/llms/openai/internal/openaiclient/chat.go
+++ b/llms/openai/internal/openaiclient/chat.go
@@ -14,7 +14,6 @@ import (
 
 const (
 	defaultChatModel = "gpt-3.5-turbo"
-	defaultBaseURL   = "https://api.openai.com"
 )
 
 // ChatRequest is a request to create an embedding.
@@ -99,10 +98,7 @@ func (c *Client) createChat(ctx context.Context, payload *ChatRequest) (*ChatRes
 
 	// Build request
 	body := bytes.NewReader(payloadBytes)
-	if c.baseURL == "" {
-		c.baseURL = defaultBaseURL
-	}
-	req, err := http.NewRequestWithContext(ctx, http.MethodPost, fmt.Sprintf("%s/v1/chat/completions", c.baseURL), body)
+	req, err := http.NewRequestWithContext(ctx, http.MethodPost, "https://api.openai.com/v1/chat/completions", body)
 	if err != nil {
 		return nil, err
 	}
@@ -161,7 +157,7 @@ func parseStreamingChatResponse(ctx context.Context, r *http.Response, payload *
 			responseChan <- streamPayload
 		}
 		if err := scanner.Err(); err != nil {
-			log.Println("issue scanning response:", err)
+			log.Fatalf("failed to scan response: %v", err)
 		}
 	}()
 	// Parse response
diff --git a/llms/openai/internal/openaiclient/completions.go b/llms/openai/internal/openaiclient/completions.go
index 2dc23ac0..719d9ded 100644
--- a/llms/openai/internal/openaiclient/completions.go
+++ b/llms/openai/internal/openaiclient/completions.go
@@ -79,12 +79,8 @@ func (c *Client) createCompletion(ctx context.Context, payload *completionPayloa
 		return nil, fmt.Errorf("marshal payload: %w", err)
 	}
 
-	if c.baseURL == "" {
-		c.baseURL = "https://api.openai.com"
-	}
-
 	// Build request
-	req, err := http.NewRequestWithContext(ctx, http.MethodPost, fmt.Sprintf("%s/v1/completions", c.baseURL), bytes.NewReader(payloadBytes))
+	req, err := http.NewRequestWithContext(ctx, http.MethodPost, "https://api.openai.com/v1/completions", bytes.NewReader(payloadBytes))
 	if err != nil {
 		return nil, fmt.Errorf("create request: %w", err)
 	}
diff --git a/llms/openai/internal/openaiclient/embeddings.go b/llms/openai/internal/openaiclient/embeddings.go
index 05d12d55..8efa6153 100644
--- a/llms/openai/internal/openaiclient/embeddings.go
+++ b/llms/openai/internal/openaiclient/embeddings.go
@@ -38,10 +38,8 @@ func (c *Client) createEmbedding(ctx context.Context, payload *embeddingPayload)
 	if err != nil {
 		return nil, fmt.Errorf("marshal payload: %w", err)
 	}
-	if c.baseURL == "" {
-		c.baseURL = "https://api.openai.com"
-	}
-	req, err := http.NewRequestWithContext(ctx, http.MethodPost, fmt.Sprintf("%s/v1/embeddings", c.baseURL), bytes.NewReader(payloadBytes))
+
+	req, err := http.NewRequestWithContext(ctx, http.MethodPost, "https://api.openai.com/v1/embeddings", bytes.NewReader(payloadBytes))
 	if err != nil {
 		return nil, fmt.Errorf("create request: %w", err)
 	}
diff --git a/llms/openai/internal/openaiclient/openaiclient.go b/llms/openai/internal/openaiclient/openaiclient.go
index e281da9e..716d644b 100644
--- a/llms/openai/internal/openaiclient/openaiclient.go
+++ b/llms/openai/internal/openaiclient/openaiclient.go
@@ -13,7 +13,6 @@ var ErrEmptyResponse = errors.New("empty response")
 type Client struct {
 	token      string
 	model      string
-	baseURL    string
 	httpClient Doer
 }
 
@@ -35,11 +34,10 @@ func WithHTTPClient(client Doer) Option {
 }
 
 // New returns a new OpenAI client.
-func New(token string, model string, baseURL string, opts ...Option) (*Client, error) {
+func New(token string, model string, opts ...Option) (*Client, error) {
 	c := &Client{
 		token:      token,
 		model:      model,
-		baseURL:    baseURL,
 		httpClient: http.DefaultClient,
 	}
 
diff --git a/llms/openai/openaillm.go b/llms/openai/openaillm.go
index 9b69644f..62f94ad1 100644
--- a/llms/openai/openaillm.go
+++ b/llms/openai/openaillm.go
@@ -128,9 +128,8 @@ func (o *LLM) CreateEmbedding(ctx context.Context, inputTexts []string) ([][]flo
 // New returns a new OpenAI LLM.
 func New(opts ...Option) (*LLM, error) {
 	options := &options{
-		token:   os.Getenv(tokenEnvVarName),
-		model:   os.Getenv(modelEnvVarName),
-		baseURL: os.Getenv(baseURLEnvVarName),
+		token: os.Getenv(tokenEnvVarName),
+		model: os.Getenv(modelEnvVarName),
 	}
 
 	for _, opt := range opts {
@@ -141,7 +140,7 @@ func New(opts ...Option) (*LLM, error) {
 		return nil, ErrMissingToken
 	}
 
-	client, err := openaiclient.New(options.token, options.model, options.baseURL)
+	client, err := openaiclient.New(options.token, options.model)
 	if err != nil {
 		return nil, err
 	}
diff --git a/llms/openai/openaillm_option.go b/llms/openai/openaillm_option.go
index fe62dd7f..ef46d901 100644
--- a/llms/openai/openaillm_option.go
+++ b/llms/openai/openaillm_option.go
@@ -1,15 +1,13 @@
 package openai
 
 const (
-	tokenEnvVarName   = "OPENAI_API_KEY"  //nolint:gosec
-	modelEnvVarName   = "OPENAI_MODEL"    //nolint:gosec
-	baseURLEnvVarName = "OPENAI_BASE_URL" //nolint:gosec
+	tokenEnvVarName = "OPENAI_API_KEY" //nolint:gosec
+	modelEnvVarName = "OPENAI_MODEL"   //nolint:gosec
 )
 
 type options struct {
-	token   string
-	model   string
-	baseURL string
+	token string
+	model string
 }
 
 type Option func(*options)
@@ -29,12 +27,3 @@ func WithModel(model string) Option {
 		opts.model = model
 	}
 }
-
-// WithBaseURL passes the OpenAI base url to the client. If not set, the base url
-// is read from the OPENAI_BASE_URL environment variable. If still not set in ENV
-// VAR OPENAI_BASE_URL, then the default value is https://api.openai.com is used.
-func WithBaseURL(baseURL string) Option {
-	return func(opts *options) {
-		opts.baseURL = baseURL
-	}
-}
diff --git a/llms/options.go b/llms/options.go
index a7c5bc95..40121127 100644
--- a/llms/options.go
+++ b/llms/options.go
@@ -18,18 +18,6 @@ type CallOptions struct {
 	// StreamingFunc is a function to be called for each chunk of a streaming response.
 	// Return an error to stop streaming early.
 	StreamingFunc func(ctx context.Context, chunk []byte) error
-	// TopK is the number of tokens to consider for top-k sampling.
-	TopK int `json:"top_k"`
-	// TopP is the cumulative probability for top-p sampling.
-	TopP float64 `json:"top_p"`
-	// Seed is a seed for deterministic sampling.
-	Seed int `json:"seed"`
-	// MinLength is the minimum length of the generated text.
-	MinLength int `json:"min_length"`
-	// MaxLength is the maximum length of the generated text.
-	MaxLength int `json:"max_length"`
-	// RepetitionPenalty is the repetition penalty for sampling.
-	RepetitionPenalty float64 `json:"repetition_penalty"`
 }
 
 // WithModel is an option for LLM.Call.
@@ -73,45 +61,3 @@ func WithStreamingFunc(streamingFunc func(ctx context.Context, chunk []byte) err
 		o.StreamingFunc = streamingFunc
 	}
 }
-
-// WithTopK will add an option to use top-k sampling.
-func WithTopK(topK int) CallOption {
-	return func(o *CallOptions) {
-		o.TopK = topK
-	}
-}
-
-// WithTopP	will add an option to use top-p sampling.
-func WithTopP(topP float64) CallOption {
-	return func(o *CallOptions) {
-		o.TopP = topP
-	}
-}
-
-// WithSeed will add an option to use deterministic sampling.
-func WithSeed(seed int) CallOption {
-	return func(o *CallOptions) {
-		o.Seed = seed
-	}
-}
-
-// WithMinLength will add an option to set the minimum length of the generated text.
-func WithMinLength(minLength int) CallOption {
-	return func(o *CallOptions) {
-		o.MinLength = minLength
-	}
-}
-
-// WithMaxLength will add an option to set the maximum length of the generated text.
-func WithMaxLength(maxLength int) CallOption {
-	return func(o *CallOptions) {
-		o.MaxLength = maxLength
-	}
-}
-
-// WithRepetitionPenalty will add an option to set the repetition penalty for sampling.
-func WithRepetitionPenalty(repetitionPenalty float64) CallOption {
-	return func(o *CallOptions) {
-		o.RepetitionPenalty = repetitionPenalty
-	}
-}
diff --git a/tools/serpapi/internal/client.go b/tools/serpapi/internal/client.go
index 48a324b2..2bfe4269 100644
--- a/tools/serpapi/internal/client.go
+++ b/tools/serpapi/internal/client.go
@@ -15,7 +15,6 @@ import (
 const _url = "https://serpapi.com/search"
 
 var (
-	ErrMissingToken = errors.New("missing the SerpAPI API key, set it in the SERPAPI_API_KEY environment variable")
 	ErrNoGoodResult = errors.New("no good search results found")
 	ErrAPIError     = errors.New("error from SerpAPI")
 )
diff --git a/tools/wikipedia/client.go b/tools/wikipedia/client.go
new file mode 100644
index 00000000..1b1c4a48
--- /dev/null
+++ b/tools/wikipedia/client.go
@@ -0,0 +1,115 @@
+package wikipedia
+
+import (
+	"bytes"
+	"context"
+	"encoding/json"
+	"fmt"
+	"io"
+	"net/http"
+	"net/url"
+	"time"
+)
+
+const _baseURL = "https://%s.wikipedia.org/w/api.php"
+
+type searchResponse struct {
+	Query struct {
+		Search []struct {
+			Ns        int       `json:"ns"`
+			Title     string    `json:"title"`
+			PageID    int       `json:"pageid"`
+			Size      int       `json:"size"`
+			WordCount int       `json:"wordcount"`
+			Snippet   string    `json:"snippet"`
+			Timestamp time.Time `json:"timestamp"`
+		} `json:"search"`
+	} `json:"query"`
+}
+
+func search(
+	ctx context.Context,
+	limit int,
+	query,
+	languageCode,
+	userAgent string,
+) (searchResponse, error) {
+	params := make(url.Values)
+	params.Add("format", "json")
+	params.Add("action", "query")
+	params.Add("list", "search")
+	params.Add("srsearch", query)
+	params.Add("srlimit", fmt.Sprintf("%v", limit))
+
+	reqURL := fmt.Sprintf("%s?%s", fmt.Sprintf(_baseURL, languageCode), params.Encode())
+	req, err := http.NewRequestWithContext(ctx, http.MethodGet, reqURL, nil)
+	if err != nil {
+		return searchResponse{}, fmt.Errorf("creating request in wikipedia: %w ", err)
+	}
+	req.Header.Add("User-Agent", userAgent)
+
+	res, err := http.DefaultClient.Do(req)
+	if err != nil {
+		return searchResponse{}, fmt.Errorf("doing response in wikipedia: %w", err)
+	}
+	defer res.Body.Close()
+
+	buf := new(bytes.Buffer)
+	_, err = io.Copy(buf, res.Body)
+	if err != nil {
+		return searchResponse{}, fmt.Errorf("coping data in wikipedia: %w", err)
+	}
+
+	var result searchResponse
+	err = json.Unmarshal(buf.Bytes(), &result)
+	if err != nil {
+		return searchResponse{}, fmt.Errorf("unmarshal data in wikipedia: %w", err)
+	}
+
+	return result, nil
+}
+
+type pageResult struct {
+	Query struct {
+		Pages map[string]struct {
+			Title   string `json:"title"`
+			Extract string `json:"extract"`
+		} `json:"pages"`
+	} `json:"query"`
+}
+
+func getPage(ctx context.Context, pageID int, languageCode, userAgent string) (pageResult, error) {
+	params := make(url.Values)
+	params.Add("format", "json")
+	params.Add("action", "query")
+	params.Add("prop", "extracts")
+	params.Add("pageids", fmt.Sprintf("%v", (pageID)))
+
+	reqURL := fmt.Sprintf("%s?%s", fmt.Sprintf(_baseURL, languageCode), params.Encode())
+
+	req, err := http.NewRequestWithContext(ctx, http.MethodGet, reqURL, nil)
+	if err != nil {
+		return pageResult{}, fmt.Errorf("creating request in wikipedia: %w ", err)
+	}
+	req.Header.Add("User-Agent", userAgent)
+
+	res, err := http.DefaultClient.Do(req)
+	if err != nil {
+		return pageResult{}, fmt.Errorf("doing response in wikipedia: %w", err)
+	}
+	defer res.Body.Close()
+
+	buf := new(bytes.Buffer)
+	_, err = io.Copy(buf, res.Body)
+	if err != nil {
+		return pageResult{}, fmt.Errorf("coping data in wikipedia: %w", err)
+	}
+
+	var result pageResult
+	err = json.Unmarshal(buf.Bytes(), &result)
+	if err != nil {
+		return pageResult{}, fmt.Errorf("unmarshal data in wikipedia: %w", err)
+	}
+
+	return result, nil
+}
diff --git a/tools/wikipedia/doc.go b/tools/wikipedia/doc.go
new file mode 100644
index 00000000..1084bddb
--- /dev/null
+++ b/tools/wikipedia/doc.go
@@ -0,0 +1,3 @@
+// Package wikipedia contains an implementation of the tool interface with the
+// wikipedia api.
+package wikipedia
diff --git a/tools/wikipedia/wikipedia.go b/tools/wikipedia/wikipedia.go
new file mode 100644
index 00000000..4984438d
--- /dev/null
+++ b/tools/wikipedia/wikipedia.go
@@ -0,0 +1,89 @@
+package wikipedia
+
+import (
+	"context"
+	"errors"
+	"fmt"
+
+	"github.com/tmc/langchaingo/tools"
+)
+
+const (
+	_defaultTopK         = 2
+	_defaultDocMaxChars  = 2000
+	_defaultLanguageCode = "en"
+)
+
+// ErrUnexpectedAPIResult is returned if the result form the wikipedia api is unexpected.
+var ErrUnexpectedAPIResult = errors.New("unexpected result from wikipedia api")
+
+// Tool is an implementation of the tool interface that finds information using the wikipedia api.
+type Tool struct {
+	// The number of wikipedia pages to include in the result.
+	TopK int
+	// The number of characters to take from each page.
+	DocMaxChars int
+	// The language code to use.
+	LanguageCode string
+	// The user agent sent in the heder. See https://www.mediawiki.org/wiki/API:Etiquette.
+	UserAgent string
+}
+
+var _ tools.Tool = Tool{}
+
+// New creates a new wikipedia tool to find wikipedia pages using the wikipedia api. TopK is set
+// to 2, DocMaxChars is set to 2000 and the language code is set to "en".
+func New(userAgent string) Tool {
+	return Tool{
+		TopK:         _defaultTopK,
+		DocMaxChars:  _defaultDocMaxChars,
+		LanguageCode: _defaultLanguageCode,
+		UserAgent:    userAgent,
+	}
+}
+
+func (t Tool) Name() string {
+	return "Wikipedia"
+}
+
+func (t Tool) Description() string {
+	return `
+	A wrapper around Wikipedia. 
+	Useful for when you need to answer general questions about 
+	people, places, companies, facts, historical events, or other subjects. 
+	Input should be a search query.`
+}
+
+// Call uses the wikipedia api to find the top search results for the input and returns
+// the first part of the documents combined.
+func (t Tool) Call(ctx context.Context, input string) (string, error) {
+	searchResult, err := search(ctx, t.TopK, input, t.LanguageCode, t.UserAgent)
+	if err != nil {
+		return "", err
+	}
+
+	if len(searchResult.Query.Search) == 0 {
+		return "no wikipedia pages found", nil
+	}
+
+	result := ""
+
+	for _, search := range searchResult.Query.Search {
+		getPageResult, err := getPage(ctx, search.PageID, t.LanguageCode, t.UserAgent)
+		if err != nil {
+			return "", err
+		}
+
+		page, ok := getPageResult.Query.Pages[fmt.Sprintf("%v", search.PageID)]
+		if !ok {
+			return "", ErrUnexpectedAPIResult
+		}
+		if len(page.Extract) >= t.DocMaxChars {
+			result += page.Extract[0:t.DocMaxChars]
+			continue
+		}
+		result += page.Extract
+	}
+
+	return result, nil
+}


Test patch:
diff --git a/agents/executor_test.go b/agents/executor/executor_test.go
similarity index 87%
rename from agents/executor_test.go
rename to agents/executor/executor_test.go
index cdb21734..ee3ac18a 100644
--- a/agents/executor_test.go
+++ b/agents/executor/executor_test.go
@@ -1,4 +1,4 @@
-package agents_test
+package executor_test
 
 import (
 	"context"
@@ -7,7 +7,7 @@ import (
 	"testing"
 
 	"github.com/stretchr/testify/require"
-	"github.com/tmc/langchaingo/agents"
+	"github.com/tmc/langchaingo/agents/executor"
 	"github.com/tmc/langchaingo/chains"
 	"github.com/tmc/langchaingo/llms/openai"
 	"github.com/tmc/langchaingo/tools"
@@ -32,10 +32,10 @@ func TestMRKL(t *testing.T) {
 
 	calculator := tools.Calculator{}
 
-	a, err := agents.Initialize(
+	a, err := executor.Initialize(
 		llm,
 		[]tools.Tool{searchTool, calculator},
-		agents.ZeroShotReactDescription,
+		executor.ZeroShotReactDescription,
 	)
 	require.NoError(t, err)
 
diff --git a/agents/markl_test.go b/agents/mrkl/markl_test.go
similarity index 98%
rename from agents/markl_test.go
rename to agents/mrkl/markl_test.go
index 97373cf9..3323274a 100644
--- a/agents/markl_test.go
+++ b/agents/mrkl/markl_test.go
@@ -1,4 +1,4 @@
-package agents
+package mrkl
 
 import (
 	"testing"
diff --git a/tools/wikipedia/wikipedia_test.go b/tools/wikipedia/wikipedia_test.go
new file mode 100644
index 00000000..a7661db7
--- /dev/null
+++ b/tools/wikipedia/wikipedia_test.go
@@ -0,0 +1,18 @@
+package wikipedia
+
+import (
+	"context"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+const _userAgent = "langchaingo test (https://github.com/tmc/langchaingo)"
+
+func TestWikipedia(t *testing.T) {
+	t.Parallel()
+
+	tool := New(_userAgent)
+	_, err := tool.Call(context.Background(), "america")
+	assert.NoError(t, err)
+}