Skip to content

Commit

Permalink
Add testcases
Browse files Browse the repository at this point in the history
  • Loading branch information
hupe1980 committed Jul 24, 2023
1 parent 50e77f8 commit 172f612
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 5 deletions.
34 changes: 30 additions & 4 deletions agent/agent.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
// Package agent provides functionality for creating and managing agents that leverage Large Language Models (LLMs) to make informed decisions and take actions.
// Package agent provides functionality for creating and managing agents
// that leverage Large Language Models (LLMs) to make informed decisions and take actions.
package agent

import (
"fmt"
"strconv"
"strings"

"github.com/hupe1980/golc/schema"
)

// toolNames returns a comma-separated string containing the names of the tools
// in the provided slice of schema.Tool.
func toolNames(tools []schema.Tool) string {
toolNames := []string{}
for _, tool := range tools {
Expand All @@ -17,6 +21,9 @@ func toolNames(tools []schema.Tool) string {
return strings.Join(toolNames, ", ")
}

// toolDescriptions returns a formatted string containing the names and descriptions
// of the tools in the provided slice of schema.Tool. Each tool's name and description
// are listed in bullet points.
func toolDescriptions(tools []schema.Tool) string {
toolDescriptions := []string{}
for _, tool := range tools {
Expand All @@ -26,13 +33,32 @@ func toolDescriptions(tools []schema.Tool) string {
return strings.Join(toolDescriptions, "\n")
}

// inputsToString converts the values of the input map to strings and returns a new map with string values.
// The function takes a map of mixed data types (any) and converts the values to strings based on their types.
// Supported data types for conversion: string, int, int64, float32, float64, bool.
// For unknown data types, the function returns an error with ErrInputNotString.
// The returned map contains the keys from the input map with their corresponding string values.
// If any value in the input map cannot be converted to a string, the function returns an error with ErrInputNotString.
func inputsToString(inputValues map[string]any) (map[string]string, error) {
inputs := make(map[string]string, len(inputValues))

for key, value := range inputValues {
valueStr, ok := value.(string)
if !ok {
return nil, fmt.Errorf("%w: %s", ErrExecutorInputNotString, key)
var valueStr string
switch v := value.(type) {
case string:
valueStr = v
case int:
valueStr = strconv.Itoa(v)
case int64:
valueStr = strconv.FormatInt(v, 10)
case float32:
valueStr = strconv.FormatFloat(float64(v), 'f', -1, 32)
case float64:
valueStr = strconv.FormatFloat(v, 'f', -1, 64)
case bool:
valueStr = strconv.FormatBool(v)
default:
return nil, fmt.Errorf("%w: %s", ErrInputNotString, key)
}

inputs[key] = valueStr
Expand Down
56 changes: 56 additions & 0 deletions agent/agent_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package agent

import (
"testing"

"github.com/hupe1980/golc/schema"
"github.com/hupe1980/golc/tool"
"github.com/stretchr/testify/assert"
)

func TestToolNames(t *testing.T) {
tools := []schema.Tool{
tool.NewSleep(),
tool.NewHuman(),
}

expected := "Sleep, Human"
result := toolNames(tools)

assert.Equal(t, expected, result)
}

func TestToolDescriptions(t *testing.T) {
tools := []schema.Tool{
tool.NewSleep(),
tool.NewHuman(),
}

expected := `- Sleep: Make agent sleep for a specified number of seconds.
- Human: You can ask a human for guidance when you think you got stuck or you are not sure what to do next. The input should be a question for the human.`

result := toolDescriptions(tools)

assert.Equal(t, expected, result)
}

func TestInputsToString(t *testing.T) {
inputValues := map[string]any{
"param1": "value1",
"param2": "value2",
}

expected := map[string]string{
"param1": "value1",
"param2": "value2",
}

result, err := inputsToString(inputValues)
assert.NoError(t, err)
assert.Equal(t, expected, result)

// Test case with non-string input value
inputValues["param3"] = nil
_, err = inputsToString(inputValues)
assert.Error(t, err)
}
2 changes: 1 addition & 1 deletion agent/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ var (
ErrUnknownAgentType = errors.New("unknown agent type")
ErrAgentNoReturn = errors.New("no actions or finish was returned by the agent")
ErrNotFinished = errors.New("agent not finished before max iterations")
ErrExecutorInputNotString = errors.New("input to executor is not a string")
ErrInputNotString = errors.New("input is not a string")
ErrInvalidChainReturnType = errors.New("agent chain did not return a string")
ErrUnableToParseOutput = errors.New("unable to parse agent output")
)
11 changes: 11 additions & 0 deletions agent/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,21 @@ import (
// Compile time check to ensure Executor satisfies the chain interface.
var _ schema.Chain = (*Executor)(nil)

// ExecutorOptions holds configuration options for the Executor.
type ExecutorOptions struct {
*schema.CallbackOptions
MaxIterations int
Memory schema.Memory
}

// Executor represents an agent executor that executes a chain of actions based on inputs and a defined agent model.
type Executor struct {
agent schema.Agent
toolsMap map[string]schema.Tool
opts ExecutorOptions
}

// NewExecutor creates a new instance of the Executor with the given agent and a list of available tools.
func NewExecutor(agent schema.Agent, tools []schema.Tool) (*Executor, error) {
opts := ExecutorOptions{
CallbackOptions: &schema.CallbackOptions{
Expand All @@ -46,6 +49,8 @@ func NewExecutor(agent schema.Agent, tools []schema.Tool) (*Executor, error) {
}, nil
}

// Call executes the AgentExecutor chain with the given context and inputs.
// It returns the outputs of the chain or an error, if any.
func (e Executor) Call(ctx context.Context, values schema.ChainValues, optFns ...func(o *schema.CallOptions)) (schema.ChainValues, error) {
opts := schema.CallOptions{
CallbackManger: &callback.NoopManager{},
Expand Down Expand Up @@ -119,26 +124,32 @@ func (e Executor) Call(ctx context.Context, values schema.ChainValues, optFns ..
return nil, ErrNotFinished
}

// Memory returns the memory associated with the chain.
func (e Executor) Memory() schema.Memory {
return e.opts.Memory
}

// Type returns the type of the chain.
func (e Executor) Type() string {
return "AgentExecutor"
}

// Verbose returns the verbosity setting of the chain.
func (e Executor) Verbose() bool {
return e.opts.Verbose
}

// Callbacks returns the callbacks associated with the chain.
func (e Executor) Callbacks() []schema.Callback {
return e.opts.Callbacks
}

// InputKeys returns the expected input keys.
func (e Executor) InputKeys() []string {
return e.agent.InputKeys()
}

// OutputKeys returns the output keys the chain will return.
func (e Executor) OutputKeys() []string {
return e.agent.OutputKeys()
}

0 comments on commit 172f612

Please sign in to comment.