Finish moving types

This commit is contained in:
mudler
2025-03-23 21:17:59 +01:00
committed by Ettore Di Giacinto
parent f0b8bfb4f4
commit 75a8d63e83
50 changed files with 568 additions and 467 deletions

View File

@@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"strings" "strings"
"github.com/mudler/LocalAgent/core/types"
"github.com/mudler/LocalAgent/pkg/xlog" "github.com/mudler/LocalAgent/pkg/xlog"
"github.com/sashabaranov/go-openai/jsonschema" "github.com/sashabaranov/go-openai/jsonschema"
"github.com/traefik/yaegi/interp" "github.com/traefik/yaegi/interp"
@@ -79,24 +80,24 @@ func (a *CustomAction) Plannable() bool {
return true return true
} }
func (a *CustomAction) Run(ctx context.Context, params ActionParams) (ActionResult, error) { func (a *CustomAction) Run(ctx context.Context, params types.ActionParams) (types.ActionResult, error) {
v, err := a.i.Eval(fmt.Sprintf("%s.Run", a.config["name"])) v, err := a.i.Eval(fmt.Sprintf("%s.Run", a.config["name"]))
if err != nil { if err != nil {
return ActionResult{}, err return types.ActionResult{}, err
} }
run := v.Interface().(func(map[string]interface{}) (string, map[string]interface{}, error)) run := v.Interface().(func(map[string]interface{}) (string, map[string]interface{}, error))
res, meta, err := run(params) res, meta, err := run(params)
return ActionResult{Result: res, Metadata: meta}, err return types.ActionResult{Result: res, Metadata: meta}, err
} }
func (a *CustomAction) Definition() ActionDefinition { func (a *CustomAction) Definition() types.ActionDefinition {
v, err := a.i.Eval(fmt.Sprintf("%s.Definition", a.config["name"])) v, err := a.i.Eval(fmt.Sprintf("%s.Definition", a.config["name"]))
if err != nil { if err != nil {
xlog.Error("Error getting custom action definition", "error", err) xlog.Error("Error getting custom action definition", "error", err)
return ActionDefinition{} return types.ActionDefinition{}
} }
properties := v.Interface().(func() map[string][]string) properties := v.Interface().(func() map[string][]string)
@@ -104,7 +105,7 @@ func (a *CustomAction) Definition() ActionDefinition {
v, err = a.i.Eval(fmt.Sprintf("%s.RequiredFields", a.config["name"])) v, err = a.i.Eval(fmt.Sprintf("%s.RequiredFields", a.config["name"]))
if err != nil { if err != nil {
xlog.Error("Error getting custom action definition", "error", err) xlog.Error("Error getting custom action definition", "error", err)
return ActionDefinition{} return types.ActionDefinition{}
} }
requiredFields := v.Interface().(func() []string) requiredFields := v.Interface().(func() []string)
@@ -121,8 +122,8 @@ func (a *CustomAction) Definition() ActionDefinition {
Description: v[1], Description: v[1],
} }
} }
return ActionDefinition{ return types.ActionDefinition{
Name: ActionDefinitionName(a.config["name"]), Name: types.ActionDefinitionName(a.config["name"]),
Description: a.config["description"], Description: a.config["description"],
Properties: prop, Properties: prop,
Required: requiredFields(), Required: requiredFields(),

View File

@@ -4,6 +4,7 @@ import (
"context" "context"
. "github.com/mudler/LocalAgent/core/action" . "github.com/mudler/LocalAgent/core/action"
"github.com/mudler/LocalAgent/core/types"
. "github.com/onsi/ginkgo/v2" . "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
@@ -63,7 +64,7 @@ return []string{"foo"}
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
definition := customAction.Definition() definition := customAction.Definition()
Expect(definition).To(Equal(ActionDefinition{ Expect(definition).To(Equal(types.ActionDefinition{
Properties: map[string]jsonschema.Definition{ Properties: map[string]jsonschema.Definition{
"foo": { "foo": {
Type: jsonschema.String, Type: jsonschema.String,
@@ -75,7 +76,7 @@ return []string{"foo"}
Description: "A test action", Description: "A test action",
})) }))
runResult, err := customAction.Run(context.Background(), ActionParams{ runResult, err := customAction.Run(context.Background(), types.ActionParams{
"Foo": "bar", "Foo": "bar",
}) })
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())

View File

@@ -3,6 +3,7 @@ package action
import ( import (
"context" "context"
"github.com/mudler/LocalAgent/core/types"
"github.com/sashabaranov/go-openai/jsonschema" "github.com/sashabaranov/go-openai/jsonschema"
) )
@@ -21,16 +22,16 @@ type IntentResponse struct {
Reasoning string `json:"reasoning"` Reasoning string `json:"reasoning"`
} }
func (a *IntentAction) Run(context.Context, ActionParams) (ActionResult, error) { func (a *IntentAction) Run(context.Context, types.ActionParams) (types.ActionResult, error) {
return ActionResult{}, nil return types.ActionResult{}, nil
} }
func (a *IntentAction) Plannable() bool { func (a *IntentAction) Plannable() bool {
return false return false
} }
func (a *IntentAction) Definition() ActionDefinition { func (a *IntentAction) Definition() types.ActionDefinition {
return ActionDefinition{ return types.ActionDefinition{
Name: "pick_tool", Name: "pick_tool",
Description: "Pick a tool", Description: "Pick a tool",
Properties: map[string]jsonschema.Definition{ Properties: map[string]jsonschema.Definition{

View File

@@ -3,6 +3,7 @@ package action
import ( import (
"context" "context"
"github.com/mudler/LocalAgent/core/types"
"github.com/sashabaranov/go-openai/jsonschema" "github.com/sashabaranov/go-openai/jsonschema"
) )
@@ -18,16 +19,16 @@ type ConversationActionResponse struct {
Message string `json:"message"` Message string `json:"message"`
} }
func (a *ConversationAction) Run(context.Context, ActionParams) (ActionResult, error) { func (a *ConversationAction) Run(context.Context, types.ActionParams) (types.ActionResult, error) {
return ActionResult{}, nil return types.ActionResult{}, nil
} }
func (a *ConversationAction) Plannable() bool { func (a *ConversationAction) Plannable() bool {
return false return false
} }
func (a *ConversationAction) Definition() ActionDefinition { func (a *ConversationAction) Definition() types.ActionDefinition {
return ActionDefinition{ return types.ActionDefinition{
Name: ConversationActionName, Name: ConversationActionName,
Description: "Use this tool to initiate a new conversation or to notify something.", Description: "Use this tool to initiate a new conversation or to notify something.",
Properties: map[string]jsonschema.Definition{ Properties: map[string]jsonschema.Definition{

View File

@@ -1,6 +1,10 @@
package action package action
import "context" import (
"context"
"github.com/mudler/LocalAgent/core/types"
)
// StopActionName is the name of the action // StopActionName is the name of the action
// used by the LLM to stop any further action // used by the LLM to stop any further action
@@ -12,16 +16,16 @@ func NewStop() *StopAction {
type StopAction struct{} type StopAction struct{}
func (a *StopAction) Run(context.Context, ActionParams) (ActionResult, error) { func (a *StopAction) Run(context.Context, types.ActionParams) (types.ActionResult, error) {
return ActionResult{}, nil return types.ActionResult{}, nil
} }
func (a *StopAction) Plannable() bool { func (a *StopAction) Plannable() bool {
return false return false
} }
func (a *StopAction) Definition() ActionDefinition { func (a *StopAction) Definition() types.ActionDefinition {
return ActionDefinition{ return types.ActionDefinition{
Name: StopActionName, Name: StopActionName,
Description: "Use this tool to stop any further action and stop the conversation. You must use this when it looks like there is a conclusion to the conversation or the topic diverged too much from the original conversation. For instance if the user offer his help and you already replied with a message, you can use this tool to stop the conversation.", Description: "Use this tool to stop any further action and stop the conversation. You must use this when it looks like there is a conclusion to the conversation or the topic diverged too much from the original conversation. For instance if the user offer his help and you already replied with a message, you can use this tool to stop the conversation.",
} }

View File

@@ -3,6 +3,7 @@ package action
import ( import (
"context" "context"
"github.com/mudler/LocalAgent/core/types"
"github.com/sashabaranov/go-openai/jsonschema" "github.com/sashabaranov/go-openai/jsonschema"
) )
@@ -29,16 +30,16 @@ type PlanSubtask struct {
Reasoning string `json:"reasoning"` Reasoning string `json:"reasoning"`
} }
func (a *PlanAction) Run(context.Context, ActionParams) (ActionResult, error) { func (a *PlanAction) Run(context.Context, types.ActionParams) (types.ActionResult, error) {
return ActionResult{}, nil return types.ActionResult{}, nil
} }
func (a *PlanAction) Plannable() bool { func (a *PlanAction) Plannable() bool {
return false return false
} }
func (a *PlanAction) Definition() ActionDefinition { func (a *PlanAction) Definition() types.ActionDefinition {
return ActionDefinition{ return types.ActionDefinition{
Name: PlanActionName, Name: PlanActionName,
Description: "The assistant for solving complex tasks that involves calling more functions in sequence, replies with the action.", Description: "The assistant for solving complex tasks that involves calling more functions in sequence, replies with the action.",
Properties: map[string]jsonschema.Definition{ Properties: map[string]jsonschema.Definition{

View File

@@ -3,6 +3,7 @@ package action
import ( import (
"context" "context"
"github.com/mudler/LocalAgent/core/types"
"github.com/sashabaranov/go-openai/jsonschema" "github.com/sashabaranov/go-openai/jsonschema"
) )
@@ -19,16 +20,16 @@ type ReasoningResponse struct {
Reasoning string `json:"reasoning"` Reasoning string `json:"reasoning"`
} }
func (a *ReasoningAction) Run(context.Context, ActionParams) (ActionResult, error) { func (a *ReasoningAction) Run(context.Context, types.ActionParams) (types.ActionResult, error) {
return ActionResult{}, nil return types.ActionResult{}, nil
} }
func (a *ReasoningAction) Plannable() bool { func (a *ReasoningAction) Plannable() bool {
return false return false
} }
func (a *ReasoningAction) Definition() ActionDefinition { func (a *ReasoningAction) Definition() types.ActionDefinition {
return ActionDefinition{ return types.ActionDefinition{
Name: "pick_action", Name: "pick_action",
Description: "try to understand what's the best thing to do and pick an action with a reasoning", Description: "try to understand what's the best thing to do and pick an action with a reasoning",
Properties: map[string]jsonschema.Definition{ Properties: map[string]jsonschema.Definition{

View File

@@ -3,6 +3,7 @@ package action
import ( import (
"context" "context"
"github.com/mudler/LocalAgent/core/types"
"github.com/sashabaranov/go-openai/jsonschema" "github.com/sashabaranov/go-openai/jsonschema"
) )
@@ -21,7 +22,7 @@ type ReplyResponse struct {
Message string `json:"message"` Message string `json:"message"`
} }
func (a *ReplyAction) Run(context.Context, ActionParams) (string, error) { func (a *ReplyAction) Run(context.Context, types.ActionParams) (string, error) {
return "no-op", nil return "no-op", nil
} }
@@ -29,8 +30,8 @@ func (a *ReplyAction) Plannable() bool {
return false return false
} }
func (a *ReplyAction) Definition() ActionDefinition { func (a *ReplyAction) Definition() types.ActionDefinition {
return ActionDefinition{ return types.ActionDefinition{
Name: ReplyActionName, Name: ReplyActionName,
Description: "Use this tool to reply to the user once we have all the informations we need.", Description: "Use this tool to reply to the user once we have all the informations we need.",
Properties: map[string]jsonschema.Definition{ Properties: map[string]jsonschema.Definition{

View File

@@ -4,6 +4,7 @@ import (
"context" "context"
"fmt" "fmt"
"github.com/mudler/LocalAgent/core/types"
"github.com/sashabaranov/go-openai/jsonschema" "github.com/sashabaranov/go-openai/jsonschema"
) )
@@ -33,16 +34,16 @@ type AgentInternalState struct {
Goal string `json:"goal"` Goal string `json:"goal"`
} }
func (a *StateAction) Run(context.Context, ActionParams) (ActionResult, error) { func (a *StateAction) Run(context.Context, types.ActionParams) (types.ActionResult, error) {
return ActionResult{Result: "internal state has been updated"}, nil return types.ActionResult{Result: "internal state has been updated"}, nil
} }
func (a *StateAction) Plannable() bool { func (a *StateAction) Plannable() bool {
return false return false
} }
func (a *StateAction) Definition() ActionDefinition { func (a *StateAction) Definition() types.ActionDefinition {
return ActionDefinition{ return types.ActionDefinition{
Name: StateActionName, Name: StateActionName,
Description: "update the agent state (short memory) with the current state of the conversation.", Description: "update the agent state (short memory) with the current state of the conversation.",
Properties: map[string]jsonschema.Definition{ Properties: map[string]jsonschema.Definition{

View File

@@ -7,53 +7,15 @@ import (
"os" "os"
"github.com/mudler/LocalAgent/core/action" "github.com/mudler/LocalAgent/core/action"
"github.com/mudler/LocalAgent/core/types"
"github.com/mudler/LocalAgent/pkg/xlog" "github.com/mudler/LocalAgent/pkg/xlog"
"github.com/sashabaranov/go-openai" "github.com/sashabaranov/go-openai"
) )
type ActionState struct {
ActionCurrentState
action.ActionResult
}
type ActionCurrentState struct {
Action Action
Params action.ActionParams
Reasoning string
}
// Actions is something the agent can do
type Action interface {
Run(ctx context.Context, action action.ActionParams) (action.ActionResult, error)
Definition() action.ActionDefinition
Plannable() bool
}
type Actions []Action
func (a Actions) ToTools() []openai.Tool {
tools := []openai.Tool{}
for _, action := range a {
tools = append(tools, openai.Tool{
Type: openai.ToolTypeFunction,
Function: action.Definition().ToFunctionDefinition(),
})
}
return tools
}
func (a Actions) Find(name string) Action {
for _, action := range a {
if action.Definition().Name.Is(name) {
return action
}
}
return nil
}
type decisionResult struct { type decisionResult struct {
actionParams action.ActionParams actionParams types.ActionParams
message string message string
actioName string actioName string
} }
@@ -85,7 +47,7 @@ func (a *Agent) decision(
return &decisionResult{message: msg.Content}, nil return &decisionResult{message: msg.Content}, nil
} }
params := action.ActionParams{} params := types.ActionParams{}
if err := params.Read(msg.ToolCalls[0].Function.Arguments); err != nil { if err := params.Read(msg.ToolCalls[0].Function.Arguments); err != nil {
return nil, err return nil, err
} }
@@ -173,7 +135,7 @@ func (m Messages) IsLastMessageFromRole(role string) bool {
return m[len(m)-1].Role == role return m[len(m)-1].Role == role
} }
func (a *Agent) generateParameters(ctx context.Context, pickTemplate string, act Action, c []openai.ChatCompletionMessage, reasoning string) (*decisionResult, error) { func (a *Agent) generateParameters(ctx context.Context, pickTemplate string, act types.Action, c []openai.ChatCompletionMessage, reasoning string) (*decisionResult, error) {
stateHUD, err := renderTemplate(pickTemplate, a.prepareHUD(), a.availableActions(), reasoning) stateHUD, err := renderTemplate(pickTemplate, a.prepareHUD(), a.availableActions(), reasoning)
if err != nil { if err != nil {
@@ -212,7 +174,7 @@ func (a *Agent) generateParameters(ctx context.Context, pickTemplate string, act
) )
} }
func (a *Agent) handlePlanning(ctx context.Context, job *Job, chosenAction Action, actionParams action.ActionParams, reasoning string, pickTemplate string) error { func (a *Agent) handlePlanning(ctx context.Context, job *types.Job, chosenAction types.Action, actionParams types.ActionParams, reasoning string, pickTemplate string) error {
// Planning: run all the actions in sequence // Planning: run all the actions in sequence
if !chosenAction.Definition().Name.Is(action.PlanActionName) { if !chosenAction.Definition().Name.Is(action.PlanActionName) {
xlog.Debug("no plan action") xlog.Debug("no plan action")
@@ -225,9 +187,17 @@ func (a *Agent) handlePlanning(ctx context.Context, job *Job, chosenAction Actio
return fmt.Errorf("error unmarshalling plan result: %w", err) return fmt.Errorf("error unmarshalling plan result: %w", err)
} }
stateResult := ActionState{ActionCurrentState{chosenAction, actionParams, reasoning}, action.ActionResult{ stateResult := types.ActionState{
Result: fmt.Sprintf("planning %s, subtasks: %+v", planResult.Goal, planResult.Subtasks), ActionCurrentState: types.ActionCurrentState{
}} Job: job,
Action: chosenAction,
Params: actionParams,
Reasoning: reasoning,
},
ActionResult: types.ActionResult{
Result: fmt.Sprintf("planning %s, subtasks: %+v", planResult.Goal, planResult.Subtasks),
},
}
job.Result.SetResult(stateResult) job.Result.SetResult(stateResult)
job.CallbackWithResult(stateResult) job.CallbackWithResult(stateResult)
@@ -258,8 +228,23 @@ func (a *Agent) handlePlanning(ctx context.Context, job *Job, chosenAction Actio
} }
actionParams = params.actionParams actionParams = params.actionParams
if !job.Callback(ActionCurrentState{subTaskAction, actionParams, subTaskReasoning}) { if !job.Callback(types.ActionCurrentState{
job.Result.SetResult(ActionState{ActionCurrentState{chosenAction, actionParams, subTaskReasoning}, action.ActionResult{Result: "stopped by callback"}}) Job: job,
Action: subTaskAction,
Params: actionParams,
Reasoning: subTaskReasoning,
}) {
job.Result.SetResult(types.ActionState{
ActionCurrentState: types.ActionCurrentState{
Job: job,
Action: chosenAction,
Params: actionParams,
Reasoning: subTaskReasoning,
},
ActionResult: types.ActionResult{
Result: "stopped by callback",
},
})
job.Result.Conversation = a.currentConversation job.Result.Conversation = a.currentConversation
job.Result.Finish(nil) job.Result.Finish(nil)
break break
@@ -270,7 +255,15 @@ func (a *Agent) handlePlanning(ctx context.Context, job *Job, chosenAction Actio
return fmt.Errorf("error running action: %w", err) return fmt.Errorf("error running action: %w", err)
} }
stateResult := ActionState{ActionCurrentState{subTaskAction, actionParams, subTaskReasoning}, result} stateResult := types.ActionState{
ActionCurrentState: types.ActionCurrentState{
Job: job,
Action: subTaskAction,
Params: actionParams,
Reasoning: subTaskReasoning,
},
ActionResult: result,
}
job.Result.SetResult(stateResult) job.Result.SetResult(stateResult)
job.CallbackWithResult(stateResult) job.CallbackWithResult(stateResult)
xlog.Debug("[subtask] Action executed", "agent", a.Character.Name, "action", subTaskAction.Definition().Name, "result", result) xlog.Debug("[subtask] Action executed", "agent", a.Character.Name, "action", subTaskAction.Definition().Name, "result", result)
@@ -280,10 +273,10 @@ func (a *Agent) handlePlanning(ctx context.Context, job *Job, chosenAction Actio
return nil return nil
} }
func (a *Agent) availableActions() Actions { func (a *Agent) availableActions() types.Actions {
// defaultActions := append(a.options.userActions, action.NewReply()) // defaultActions := append(a.options.userActions, action.NewReply())
addPlanAction := func(actions Actions) Actions { addPlanAction := func(actions types.Actions) types.Actions {
if !a.options.canPlan { if !a.options.canPlan {
return actions return actions
} }
@@ -341,7 +334,7 @@ func (a *Agent) prepareHUD() (promptHUD *PromptHUD) {
} }
// pickAction picks an action based on the conversation // pickAction picks an action based on the conversation
func (a *Agent) pickAction(ctx context.Context, templ string, messages []openai.ChatCompletionMessage) (Action, action.ActionParams, string, error) { func (a *Agent) pickAction(ctx context.Context, templ string, messages []openai.ChatCompletionMessage) (types.Action, types.ActionParams, string, error) {
c := messages c := messages
if !a.options.forceReasoning { if !a.options.forceReasoning {
@@ -390,7 +383,7 @@ func (a *Agent) pickAction(ctx context.Context, templ string, messages []openai.
// and then use the reply to get the action // and then use the reply to get the action
thought, err := a.decision(ctx, thought, err := a.decision(ctx,
c, c,
Actions{action.NewReasoning()}.ToTools(), types.Actions{action.NewReasoning()}.ToTools(),
action.NewReasoning().Definition().Name) action.NewReasoning().Definition().Name)
if err != nil { if err != nil {
return nil, nil, "", err return nil, nil, "", err
@@ -421,7 +414,7 @@ func (a *Agent) pickAction(ctx context.Context, templ string, messages []openai.
Role: "system", Role: "system",
Content: "Given the assistant thought, pick the relevant action: " + reason, Content: "Given the assistant thought, pick the relevant action: " + reason,
}), }),
Actions{intentionsTools}.ToTools(), types.Actions{intentionsTools}.ToTools(),
intentionsTools.Definition().Name) intentionsTools.Definition().Name)
if err != nil { if err != nil {
return nil, nil, "", fmt.Errorf("failed to get the action tool parameters: %v", err) return nil, nil, "", fmt.Errorf("failed to get the action tool parameters: %v", err)

View File

@@ -10,6 +10,7 @@ import (
"github.com/mudler/LocalAgent/pkg/xlog" "github.com/mudler/LocalAgent/pkg/xlog"
"github.com/mudler/LocalAgent/core/action" "github.com/mudler/LocalAgent/core/action"
"github.com/mudler/LocalAgent/core/types"
"github.com/mudler/LocalAgent/pkg/llm" "github.com/mudler/LocalAgent/pkg/llm"
"github.com/sashabaranov/go-openai" "github.com/sashabaranov/go-openai"
) )
@@ -25,21 +26,21 @@ type Agent struct {
options *options options *options
Character Character Character Character
client *openai.Client client *openai.Client
jobQueue chan *Job jobQueue chan *types.Job
actionContext *action.ActionContext actionContext *types.ActionContext
context *action.ActionContext context *types.ActionContext
currentReasoning string currentReasoning string
currentState *action.AgentInternalState currentState *action.AgentInternalState
nextAction Action nextAction types.Action
nextActionParams *action.ActionParams nextActionParams *types.ActionParams
currentConversation Messages currentConversation Messages
selfEvaluationInProgress bool selfEvaluationInProgress bool
pause bool pause bool
newConversations chan openai.ChatCompletionMessage newConversations chan openai.ChatCompletionMessage
mcpActions Actions mcpActions types.Actions
} }
type RAGDB interface { type RAGDB interface {
@@ -64,12 +65,12 @@ func New(opts ...Option) (*Agent, error) {
ctx, cancel := context.WithCancel(c) ctx, cancel := context.WithCancel(c)
a := &Agent{ a := &Agent{
jobQueue: make(chan *Job), jobQueue: make(chan *types.Job),
options: options, options: options,
client: client, client: client,
Character: options.character, Character: options.character,
currentState: &action.AgentInternalState{}, currentState: &action.AgentInternalState{},
context: action.NewContext(ctx, cancel), context: types.NewActionContext(ctx, cancel),
} }
if a.options.statefile != "" { if a.options.statefile != "" {
@@ -130,18 +131,18 @@ func (a *Agent) ConversationChannel() chan openai.ChatCompletionMessage {
// Ask is a pre-emptive, blocking call that returns the response as soon as it's ready. // Ask is a pre-emptive, blocking call that returns the response as soon as it's ready.
// It discards any other computation. // It discards any other computation.
func (a *Agent) Ask(opts ...JobOption) *JobResult { func (a *Agent) Ask(opts ...types.JobOption) *types.JobResult {
xlog.Debug("Agent Ask()", "agent", a.Character.Name, "model", a.options.LLMAPI.Model) xlog.Debug("Agent Ask()", "agent", a.Character.Name, "model", a.options.LLMAPI.Model)
defer func() { defer func() {
xlog.Debug("Agent has finished being asked", "agent", a.Character.Name) xlog.Debug("Agent has finished being asked", "agent", a.Character.Name)
}() }()
//a.StopAction() //a.StopAction()
j := NewJob( j := types.NewJob(
append( append(
opts, opts,
WithReasoningCallback(a.options.reasoningCallback), types.WithReasoningCallback(a.options.reasoningCallback),
WithResultCallback(a.options.resultCallback), types.WithResultCallback(a.options.resultCallback),
)..., )...,
) )
a.jobQueue <- j a.jobQueue <- j
@@ -224,12 +225,12 @@ func (a *Agent) Memory() RAGDB {
return a.options.ragdb return a.options.ragdb
} }
func (a *Agent) runAction(chosenAction Action, params action.ActionParams) (result action.ActionResult, err error) { func (a *Agent) runAction(chosenAction types.Action, params types.ActionParams) (result types.ActionResult, err error) {
for _, act := range a.availableActions() { for _, act := range a.availableActions() {
if act.Definition().Name == chosenAction.Definition().Name { if act.Definition().Name == chosenAction.Definition().Name {
res, err := act.Run(a.actionContext, params) res, err := act.Run(a.actionContext, params)
if err != nil { if err != nil {
return action.ActionResult{}, fmt.Errorf("error running action: %w", err) return types.ActionResult{}, fmt.Errorf("error running action: %w", err)
} }
result = res result = res
@@ -244,7 +245,7 @@ func (a *Agent) runAction(chosenAction Action, params action.ActionParams) (resu
err = params.Unmarshal(&state) err = params.Unmarshal(&state)
if err != nil { if err != nil {
return action.ActionResult{}, fmt.Errorf("error unmarshalling state of the agent: %w", err) return types.ActionResult{}, fmt.Errorf("error unmarshalling state of the agent: %w", err)
} }
// update the current state with the one we just got from the action // update the current state with the one we just got from the action
a.currentState = &state a.currentState = &state
@@ -252,7 +253,7 @@ func (a *Agent) runAction(chosenAction Action, params action.ActionParams) (resu
// update the state file // update the state file
if a.options.statefile != "" { if a.options.statefile != "" {
if err := a.SaveState(a.options.statefile); err != nil { if err := a.SaveState(a.options.statefile); err != nil {
return action.ActionResult{}, err return types.ActionResult{}, err
} }
} }
} }
@@ -348,7 +349,7 @@ func extractImageContent(message openai.ChatCompletionMessage) (imageURL, text s
return return
} }
func (a *Agent) processUserInputs(job *Job, role string) { func (a *Agent) processUserInputs(job *types.Job, role string) {
noNewMessage := job.Text == "" && job.Image == "" noNewMessage := job.Text == "" && job.Image == ""
onlyText := job.Text != "" && job.Image == "" onlyText := job.Text != "" && job.Image == ""
@@ -434,7 +435,7 @@ func (a *Agent) processUserInputs(job *Job, role string) {
} }
} }
func (a *Agent) consumeJob(job *Job, role string) { func (a *Agent) consumeJob(job *types.Job, role string) {
a.Lock() a.Lock()
paused := a.pause paused := a.pause
a.Unlock() a.Unlock()
@@ -451,10 +452,10 @@ func (a *Agent) consumeJob(job *Job, role string) {
a.Lock() a.Lock()
// Set the action context // Set the action context
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
a.actionContext = action.NewContext(ctx, cancel) a.actionContext = types.NewActionContext(ctx, cancel)
a.selfEvaluationInProgress = selfEvaluation a.selfEvaluationInProgress = selfEvaluation
if len(job.conversationHistory) != 0 { if len(job.ConversationHistory) != 0 {
a.currentConversation = job.conversationHistory a.currentConversation = job.ConversationHistory
} }
a.Unlock() a.Unlock()
@@ -493,9 +494,9 @@ func (a *Agent) consumeJob(job *Job, role string) {
} }
// choose an action first // choose an action first
var chosenAction Action var chosenAction types.Action
var reasoning string var reasoning string
var actionParams action.ActionParams var actionParams types.ActionParams
if a.nextAction != nil { if a.nextAction != nil {
// if we are being re-evaluated, we already have the action // if we are being re-evaluated, we already have the action
@@ -576,8 +577,19 @@ func (a *Agent) consumeJob(job *Job, role string) {
return return
} }
if !job.Callback(ActionCurrentState{chosenAction, actionParams, reasoning}) { if !job.Callback(types.ActionCurrentState{
job.Result.SetResult(ActionState{ActionCurrentState{chosenAction, actionParams, reasoning}, action.ActionResult{Result: "stopped by callback"}}) Job: job,
Action: chosenAction,
Params: actionParams,
Reasoning: reasoning}) {
job.Result.SetResult(types.ActionState{
ActionCurrentState: types.ActionCurrentState{
Job: job,
Action: chosenAction,
Params: actionParams,
Reasoning: reasoning,
},
ActionResult: types.ActionResult{Result: "stopped by callback"}})
job.Result.Conversation = a.currentConversation job.Result.Conversation = a.currentConversation
job.Result.Finish(nil) job.Result.Finish(nil)
return return
@@ -622,7 +634,15 @@ func (a *Agent) consumeJob(job *Job, role string) {
result.Result = fmt.Sprintf("Error running tool: %v", err) result.Result = fmt.Sprintf("Error running tool: %v", err)
} }
stateResult := ActionState{ActionCurrentState{chosenAction, actionParams, reasoning}, result} stateResult := types.ActionState{
ActionCurrentState: types.ActionCurrentState{
Job: job,
Action: chosenAction,
Params: actionParams,
Reasoning: reasoning,
},
ActionResult: result,
}
job.Result.SetResult(stateResult) job.Result.SetResult(stateResult)
job.CallbackWithResult(stateResult) job.CallbackWithResult(stateResult)
xlog.Debug("Action executed", "agent", a.Character.Name, "action", chosenAction.Definition().Name, "result", result) xlog.Debug("Action executed", "agent", a.Character.Name, "action", chosenAction.Definition().Name, "result", result)
@@ -781,7 +801,7 @@ func (a *Agent) consumeJob(job *Job, role string) {
job.Result.Finish(nil) job.Result.Finish(nil)
} }
func (a *Agent) addFunctionResultToConversation(chosenAction Action, actionParams action.ActionParams, result action.ActionResult) { func (a *Agent) addFunctionResultToConversation(chosenAction types.Action, actionParams types.ActionParams, result types.ActionResult) {
// calling the function // calling the function
a.currentConversation = append(a.currentConversation, openai.ChatCompletionMessage{ a.currentConversation = append(a.currentConversation, openai.ChatCompletionMessage{
Role: "assistant", Role: "assistant",
@@ -847,10 +867,10 @@ func (a *Agent) periodicallyRun(timer *time.Timer) {
// - asking the agent to do something else based on the result // - asking the agent to do something else based on the result
// whatNext := NewJob(WithText("Decide what to do based on the state")) // whatNext := NewJob(WithText("Decide what to do based on the state"))
whatNext := NewJob( whatNext := types.NewJob(
WithText(innerMonologueTemplate), types.WithText(innerMonologueTemplate),
WithReasoningCallback(a.options.reasoningCallback), types.WithReasoningCallback(a.options.reasoningCallback),
WithResultCallback(a.options.resultCallback), types.WithResultCallback(a.options.resultCallback),
) )
a.consumeJob(whatNext, SystemRole) a.consumeJob(whatNext, SystemRole)
a.ResetConversation() a.ResetConversation()
@@ -913,7 +933,7 @@ func (a *Agent) Run() error {
} }
} }
func (a *Agent) loop(timer *time.Timer, job *Job) { func (a *Agent) loop(timer *time.Timer, job *types.Job) {
// Remember always to reset the timer - if we don't the agent will stop.. // Remember always to reset the timer - if we don't the agent will stop..
defer timer.Reset(a.options.periodicRuns) defer timer.Reset(a.options.periodicRuns)
// Consume the job and generate a response // Consume the job and generate a response

View File

@@ -8,8 +8,8 @@ import (
"github.com/mudler/LocalAgent/pkg/xlog" "github.com/mudler/LocalAgent/pkg/xlog"
"github.com/mudler/LocalAgent/services/actions" "github.com/mudler/LocalAgent/services/actions"
"github.com/mudler/LocalAgent/core/action"
. "github.com/mudler/LocalAgent/core/agent" . "github.com/mudler/LocalAgent/core/agent"
"github.com/mudler/LocalAgent/core/types"
. "github.com/onsi/ginkgo/v2" . "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
"github.com/sashabaranov/go-openai/jsonschema" "github.com/sashabaranov/go-openai/jsonschema"
@@ -19,14 +19,14 @@ const testActionResult = "In Boston it's 30C today, it's sunny, and humidity is
const testActionResult2 = "In milan it's very hot today, it is 45C and the humidity is at 200%" const testActionResult2 = "In milan it's very hot today, it is 45C and the humidity is at 200%"
const testActionResult3 = "In paris it's very cold today, it is 2C and the humidity is at 10%" const testActionResult3 = "In paris it's very cold today, it is 2C and the humidity is at 10%"
var _ Action = &TestAction{} var _ types.Action = &TestAction{}
var debugOptions = []JobOption{ var debugOptions = []types.JobOption{
WithReasoningCallback(func(state ActionCurrentState) bool { types.WithReasoningCallback(func(state types.ActionCurrentState) bool {
xlog.Info("Reasoning", state) xlog.Info("Reasoning", state)
return true return true
}), }),
WithResultCallback(func(state ActionState) { types.WithResultCallback(func(state types.ActionState) {
xlog.Info("Reasoning", state.Reasoning) xlog.Info("Reasoning", state.Reasoning)
xlog.Info("Action", state.Action) xlog.Info("Action", state.Action)
xlog.Info("Result", state.Result) xlog.Info("Result", state.Result)
@@ -41,18 +41,18 @@ func (a *TestAction) Plannable() bool {
return true return true
} }
func (a *TestAction) Run(c context.Context, p action.ActionParams) (action.ActionResult, error) { func (a *TestAction) Run(c context.Context, p types.ActionParams) (types.ActionResult, error) {
for k, r := range a.response { for k, r := range a.response {
if strings.Contains(strings.ToLower(p.String()), strings.ToLower(k)) { if strings.Contains(strings.ToLower(p.String()), strings.ToLower(k)) {
return action.ActionResult{Result: r}, nil return types.ActionResult{Result: r}, nil
} }
} }
return action.ActionResult{Result: "No match"}, nil return types.ActionResult{Result: "No match"}, nil
} }
func (a *TestAction) Definition() action.ActionDefinition { func (a *TestAction) Definition() types.ActionDefinition {
return action.ActionDefinition{ return types.ActionDefinition{
Name: "get_weather", Name: "get_weather",
Description: "get current weather", Description: "get current weather",
Properties: map[string]jsonschema.Definition{ Properties: map[string]jsonschema.Definition{
@@ -74,8 +74,8 @@ type FakeStoreResultAction struct {
TestAction TestAction
} }
func (a *FakeStoreResultAction) Definition() action.ActionDefinition { func (a *FakeStoreResultAction) Definition() types.ActionDefinition {
return action.ActionDefinition{ return types.ActionDefinition{
Name: "store_results", Name: "store_results",
Description: "store results permanently. Use this tool after you have a result you want to keep.", Description: "store results permanently. Use this tool after you have a result you want to keep.",
Properties: map[string]jsonschema.Definition{ Properties: map[string]jsonschema.Definition{
@@ -93,8 +93,8 @@ type FakeInternetAction struct {
TestAction TestAction
} }
func (a *FakeInternetAction) Definition() action.ActionDefinition { func (a *FakeInternetAction) Definition() types.ActionDefinition {
return action.ActionDefinition{ return types.ActionDefinition{
Name: "search_internet", Name: "search_internet",
Description: "search on internet", Description: "search on internet",
Properties: map[string]jsonschema.Definition{ Properties: map[string]jsonschema.Definition{
@@ -127,7 +127,7 @@ var _ = Describe("Agent test", func() {
res := agent.Ask( res := agent.Ask(
append(debugOptions, append(debugOptions,
WithText("what's the weather in Boston and Milano? Use celsius units"), types.WithText("what's the weather in Boston and Milano? Use celsius units"),
)..., )...,
) )
Expect(res.Error).ToNot(HaveOccurred()) Expect(res.Error).ToNot(HaveOccurred())
@@ -142,7 +142,7 @@ var _ = Describe("Agent test", func() {
res = agent.Ask( res = agent.Ask(
append(debugOptions, append(debugOptions,
WithText("Now I want to know the weather in Paris, always use celsius units"), types.WithText("Now I want to know the weather in Paris, always use celsius units"),
)...) )...)
for _, r := range res.State { for _, r := range res.State {
@@ -173,7 +173,7 @@ var _ = Describe("Agent test", func() {
defer agent.Stop() defer agent.Stop()
res := agent.Ask( res := agent.Ask(
append(debugOptions, append(debugOptions,
WithText("can you get the weather in boston? Use celsius units"))..., types.WithText("can you get the weather in boston? Use celsius units"))...,
) )
reasons := []string{} reasons := []string{}
for _, r := range res.State { for _, r := range res.State {
@@ -196,7 +196,7 @@ var _ = Describe("Agent test", func() {
defer agent.Stop() defer agent.Stop()
result := agent.Ask( result := agent.Ask(
WithText("Update your goals such as you want to learn to play the guitar"), types.WithText("Update your goals such as you want to learn to play the guitar"),
) )
fmt.Printf("%+v\n", result) fmt.Printf("%+v\n", result)
Expect(result.Error).ToNot(HaveOccurred()) Expect(result.Error).ToNot(HaveOccurred())
@@ -221,7 +221,7 @@ var _ = Describe("Agent test", func() {
defer agent.Stop() defer agent.Stop()
result := agent.Ask( result := agent.Ask(
WithText("plan a trip to San Francisco from Venice, Italy"), types.WithText("plan a trip to San Francisco from Venice, Italy"),
) )
Expect(len(result.State)).To(BeNumerically(">", 1)) Expect(len(result.State)).To(BeNumerically(">", 1))

View File

@@ -7,12 +7,12 @@ import (
mcp "github.com/metoro-io/mcp-golang" mcp "github.com/metoro-io/mcp-golang"
"github.com/metoro-io/mcp-golang/transport/http" "github.com/metoro-io/mcp-golang/transport/http"
"github.com/mudler/LocalAgent/core/action" "github.com/mudler/LocalAgent/core/types"
"github.com/mudler/LocalAgent/pkg/xlog" "github.com/mudler/LocalAgent/pkg/xlog"
"github.com/sashabaranov/go-openai/jsonschema" "github.com/sashabaranov/go-openai/jsonschema"
) )
var _ Action = &mcpAction{} var _ types.Action = &mcpAction{}
type MCPServer struct { type MCPServer struct {
URL string `json:"url"` URL string `json:"url"`
@@ -30,11 +30,11 @@ func (a *mcpAction) Plannable() bool {
return true return true
} }
func (m *mcpAction) Run(ctx context.Context, params action.ActionParams) (action.ActionResult, error) { func (m *mcpAction) Run(ctx context.Context, params types.ActionParams) (types.ActionResult, error) {
resp, err := m.mcpClient.CallTool(ctx, m.toolName, params) resp, err := m.mcpClient.CallTool(ctx, m.toolName, params)
if err != nil { if err != nil {
xlog.Error("Failed to call tool", "error", err.Error()) xlog.Error("Failed to call tool", "error", err.Error())
return action.ActionResult{}, err return types.ActionResult{}, err
} }
xlog.Debug("MCP response", "response", resp) xlog.Debug("MCP response", "response", resp)
@@ -51,12 +51,12 @@ func (m *mcpAction) Run(ctx context.Context, params action.ActionParams) (action
} }
} }
return action.ActionResult{ return types.ActionResult{
Result: textResult, Result: textResult,
}, nil }, nil
} }
func (m *mcpAction) Definition() action.ActionDefinition { func (m *mcpAction) Definition() types.ActionDefinition {
props := map[string]jsonschema.Definition{} props := map[string]jsonschema.Definition{}
dat, err := json.Marshal(m.inputSchema.Properties) dat, err := json.Marshal(m.inputSchema.Properties)
if err != nil { if err != nil {
@@ -64,8 +64,8 @@ func (m *mcpAction) Definition() action.ActionDefinition {
} }
json.Unmarshal(dat, &props) json.Unmarshal(dat, &props)
return action.ActionDefinition{ return types.ActionDefinition{
Name: action.ActionDefinitionName(m.toolName), Name: types.ActionDefinitionName(m.toolName),
Description: m.toolDescription, Description: m.toolDescription,
Required: m.inputSchema.Required, Required: m.inputSchema.Required,
//Properties: , //Properties: ,
@@ -84,7 +84,7 @@ func (a *Agent) initMCPActions() error {
a.mcpActions = nil a.mcpActions = nil
var err error var err error
generatedActions := Actions{} generatedActions := types.Actions{}
for _, mcpServer := range a.options.mcpServers { for _, mcpServer := range a.options.mcpServers {
transport := http.NewHTTPClientTransport("/mcp") transport := http.NewHTTPClientTransport("/mcp")

View File

@@ -4,6 +4,8 @@ import (
"context" "context"
"strings" "strings"
"time" "time"
"github.com/mudler/LocalAgent/core/types"
) )
type Option func(*options) error type Option func(*options) error
@@ -20,7 +22,7 @@ type options struct {
character Character character Character
randomIdentityGuidance string randomIdentityGuidance string
randomIdentity bool randomIdentity bool
userActions Actions userActions types.Actions
enableHUD, standaloneJob, showCharacter, enableKB, enableSummaryMemory, enableLongTermMemory bool enableHUD, standaloneJob, showCharacter, enableKB, enableSummaryMemory, enableLongTermMemory bool
canStopItself bool canStopItself bool
@@ -41,8 +43,8 @@ type options struct {
systemPrompt string systemPrompt string
// callbacks // callbacks
reasoningCallback func(ActionCurrentState) bool reasoningCallback func(types.ActionCurrentState) bool
resultCallback func(ActionState) resultCallback func(types.ActionState)
conversationsPath string conversationsPath string
@@ -262,14 +264,14 @@ func WithContext(ctx context.Context) Option {
} }
} }
func WithAgentReasoningCallback(cb func(ActionCurrentState) bool) Option { func WithAgentReasoningCallback(cb func(types.ActionCurrentState) bool) Option {
return func(o *options) error { return func(o *options) error {
o.reasoningCallback = cb o.reasoningCallback = cb
return nil return nil
} }
} }
func WithAgentResultCallback(cb func(ActionState)) Option { func WithAgentResultCallback(cb func(types.ActionState)) Option {
return func(o *options) error { return func(o *options) error {
o.resultCallback = cb o.resultCallback = cb
return nil return nil
@@ -310,7 +312,7 @@ func WithRandomIdentity(guidance ...string) Option {
} }
} }
func WithActions(actions ...Action) Option { func WithActions(actions ...types.Action) Option {
return func(o *options) error { return func(o *options) error {
o.userActions = actions o.userActions = actions
return nil return nil

View File

@@ -5,11 +5,11 @@ import (
"html/template" "html/template"
"time" "time"
"github.com/mudler/LocalAgent/core/action" "github.com/mudler/LocalAgent/core/types"
"github.com/sashabaranov/go-openai" "github.com/sashabaranov/go-openai"
) )
func renderTemplate(templ string, hud *PromptHUD, actions Actions, reasoning string) (string, error) { func renderTemplate(templ string, hud *PromptHUD, actions types.Actions, reasoning string) (string, error) {
// prepare the prompt // prepare the prompt
prompt := bytes.NewBuffer([]byte{}) prompt := bytes.NewBuffer([]byte{})
@@ -19,14 +19,14 @@ func renderTemplate(templ string, hud *PromptHUD, actions Actions, reasoning str
} }
// Get all the actions definitions // Get all the actions definitions
definitions := []action.ActionDefinition{} definitions := []types.ActionDefinition{}
for _, m := range actions { for _, m := range actions {
definitions = append(definitions, m.Definition()) definitions = append(definitions, m.Definition())
} }
err = promptTemplate.Execute(prompt, struct { err = promptTemplate.Execute(prompt, struct {
HUD *PromptHUD HUD *PromptHUD
Actions []action.ActionDefinition Actions []types.ActionDefinition
Reasoning string Reasoning string
Messages []openai.ChatCompletionMessage Messages []openai.ChatCompletionMessage
Time string Time string

View File

@@ -4,6 +4,7 @@ import (
"encoding/json" "encoding/json"
"github.com/mudler/LocalAgent/core/agent" "github.com/mudler/LocalAgent/core/agent"
"github.com/mudler/LocalAgent/core/types"
) )
type ConnectorConfig struct { type ConnectorConfig struct {
@@ -61,7 +62,7 @@ type AgentConfig struct {
} }
type Connector interface { type Connector interface {
AgentResultCallback() func(state agent.ActionState) AgentResultCallback() func(state types.ActionState)
AgentReasoningCallback() func(state agent.ActionCurrentState) bool AgentReasoningCallback() func(state types.ActionCurrentState) bool
Start(a *agent.Agent) Start(a *agent.Agent)
} }

View File

@@ -12,9 +12,9 @@ import (
"sync" "sync"
"time" "time"
"github.com/mudler/LocalAgent/core/agent"
. "github.com/mudler/LocalAgent/core/agent" . "github.com/mudler/LocalAgent/core/agent"
"github.com/mudler/LocalAgent/core/sse" "github.com/mudler/LocalAgent/core/sse"
"github.com/mudler/LocalAgent/core/types"
"github.com/mudler/LocalAgent/pkg/llm" "github.com/mudler/LocalAgent/pkg/llm"
"github.com/mudler/LocalAgent/pkg/localrag" "github.com/mudler/LocalAgent/pkg/localrag"
"github.com/mudler/LocalAgent/pkg/utils" "github.com/mudler/LocalAgent/pkg/utils"
@@ -26,25 +26,26 @@ import (
type AgentPool struct { type AgentPool struct {
sync.Mutex sync.Mutex
file string file string
pooldir string pooldir string
pool AgentPoolData pool AgentPoolData
agents map[string]*Agent agents map[string]*Agent
managers map[string]sse.Manager managers map[string]sse.Manager
agentStatus map[string]*Status agentStatus map[string]*Status
apiURL, defaultModel, defaultMultimodalModel, imageModel, localRAGAPI, localRAGKey, apiKey string apiURL, defaultModel, defaultMultimodalModel string
availableActions func(*AgentConfig) func(ctx context.Context, pool *AgentPool) []Action imageModel, localRAGAPI, localRAGKey, apiKey string
connectors func(*AgentConfig) []Connector availableActions func(*AgentConfig) func(ctx context.Context, pool *AgentPool) []types.Action
promptBlocks func(*AgentConfig) []PromptBlock connectors func(*AgentConfig) []Connector
timeout string promptBlocks func(*AgentConfig) []PromptBlock
conversationLogs string timeout string
conversationLogs string
} }
type Status struct { type Status struct {
ActionResults []ActionState ActionResults []types.ActionState
} }
func (s *Status) addResult(result ActionState) { func (s *Status) addResult(result types.ActionState) {
// If we have more than 10 results, remove the oldest one // If we have more than 10 results, remove the oldest one
if len(s.ActionResults) > 10 { if len(s.ActionResults) > 10 {
s.ActionResults = s.ActionResults[1:] s.ActionResults = s.ActionResults[1:]
@@ -53,7 +54,7 @@ func (s *Status) addResult(result ActionState) {
s.ActionResults = append(s.ActionResults, result) s.ActionResults = append(s.ActionResults, result)
} }
func (s *Status) Results() []ActionState { func (s *Status) Results() []types.ActionState {
return s.ActionResults return s.ActionResults
} }
@@ -73,7 +74,7 @@ func loadPoolFromFile(path string) (*AgentPoolData, error) {
func NewAgentPool( func NewAgentPool(
defaultModel, defaultMultimodalModel, imageModel, apiURL, apiKey, directory string, defaultModel, defaultMultimodalModel, imageModel, apiURL, apiKey, directory string,
LocalRAGAPI string, LocalRAGAPI string,
availableActions func(*AgentConfig) func(ctx context.Context, pool *AgentPool) []agent.Action, availableActions func(*AgentConfig) func(ctx context.Context, pool *AgentPool) []types.Action,
connectors func(*AgentConfig) []Connector, connectors func(*AgentConfig) []Connector,
promptBlocks func(*AgentConfig) []PromptBlock, promptBlocks func(*AgentConfig) []PromptBlock,
timeout string, timeout string,
@@ -158,24 +159,24 @@ func (a *AgentPool) CreateAgent(name string, agentConfig *AgentConfig) error {
return err return err
} }
go func(ac AgentConfig, pool *AgentPool) { go func(ac AgentConfig) {
// Create the agent avatar // Create the agent avatar
if err := a.createAgentAvatar(ac); err != nil { if err := createAgentAvatar(a.apiURL, a.apiKey, a.defaultModel, a.imageModel, a.pooldir, ac); err != nil {
xlog.Error("Failed to create agent avatar", "error", err) xlog.Error("Failed to create agent avatar", "error", err)
} }
}(a.pool[name], a) }(a.pool[name])
return a.startAgentWithConfig(name, agentConfig) return a.startAgentWithConfig(name, agentConfig)
} }
func (a *AgentPool) createAgentAvatar(agent AgentConfig) error { func createAgentAvatar(APIURL, APIKey, model, imageModel, avatarDir string, agent AgentConfig) error {
client := llm.NewClient(a.apiKey, a.apiURL+"/v1", "10m") client := llm.NewClient(APIKey, APIURL+"/v1", "10m")
if a.imageModel == "" { if imageModel == "" {
return fmt.Errorf("image model not set") return fmt.Errorf("image model not set")
} }
if a.defaultModel == "" { if model == "" {
return fmt.Errorf("default model not set") return fmt.Errorf("default model not set")
} }
@@ -185,9 +186,9 @@ func (a *AgentPool) createAgentAvatar(agent AgentConfig) error {
err := llm.GenerateTypedJSON( err := llm.GenerateTypedJSON(
context.Background(), context.Background(),
llm.NewClient(a.apiKey, a.apiURL, "10m"), llm.NewClient(APIKey, APIURL, "10m"),
"Generate a prompt that I can use to create a random avatar for the bot '"+agent.Name+"', the description of the bot is: "+agent.Description, "Generate a prompt that I can use to create a random avatar for the bot '"+agent.Name+"', the description of the bot is: "+agent.Description,
a.defaultModel, model,
jsonschema.Definition{ jsonschema.Definition{
Type: jsonschema.Object, Type: jsonschema.Object,
Properties: map[string]jsonschema.Definition{ Properties: map[string]jsonschema.Definition{
@@ -209,7 +210,7 @@ func (a *AgentPool) createAgentAvatar(agent AgentConfig) error {
req := openai.ImageRequest{ req := openai.ImageRequest{
Prompt: results.ImagePrompt, Prompt: results.ImagePrompt,
Model: a.imageModel, Model: imageModel,
Size: openai.CreateImageSize256x256, Size: openai.CreateImageSize256x256,
ResponseFormat: openai.CreateImageResponseFormatB64JSON, ResponseFormat: openai.CreateImageResponseFormatB64JSON,
} }
@@ -228,10 +229,10 @@ func (a *AgentPool) createAgentAvatar(agent AgentConfig) error {
imageJson := resp.Data[0].B64JSON imageJson := resp.Data[0].B64JSON
os.MkdirAll(filepath.Join(a.pooldir, "avatars"), 0755) os.MkdirAll(filepath.Join(avatarDir, "avatars"), 0755)
// Save the image to the agent directory // Save the image to the agent directory
imagePath := filepath.Join(a.pooldir, "avatars", fmt.Sprintf("%s.png", agent.Name)) imagePath := filepath.Join(avatarDir, "avatars", fmt.Sprintf("%s.png", agent.Name))
imageData, err := base64.StdEncoding.DecodeString(imageJson) imageData, err := base64.StdEncoding.DecodeString(imageJson)
if err != nil { if err != nil {
return err return err
@@ -343,7 +344,7 @@ func (a *AgentPool) startAgentWithConfig(name string, config *AgentConfig) error
WithLLMAPIKey(a.apiKey), WithLLMAPIKey(a.apiKey),
WithTimeout(a.timeout), WithTimeout(a.timeout),
WithRAGDB(localrag.NewWrappedClient(a.localRAGAPI, a.localRAGKey, name)), WithRAGDB(localrag.NewWrappedClient(a.localRAGAPI, a.localRAGKey, name)),
WithAgentReasoningCallback(func(state ActionCurrentState) bool { WithAgentReasoningCallback(func(state types.ActionCurrentState) bool {
xlog.Info( xlog.Info(
"Agent is thinking", "Agent is thinking",
"agent", name, "agent", name,
@@ -367,7 +368,7 @@ func (a *AgentPool) startAgentWithConfig(name string, config *AgentConfig) error
}), }),
WithSystemPrompt(config.SystemPrompt), WithSystemPrompt(config.SystemPrompt),
WithMultimodalModel(multimodalModel), WithMultimodalModel(multimodalModel),
WithAgentResultCallback(func(state ActionState) { WithAgentResultCallback(func(state types.ActionState) {
a.Lock() a.Lock()
if _, ok := a.agentStatus[name]; !ok { if _, ok := a.agentStatus[name]; !ok {
a.agentStatus[name] = &Status{} a.agentStatus[name] = &Status{}

View File

@@ -1,4 +1,4 @@
package action package types
import ( import (
"context" "context"
@@ -19,7 +19,7 @@ func (ac *ActionContext) Cancel() {
} }
} }
func NewContext(ctx context.Context, cancel context.CancelFunc) *ActionContext { func NewActionContext(ctx context.Context, cancel context.CancelFunc) *ActionContext {
return &ActionContext{ return &ActionContext{
Context: ctx, Context: ctx,
cancelFunc: cancel, cancelFunc: cancel,
@@ -29,6 +29,7 @@ func NewContext(ctx context.Context, cancel context.CancelFunc) *ActionContext {
type ActionParams map[string]interface{} type ActionParams map[string]interface{}
type ActionResult struct { type ActionResult struct {
Job *Job
Result string Result string
Metadata map[string]interface{} Metadata map[string]interface{}
} }
@@ -84,3 +85,44 @@ func (a ActionDefinition) ToFunctionDefinition() openai.FunctionDefinition {
}, },
} }
} }
// Actions is something the agent can do
type Action interface {
Run(ctx context.Context, action ActionParams) (ActionResult, error)
Definition() ActionDefinition
Plannable() bool
}
type Actions []Action
func (a Actions) ToTools() []openai.Tool {
tools := []openai.Tool{}
for _, action := range a {
tools = append(tools, openai.Tool{
Type: openai.ToolTypeFunction,
Function: action.Definition().ToFunctionDefinition(),
})
}
return tools
}
func (a Actions) Find(name string) Action {
for _, action := range a {
if action.Definition().Name.Is(name) {
return action
}
}
return nil
}
type ActionState struct {
ActionCurrentState
ActionResult
}
type ActionCurrentState struct {
Job *Job
Action Action
Params ActionParams
Reasoning string
}

View File

@@ -1,8 +1,10 @@
package agent package types
import ( import (
"log"
"sync" "sync"
"github.com/google/uuid"
"github.com/sashabaranov/go-openai" "github.com/sashabaranov/go-openai"
) )
@@ -16,7 +18,8 @@ type Job struct {
Result *JobResult Result *JobResult
reasoningCallback func(ActionCurrentState) bool reasoningCallback func(ActionCurrentState) bool
resultCallback func(ActionState) resultCallback func(ActionState)
conversationHistory []openai.ChatCompletionMessage ConversationHistory []openai.ChatCompletionMessage
UUID string
} }
// JobResult is the result of a job // JobResult is the result of a job
@@ -25,17 +28,17 @@ type JobResult struct {
// The result of a job // The result of a job
State []ActionState State []ActionState
Conversation []openai.ChatCompletionMessage Conversation []openai.ChatCompletionMessage
Response string Response string
Error error Error error
ready chan bool ready chan bool
} }
type JobOption func(*Job) type JobOption func(*Job)
func WithConversationHistory(history []openai.ChatCompletionMessage) JobOption { func WithConversationHistory(history []openai.ChatCompletionMessage) JobOption {
return func(j *Job) { return func(j *Job) {
j.conversationHistory = history j.ConversationHistory = history
} }
} }
@@ -85,6 +88,19 @@ func WithText(text string) JobOption {
} }
} }
func newUUID() string {
// Generate UUID with google/uuid
// https://pkg.go.dev/github.com/google/uuid
// Generate a Version 4 UUID
u, err := uuid.NewRandom()
if err != nil {
log.Fatalf("failed to generate UUID: %v", err)
}
return u.String()
}
// NewJob creates a new job // NewJob creates a new job
// It is a request to the agent to do something // It is a request to the agent to do something
// It has a JobResult to get the result asynchronously // It has a JobResult to get the result asynchronously
@@ -92,42 +108,17 @@ func WithText(text string) JobOption {
func NewJob(opts ...JobOption) *Job { func NewJob(opts ...JobOption) *Job {
j := &Job{ j := &Job{
Result: NewJobResult(), Result: NewJobResult(),
UUID: newUUID(),
} }
for _, o := range opts { for _, o := range opts {
o(j) o(j)
} }
return j return j
} }
// SetResult sets the result of a job func WithUUID(uuid string) JobOption {
func (j *JobResult) SetResult(text ActionState) { return func(j *Job) {
j.Lock() j.UUID = uuid
defer j.Unlock() }
j.State = append(j.State, text)
}
// SetResult sets the result of a job
func (j *JobResult) Finish(e error) {
j.Lock()
defer j.Unlock()
j.Error = e
close(j.ready)
}
// SetResult sets the result of a job
func (j *JobResult) SetResponse(response string) {
j.Lock()
defer j.Unlock()
j.Response = response
}
// WaitResult waits for the result of a job
func (j *JobResult) WaitResult() *JobResult {
<-j.ready
j.Lock()
defer j.Unlock()
return j
} }

34
core/types/result.go Normal file
View File

@@ -0,0 +1,34 @@
package types
// SetResult sets the result of a job
func (j *JobResult) SetResult(text ActionState) {
j.Lock()
defer j.Unlock()
j.State = append(j.State, text)
}
// SetResult sets the result of a job
func (j *JobResult) Finish(e error) {
j.Lock()
defer j.Unlock()
j.Error = e
close(j.ready)
}
// SetResult sets the result of a job
func (j *JobResult) SetResponse(response string) {
j.Lock()
defer j.Unlock()
j.Response = response
}
// WaitResult waits for the result of a job
func (j *JobResult) WaitResult() *JobResult {
<-j.ready
j.Lock()
defer j.Unlock()
return j
}

View File

@@ -7,9 +7,9 @@ import (
"github.com/mudler/LocalAgent/core/action" "github.com/mudler/LocalAgent/core/action"
"github.com/mudler/LocalAgent/core/state" "github.com/mudler/LocalAgent/core/state"
"github.com/mudler/LocalAgent/core/types"
"github.com/mudler/LocalAgent/pkg/xlog" "github.com/mudler/LocalAgent/pkg/xlog"
"github.com/mudler/LocalAgent/core/agent"
"github.com/mudler/LocalAgent/services/actions" "github.com/mudler/LocalAgent/services/actions"
) )
@@ -60,9 +60,9 @@ var AvailableActions = []string{
ActionShellcommand, ActionShellcommand,
} }
func Actions(a *state.AgentConfig) func(ctx context.Context, pool *state.AgentPool) []agent.Action { func Actions(a *state.AgentConfig) func(ctx context.Context, pool *state.AgentPool) []types.Action {
return func(ctx context.Context, pool *state.AgentPool) []agent.Action { return func(ctx context.Context, pool *state.AgentPool) []types.Action {
allActions := []agent.Action{} allActions := []types.Action{}
for _, a := range a.Actions { for _, a := range a.Actions {
var config map[string]string var config map[string]string
@@ -82,8 +82,8 @@ func Actions(a *state.AgentConfig) func(ctx context.Context, pool *state.AgentPo
} }
} }
func Action(name string, config map[string]string, pool *state.AgentPool) (agent.Action, error) { func Action(name string, config map[string]string, pool *state.AgentPool) (types.Action, error) {
var a agent.Action var a types.Action
var err error var err error
switch name { switch name {

View File

@@ -6,7 +6,7 @@ import (
"io" "io"
"net/http" "net/http"
"github.com/mudler/LocalAgent/core/action" "github.com/mudler/LocalAgent/core/types"
"github.com/sashabaranov/go-openai/jsonschema" "github.com/sashabaranov/go-openai/jsonschema"
"jaytaylor.com/html2text" "jaytaylor.com/html2text"
) )
@@ -18,7 +18,7 @@ func NewBrowse(config map[string]string) *BrowseAction {
type BrowseAction struct{} type BrowseAction struct{}
func (a *BrowseAction) Run(ctx context.Context, params action.ActionParams) (action.ActionResult, error) { func (a *BrowseAction) Run(ctx context.Context, params types.ActionParams) (types.ActionResult, error) {
result := struct { result := struct {
URL string `json:"url"` URL string `json:"url"`
}{} }{}
@@ -26,35 +26,35 @@ func (a *BrowseAction) Run(ctx context.Context, params action.ActionParams) (act
if err != nil { if err != nil {
fmt.Printf("error: %v", err) fmt.Printf("error: %v", err)
return action.ActionResult{}, err return types.ActionResult{}, err
} }
// download page with http.Client // download page with http.Client
client := &http.Client{} client := &http.Client{}
req, err := http.NewRequest("GET", result.URL, nil) req, err := http.NewRequest("GET", result.URL, nil)
if err != nil { if err != nil {
return action.ActionResult{}, err return types.ActionResult{}, err
} }
resp, err := client.Do(req) resp, err := client.Do(req)
if err != nil { if err != nil {
return action.ActionResult{}, err return types.ActionResult{}, err
} }
defer resp.Body.Close() defer resp.Body.Close()
pagebyte, err := io.ReadAll(resp.Body) pagebyte, err := io.ReadAll(resp.Body)
if err != nil { if err != nil {
return action.ActionResult{}, err return types.ActionResult{}, err
} }
rendered, err := html2text.FromString(string(pagebyte), html2text.Options{PrettyTables: true}) rendered, err := html2text.FromString(string(pagebyte), html2text.Options{PrettyTables: true})
if err != nil { if err != nil {
return action.ActionResult{}, err return types.ActionResult{}, err
} }
return action.ActionResult{Result: fmt.Sprintf("The webpage '%s' content is:\n%s", result.URL, rendered)}, nil return types.ActionResult{Result: fmt.Sprintf("The webpage '%s' content is:\n%s", result.URL, rendered)}, nil
} }
func (a *BrowseAction) Definition() action.ActionDefinition { func (a *BrowseAction) Definition() types.ActionDefinition {
return action.ActionDefinition{ return types.ActionDefinition{
Name: "browse", Name: "browse",
Description: "Use this tool to visit an URL. It browse a website page and return the text content.", Description: "Use this tool to visit an URL. It browse a website page and return the text content.",
Properties: map[string]jsonschema.Definition{ Properties: map[string]jsonschema.Definition{

View File

@@ -4,9 +4,8 @@ import (
"context" "context"
"fmt" "fmt"
"github.com/mudler/LocalAgent/core/action"
"github.com/mudler/LocalAgent/core/agent"
"github.com/mudler/LocalAgent/core/state" "github.com/mudler/LocalAgent/core/state"
"github.com/mudler/LocalAgent/core/types"
"github.com/sashabaranov/go-openai" "github.com/sashabaranov/go-openai"
"github.com/sashabaranov/go-openai/jsonschema" "github.com/sashabaranov/go-openai/jsonschema"
) )
@@ -21,7 +20,7 @@ type CallAgentAction struct {
pool *state.AgentPool pool *state.AgentPool
} }
func (a *CallAgentAction) Run(ctx context.Context, params action.ActionParams) (action.ActionResult, error) { func (a *CallAgentAction) Run(ctx context.Context, params types.ActionParams) (types.ActionResult, error) {
result := struct { result := struct {
AgentName string `json:"agent_name"` AgentName string `json:"agent_name"`
Message string `json:"message"` Message string `json:"message"`
@@ -30,16 +29,16 @@ func (a *CallAgentAction) Run(ctx context.Context, params action.ActionParams) (
if err != nil { if err != nil {
fmt.Printf("error: %v", err) fmt.Printf("error: %v", err)
return action.ActionResult{}, err return types.ActionResult{}, err
} }
ag := a.pool.GetAgent(result.AgentName) ag := a.pool.GetAgent(result.AgentName)
if ag == nil { if ag == nil {
return action.ActionResult{}, fmt.Errorf("agent '%s' not found", result.AgentName) return types.ActionResult{}, fmt.Errorf("agent '%s' not found", result.AgentName)
} }
resp := ag.Ask( resp := ag.Ask(
agent.WithConversationHistory( types.WithConversationHistory(
[]openai.ChatCompletionMessage{ []openai.ChatCompletionMessage{
{ {
Role: "user", Role: "user",
@@ -49,13 +48,13 @@ func (a *CallAgentAction) Run(ctx context.Context, params action.ActionParams) (
), ),
) )
if resp.Error != nil { if resp.Error != nil {
return action.ActionResult{}, err return types.ActionResult{}, err
} }
return action.ActionResult{Result: resp.Response}, nil return types.ActionResult{Result: resp.Response}, nil
} }
func (a *CallAgentAction) Definition() action.ActionDefinition { func (a *CallAgentAction) Definition() types.ActionDefinition {
allAgents := a.pool.AllAgents() allAgents := a.pool.AllAgents()
description := "Use this tool to call another agent. Available agents and their roles are:" description := "Use this tool to call another agent. Available agents and their roles are:"
@@ -68,7 +67,7 @@ func (a *CallAgentAction) Definition() action.ActionDefinition {
description += fmt.Sprintf("\n- %s: %s", agent, agentConfig.Description) description += fmt.Sprintf("\n- %s: %s", agent, agentConfig.Description)
} }
return action.ActionDefinition{ return types.ActionDefinition{
Name: "call_agent", Name: "call_agent",
Description: description, Description: description,
Properties: map[string]jsonschema.Definition{ Properties: map[string]jsonschema.Definition{

View File

@@ -5,7 +5,7 @@ import (
"fmt" "fmt"
"sync" "sync"
"github.com/mudler/LocalAgent/core/action" "github.com/mudler/LocalAgent/core/types"
"github.com/sashabaranov/go-openai/jsonschema" "github.com/sashabaranov/go-openai/jsonschema"
) )
@@ -24,7 +24,7 @@ func NewCounter(config map[string]string) *CounterAction {
} }
// Run executes the counter action // Run executes the counter action
func (a *CounterAction) Run(ctx context.Context, params action.ActionParams) (action.ActionResult, error) { func (a *CounterAction) Run(ctx context.Context, params types.ActionParams) (types.ActionResult, error) {
// Parse parameters // Parse parameters
request := struct { request := struct {
Name string `json:"name"` Name string `json:"name"`
@@ -32,11 +32,11 @@ func (a *CounterAction) Run(ctx context.Context, params action.ActionParams) (ac
}{} }{}
if err := params.Unmarshal(&request); err != nil { if err := params.Unmarshal(&request); err != nil {
return action.ActionResult{}, fmt.Errorf("invalid parameters: %w", err) return types.ActionResult{}, fmt.Errorf("invalid parameters: %w", err)
} }
if request.Name == "" { if request.Name == "" {
return action.ActionResult{}, fmt.Errorf("counter name cannot be empty") return types.ActionResult{}, fmt.Errorf("counter name cannot be empty")
} }
a.mutex.Lock() a.mutex.Lock()
@@ -63,7 +63,7 @@ func (a *CounterAction) Run(ctx context.Context, params action.ActionParams) (ac
message = fmt.Sprintf("Current value of counter '%s' is %d", request.Name, newValue) message = fmt.Sprintf("Current value of counter '%s' is %d", request.Name, newValue)
} }
return action.ActionResult{ return types.ActionResult{
Result: message, Result: message,
Metadata: map[string]any{ Metadata: map[string]any{
"counter_name": request.Name, "counter_name": request.Name,
@@ -75,8 +75,8 @@ func (a *CounterAction) Run(ctx context.Context, params action.ActionParams) (ac
} }
// Definition returns the action definition // Definition returns the action definition
func (a *CounterAction) Definition() action.ActionDefinition { func (a *CounterAction) Definition() types.ActionDefinition {
return action.ActionDefinition{ return types.ActionDefinition{
Name: "counter", Name: "counter",
Description: "Create, update, or query named counters. Specify a name and an adjustment value (positive to increase, negative to decrease, zero to query).", Description: "Create, update, or query named counters. Specify a name and an adjustment value (positive to increase, negative to decrease, zero to query).",
Properties: map[string]jsonschema.Definition{ Properties: map[string]jsonschema.Definition{

View File

@@ -4,7 +4,7 @@ import (
"context" "context"
"fmt" "fmt"
"github.com/mudler/LocalAgent/core/action" "github.com/mudler/LocalAgent/core/types"
"github.com/sashabaranov/go-openai" "github.com/sashabaranov/go-openai"
"github.com/sashabaranov/go-openai/jsonschema" "github.com/sashabaranov/go-openai/jsonschema"
) )
@@ -28,18 +28,18 @@ type GenImageAction struct {
imageModel string imageModel string
} }
func (a *GenImageAction) Run(ctx context.Context, params action.ActionParams) (action.ActionResult, error) { func (a *GenImageAction) Run(ctx context.Context, params types.ActionParams) (types.ActionResult, error) {
result := struct { result := struct {
Prompt string `json:"prompt"` Prompt string `json:"prompt"`
Size string `json:"size"` Size string `json:"size"`
}{} }{}
err := params.Unmarshal(&result) err := params.Unmarshal(&result)
if err != nil { if err != nil {
return action.ActionResult{}, err return types.ActionResult{}, err
} }
if result.Prompt == "" { if result.Prompt == "" {
return action.ActionResult{}, fmt.Errorf("prompt is required") return types.ActionResult{}, fmt.Errorf("prompt is required")
} }
req := openai.ImageRequest{ req := openai.ImageRequest{
@@ -60,22 +60,22 @@ func (a *GenImageAction) Run(ctx context.Context, params action.ActionParams) (a
resp, err := a.client.CreateImage(ctx, req) resp, err := a.client.CreateImage(ctx, req)
if err != nil { if err != nil {
return action.ActionResult{Result: "Failed to generate image " + err.Error()}, err return types.ActionResult{Result: "Failed to generate image " + err.Error()}, err
} }
if len(resp.Data) == 0 { if len(resp.Data) == 0 {
return action.ActionResult{Result: "Failed to generate image"}, nil return types.ActionResult{Result: "Failed to generate image"}, nil
} }
return action.ActionResult{ return types.ActionResult{
Result: fmt.Sprintf("The image was generated and available at: %s", resp.Data[0].URL), Result: fmt.Sprintf("The image was generated and available at: %s", resp.Data[0].URL),
Metadata: map[string]interface{}{ Metadata: map[string]interface{}{
MetadataImages: []string{resp.Data[0].URL}, MetadataImages: []string{resp.Data[0].URL},
}}, nil }}, nil
} }
func (a *GenImageAction) Definition() action.ActionDefinition { func (a *GenImageAction) Definition() types.ActionDefinition {
return action.ActionDefinition{ return types.ActionDefinition{
Name: "generate_image", Name: "generate_image",
Description: "Generate image with.", Description: "Generate image with.",
Properties: map[string]jsonschema.Definition{ Properties: map[string]jsonschema.Definition{

View File

@@ -4,7 +4,7 @@ import (
"context" "context"
"os" "os"
. "github.com/mudler/LocalAgent/core/action" "github.com/mudler/LocalAgent/core/types"
. "github.com/mudler/LocalAgent/services/actions" . "github.com/mudler/LocalAgent/services/actions"
. "github.com/onsi/ginkgo/v2" . "github.com/onsi/ginkgo/v2"
@@ -15,7 +15,7 @@ var _ = Describe("GenImageAction", func() {
var ( var (
ctx context.Context ctx context.Context
action *GenImageAction action *GenImageAction
params ActionParams params types.ActionParams
config map[string]string config map[string]string
) )
@@ -37,7 +37,7 @@ var _ = Describe("GenImageAction", func() {
Describe("Run", func() { Describe("Run", func() {
It("should generate an image with valid prompt and size", func() { It("should generate an image with valid prompt and size", func() {
params = ActionParams{ params = types.ActionParams{
"prompt": "test prompt", "prompt": "test prompt",
"size": "256x256", "size": "256x256",
} }
@@ -48,7 +48,7 @@ var _ = Describe("GenImageAction", func() {
}) })
It("should return an error if the prompt is not provided", func() { It("should return an error if the prompt is not provided", func() {
params = ActionParams{ params = types.ActionParams{
"size": "256x256", "size": "256x256",
} }

View File

@@ -5,7 +5,7 @@ import (
"fmt" "fmt"
"github.com/google/go-github/v69/github" "github.com/google/go-github/v69/github"
"github.com/mudler/LocalAgent/core/action" "github.com/mudler/LocalAgent/core/types"
"github.com/sashabaranov/go-openai/jsonschema" "github.com/sashabaranov/go-openai/jsonschema"
) )
@@ -27,7 +27,7 @@ func NewGithubIssueCloser(ctx context.Context, config map[string]string) *Github
} }
} }
func (g *GithubIssuesCloser) Run(ctx context.Context, params action.ActionParams) (action.ActionResult, error) { func (g *GithubIssuesCloser) Run(ctx context.Context, params types.ActionParams) (types.ActionResult, error) {
result := struct { result := struct {
Repository string `json:"repository"` Repository string `json:"repository"`
Owner string `json:"owner"` Owner string `json:"owner"`
@@ -37,7 +37,7 @@ func (g *GithubIssuesCloser) Run(ctx context.Context, params action.ActionParams
if err != nil { if err != nil {
fmt.Printf("error: %v", err) fmt.Printf("error: %v", err)
return action.ActionResult{}, err return types.ActionResult{}, err
} }
if g.repository != "" { if g.repository != "" {
@@ -67,24 +67,24 @@ func (g *GithubIssuesCloser) Run(ctx context.Context, params action.ActionParams
if err != nil { if err != nil {
fmt.Printf("error: %v", err) fmt.Printf("error: %v", err)
return action.ActionResult{}, err return types.ActionResult{}, err
} }
resultString := fmt.Sprintf("Closed issue %d in repository %s/%s", result.IssueNumber, result.Owner, result.Repository) resultString := fmt.Sprintf("Closed issue %d in repository %s/%s", result.IssueNumber, result.Owner, result.Repository)
if err != nil { if err != nil {
resultString = fmt.Sprintf("Error closing issue %d in repository %s/%s: %v", result.IssueNumber, result.Owner, result.Repository, err) resultString = fmt.Sprintf("Error closing issue %d in repository %s/%s: %v", result.IssueNumber, result.Owner, result.Repository, err)
} }
return action.ActionResult{Result: resultString}, err return types.ActionResult{Result: resultString}, err
} }
func (g *GithubIssuesCloser) Definition() action.ActionDefinition { func (g *GithubIssuesCloser) Definition() types.ActionDefinition {
actionName := "close_github_issue" actionName := "close_github_issue"
if g.customActionName != "" { if g.customActionName != "" {
actionName = g.customActionName actionName = g.customActionName
} }
if g.repository != "" && g.owner != "" { if g.repository != "" && g.owner != "" {
return action.ActionDefinition{ return types.ActionDefinition{
Name: action.ActionDefinitionName(actionName), Name: types.ActionDefinitionName(actionName),
Description: "Closes a Github issue.", Description: "Closes a Github issue.",
Properties: map[string]jsonschema.Definition{ Properties: map[string]jsonschema.Definition{
"issue_number": { "issue_number": {
@@ -96,8 +96,8 @@ func (g *GithubIssuesCloser) Definition() action.ActionDefinition {
} }
} }
return action.ActionDefinition{ return types.ActionDefinition{
Name: action.ActionDefinitionName(actionName), Name: types.ActionDefinitionName(actionName),
Description: "Closes a Github issue.", Description: "Closes a Github issue.",
Properties: map[string]jsonschema.Definition{ Properties: map[string]jsonschema.Definition{
"repository": { "repository": {

View File

@@ -5,7 +5,7 @@ import (
"fmt" "fmt"
"github.com/google/go-github/v69/github" "github.com/google/go-github/v69/github"
"github.com/mudler/LocalAgent/core/action" "github.com/mudler/LocalAgent/core/types"
"github.com/sashabaranov/go-openai/jsonschema" "github.com/sashabaranov/go-openai/jsonschema"
) )
@@ -28,7 +28,7 @@ func NewGithubIssueCommenter(ctx context.Context, config map[string]string) *Git
} }
} }
func (g *GithubIssuesCommenter) Run(ctx context.Context, params action.ActionParams) (action.ActionResult, error) { func (g *GithubIssuesCommenter) Run(ctx context.Context, params types.ActionParams) (types.ActionResult, error) {
result := struct { result := struct {
Repository string `json:"repository"` Repository string `json:"repository"`
Owner string `json:"owner"` Owner string `json:"owner"`
@@ -37,7 +37,7 @@ func (g *GithubIssuesCommenter) Run(ctx context.Context, params action.ActionPar
}{} }{}
err := params.Unmarshal(&result) err := params.Unmarshal(&result)
if err != nil { if err != nil {
return action.ActionResult{}, err return types.ActionResult{}, err
} }
if g.repository != "" && g.owner != "" { if g.repository != "" && g.owner != "" {
@@ -53,18 +53,18 @@ func (g *GithubIssuesCommenter) Run(ctx context.Context, params action.ActionPar
if err != nil { if err != nil {
resultString = fmt.Sprintf("Error adding comment to issue %d in repository %s/%s: %v", result.IssueNumber, result.Owner, result.Repository, err) resultString = fmt.Sprintf("Error adding comment to issue %d in repository %s/%s: %v", result.IssueNumber, result.Owner, result.Repository, err)
} }
return action.ActionResult{Result: resultString}, err return types.ActionResult{Result: resultString}, err
} }
func (g *GithubIssuesCommenter) Definition() action.ActionDefinition { func (g *GithubIssuesCommenter) Definition() types.ActionDefinition {
actionName := "add_comment_to_github_issue" actionName := "add_comment_to_github_issue"
if g.customActionName != "" { if g.customActionName != "" {
actionName = g.customActionName actionName = g.customActionName
} }
description := "Add a comment to a Github issue to a repository." description := "Add a comment to a Github issue to a repository."
if g.repository != "" && g.owner != "" { if g.repository != "" && g.owner != "" {
return action.ActionDefinition{ return types.ActionDefinition{
Name: action.ActionDefinitionName(actionName), Name: types.ActionDefinitionName(actionName),
Description: description, Description: description,
Properties: map[string]jsonschema.Definition{ Properties: map[string]jsonschema.Definition{
"issue_number": { "issue_number": {
@@ -79,8 +79,8 @@ func (g *GithubIssuesCommenter) Definition() action.ActionDefinition {
Required: []string{"issue_number", "comment"}, Required: []string{"issue_number", "comment"},
} }
} }
return action.ActionDefinition{ return types.ActionDefinition{
Name: action.ActionDefinitionName(actionName), Name: types.ActionDefinitionName(actionName),
Description: description, Description: description,
Properties: map[string]jsonschema.Definition{ Properties: map[string]jsonschema.Definition{
"issue_number": { "issue_number": {

View File

@@ -6,7 +6,7 @@ import (
"strings" "strings"
"github.com/google/go-github/v69/github" "github.com/google/go-github/v69/github"
"github.com/mudler/LocalAgent/core/action" "github.com/mudler/LocalAgent/core/types"
"github.com/mudler/LocalAgent/pkg/xlog" "github.com/mudler/LocalAgent/pkg/xlog"
"github.com/sashabaranov/go-openai/jsonschema" "github.com/sashabaranov/go-openai/jsonschema"
) )
@@ -39,7 +39,7 @@ func NewGithubIssueLabeler(ctx context.Context, config map[string]string) *Githu
} }
} }
func (g *GithubIssuesLabeler) Run(ctx context.Context, params action.ActionParams) (action.ActionResult, error) { func (g *GithubIssuesLabeler) Run(ctx context.Context, params types.ActionParams) (types.ActionResult, error) {
result := struct { result := struct {
Repository string `json:"repository"` Repository string `json:"repository"`
Owner string `json:"owner"` Owner string `json:"owner"`
@@ -48,7 +48,7 @@ func (g *GithubIssuesLabeler) Run(ctx context.Context, params action.ActionParam
}{} }{}
err := params.Unmarshal(&result) err := params.Unmarshal(&result)
if err != nil { if err != nil {
return action.ActionResult{}, err return types.ActionResult{}, err
} }
if g.repository != "" && g.owner != "" { if g.repository != "" && g.owner != "" {
@@ -67,17 +67,17 @@ func (g *GithubIssuesLabeler) Run(ctx context.Context, params action.ActionParam
if err != nil { if err != nil {
resultString = fmt.Sprintf("Error adding label '%s' to issue %d in repository %s/%s: %v", result.Label, result.IssueNumber, result.Owner, result.Repository, err) resultString = fmt.Sprintf("Error adding label '%s' to issue %d in repository %s/%s: %v", result.Label, result.IssueNumber, result.Owner, result.Repository, err)
} }
return action.ActionResult{Result: resultString}, err return types.ActionResult{Result: resultString}, err
} }
func (g *GithubIssuesLabeler) Definition() action.ActionDefinition { func (g *GithubIssuesLabeler) Definition() types.ActionDefinition {
actionName := "add_label_to_github_issue" actionName := "add_label_to_github_issue"
if g.customActionName != "" { if g.customActionName != "" {
actionName = g.customActionName actionName = g.customActionName
} }
if g.repository != "" && g.owner != "" { if g.repository != "" && g.owner != "" {
return action.ActionDefinition{ return types.ActionDefinition{
Name: action.ActionDefinitionName(actionName), Name: types.ActionDefinitionName(actionName),
Description: "Add a label to a Github issue. You might want to assign labels to issues to categorize them.", Description: "Add a label to a Github issue. You might want to assign labels to issues to categorize them.",
Properties: map[string]jsonschema.Definition{ Properties: map[string]jsonschema.Definition{
"issue_number": { "issue_number": {
@@ -93,8 +93,8 @@ func (g *GithubIssuesLabeler) Definition() action.ActionDefinition {
Required: []string{"issue_number", "label"}, Required: []string{"issue_number", "label"},
} }
} }
return action.ActionDefinition{ return types.ActionDefinition{
Name: action.ActionDefinitionName(actionName), Name: types.ActionDefinitionName(actionName),
Description: "Add a label to a Github issue. You might want to assign labels to issues to categorize them.", Description: "Add a label to a Github issue. You might want to assign labels to issues to categorize them.",
Properties: map[string]jsonschema.Definition{ Properties: map[string]jsonschema.Definition{
"issue_number": { "issue_number": {

View File

@@ -5,7 +5,7 @@ import (
"fmt" "fmt"
"github.com/google/go-github/v69/github" "github.com/google/go-github/v69/github"
"github.com/mudler/LocalAgent/core/action" "github.com/mudler/LocalAgent/core/types"
"github.com/sashabaranov/go-openai/jsonschema" "github.com/sashabaranov/go-openai/jsonschema"
) )
@@ -28,7 +28,7 @@ func NewGithubIssueOpener(ctx context.Context, config map[string]string) *Github
} }
} }
func (g *GithubIssuesOpener) Run(ctx context.Context, params action.ActionParams) (action.ActionResult, error) { func (g *GithubIssuesOpener) Run(ctx context.Context, params types.ActionParams) (types.ActionResult, error) {
result := struct { result := struct {
Title string `json:"title"` Title string `json:"title"`
Body string `json:"text"` Body string `json:"text"`
@@ -39,7 +39,7 @@ func (g *GithubIssuesOpener) Run(ctx context.Context, params action.ActionParams
if err != nil { if err != nil {
fmt.Printf("error: %v", err) fmt.Printf("error: %v", err)
return action.ActionResult{}, err return types.ActionResult{}, err
} }
if g.repository != "" && g.owner != "" { if g.repository != "" && g.owner != "" {
@@ -60,17 +60,17 @@ func (g *GithubIssuesOpener) Run(ctx context.Context, params action.ActionParams
resultString = fmt.Sprintf("Created issue %d in repository %s/%s: %s", createdIssue.GetNumber(), result.Owner, result.Repository, createdIssue.GetURL()) resultString = fmt.Sprintf("Created issue %d in repository %s/%s: %s", createdIssue.GetNumber(), result.Owner, result.Repository, createdIssue.GetURL())
} }
return action.ActionResult{Result: resultString}, err return types.ActionResult{Result: resultString}, err
} }
func (g *GithubIssuesOpener) Definition() action.ActionDefinition { func (g *GithubIssuesOpener) Definition() types.ActionDefinition {
actionName := "create_github_issue" actionName := "create_github_issue"
if g.customActionName != "" { if g.customActionName != "" {
actionName = g.customActionName actionName = g.customActionName
} }
if g.repository != "" && g.owner != "" { if g.repository != "" && g.owner != "" {
return action.ActionDefinition{ return types.ActionDefinition{
Name: action.ActionDefinitionName(actionName), Name: types.ActionDefinitionName(actionName),
Description: "Create a new issue on a GitHub repository.", Description: "Create a new issue on a GitHub repository.",
Properties: map[string]jsonschema.Definition{ Properties: map[string]jsonschema.Definition{
"text": { "text": {
@@ -85,8 +85,8 @@ func (g *GithubIssuesOpener) Definition() action.ActionDefinition {
Required: []string{"title", "text"}, Required: []string{"title", "text"},
} }
} }
return action.ActionDefinition{ return types.ActionDefinition{
Name: action.ActionDefinitionName(actionName), Name: types.ActionDefinitionName(actionName),
Description: "Create a new issue on a GitHub repository.", Description: "Create a new issue on a GitHub repository.",
Properties: map[string]jsonschema.Definition{ Properties: map[string]jsonschema.Definition{
"text": { "text": {

View File

@@ -5,7 +5,7 @@ import (
"fmt" "fmt"
"github.com/google/go-github/v69/github" "github.com/google/go-github/v69/github"
"github.com/mudler/LocalAgent/core/action" "github.com/mudler/LocalAgent/core/types"
"github.com/sashabaranov/go-openai/jsonschema" "github.com/sashabaranov/go-openai/jsonschema"
) )
@@ -28,7 +28,7 @@ func NewGithubIssueReader(ctx context.Context, config map[string]string) *Github
} }
} }
func (g *GithubIssuesReader) Run(ctx context.Context, params action.ActionParams) (action.ActionResult, error) { func (g *GithubIssuesReader) Run(ctx context.Context, params types.ActionParams) (types.ActionResult, error) {
result := struct { result := struct {
Repository string `json:"repository"` Repository string `json:"repository"`
Owner string `json:"owner"` Owner string `json:"owner"`
@@ -37,7 +37,7 @@ func (g *GithubIssuesReader) Run(ctx context.Context, params action.ActionParams
}{} }{}
err := params.Unmarshal(&result) err := params.Unmarshal(&result)
if err != nil { if err != nil {
return action.ActionResult{}, err return types.ActionResult{}, err
} }
if g.repository != "" && g.owner != "" { if g.repository != "" && g.owner != "" {
@@ -47,26 +47,26 @@ func (g *GithubIssuesReader) Run(ctx context.Context, params action.ActionParams
issue, _, err := g.client.Issues.Get(g.context, result.Owner, result.Repository, result.IssueNumber) issue, _, err := g.client.Issues.Get(g.context, result.Owner, result.Repository, result.IssueNumber)
if err == nil && issue != nil { if err == nil && issue != nil {
return action.ActionResult{ return types.ActionResult{
Result: fmt.Sprintf( Result: fmt.Sprintf(
"Issue %d Repository: %s\nTitle: %s\nBody: %s", "Issue %d Repository: %s\nTitle: %s\nBody: %s",
*issue.Number, *issue.Repository.FullName, *issue.Title, *issue.Body)}, nil *issue.Number, *issue.Repository.FullName, *issue.Title, *issue.Body)}, nil
} }
if err != nil { if err != nil {
return action.ActionResult{Result: fmt.Sprintf("Error fetching issue: %s", err.Error())}, err return types.ActionResult{Result: fmt.Sprintf("Error fetching issue: %s", err.Error())}, err
} }
return action.ActionResult{Result: fmt.Sprintf("No issue found")}, err return types.ActionResult{Result: fmt.Sprintf("No issue found")}, err
} }
func (g *GithubIssuesReader) Definition() action.ActionDefinition { func (g *GithubIssuesReader) Definition() types.ActionDefinition {
actionName := "read_github_issue" actionName := "read_github_issue"
if g.customActionName != "" { if g.customActionName != "" {
actionName = g.customActionName actionName = g.customActionName
} }
description := "Read a Github issue." description := "Read a Github issue."
if g.repository != "" && g.owner != "" { if g.repository != "" && g.owner != "" {
return action.ActionDefinition{ return types.ActionDefinition{
Name: action.ActionDefinitionName(actionName), Name: types.ActionDefinitionName(actionName),
Description: description, Description: description,
Properties: map[string]jsonschema.Definition{ Properties: map[string]jsonschema.Definition{
"issue_number": { "issue_number": {
@@ -77,8 +77,8 @@ func (g *GithubIssuesReader) Definition() action.ActionDefinition {
Required: []string{"issue_number"}, Required: []string{"issue_number"},
} }
} }
return action.ActionDefinition{ return types.ActionDefinition{
Name: action.ActionDefinitionName(actionName), Name: types.ActionDefinitionName(actionName),
Description: description, Description: description,
Properties: map[string]jsonschema.Definition{ Properties: map[string]jsonschema.Definition{
"issue_number": { "issue_number": {

View File

@@ -5,7 +5,7 @@ import (
"fmt" "fmt"
"github.com/google/go-github/v69/github" "github.com/google/go-github/v69/github"
"github.com/mudler/LocalAgent/core/action" "github.com/mudler/LocalAgent/core/types"
"github.com/mudler/LocalAgent/pkg/xlog" "github.com/mudler/LocalAgent/pkg/xlog"
"github.com/sashabaranov/go-openai/jsonschema" "github.com/sashabaranov/go-openai/jsonschema"
) )
@@ -29,7 +29,7 @@ func NewGithubIssueSearch(ctx context.Context, config map[string]string) *Github
} }
} }
func (g *GithubIssueSearch) Run(ctx context.Context, params action.ActionParams) (action.ActionResult, error) { func (g *GithubIssueSearch) Run(ctx context.Context, params types.ActionParams) (types.ActionResult, error) {
result := struct { result := struct {
Query string `json:"query"` Query string `json:"query"`
Repository string `json:"repository"` Repository string `json:"repository"`
@@ -39,7 +39,7 @@ func (g *GithubIssueSearch) Run(ctx context.Context, params action.ActionParams)
if err != nil { if err != nil {
fmt.Printf("error: %v", err) fmt.Printf("error: %v", err)
return action.ActionResult{}, err return types.ActionResult{}, err
} }
if g.repository != "" && g.owner != "" { if g.repository != "" && g.owner != "" {
@@ -56,7 +56,7 @@ func (g *GithubIssueSearch) Run(ctx context.Context, params action.ActionParams)
}) })
if err != nil { if err != nil {
resultString = fmt.Sprintf("Error listing issues: %v", err) resultString = fmt.Sprintf("Error listing issues: %v", err)
return action.ActionResult{Result: resultString}, err return types.ActionResult{Result: resultString}, err
} }
for _, i := range issues.Issues { for _, i := range issues.Issues {
xlog.Info("Issue found", "title", i.GetTitle()) xlog.Info("Issue found", "title", i.GetTitle())
@@ -65,17 +65,17 @@ func (g *GithubIssueSearch) Run(ctx context.Context, params action.ActionParams)
// resultString += fmt.Sprintf("Body: %s\n", i.GetBody()) // resultString += fmt.Sprintf("Body: %s\n", i.GetBody())
} }
return action.ActionResult{Result: resultString}, err return types.ActionResult{Result: resultString}, err
} }
func (g *GithubIssueSearch) Definition() action.ActionDefinition { func (g *GithubIssueSearch) Definition() types.ActionDefinition {
actionName := "search_github_issue" actionName := "search_github_issue"
if g.customActionName != "" { if g.customActionName != "" {
actionName = g.customActionName actionName = g.customActionName
} }
if g.repository != "" && g.owner != "" { if g.repository != "" && g.owner != "" {
return action.ActionDefinition{ return types.ActionDefinition{
Name: action.ActionDefinitionName(actionName), Name: types.ActionDefinitionName(actionName),
Description: "Search between github issues", Description: "Search between github issues",
Properties: map[string]jsonschema.Definition{ Properties: map[string]jsonschema.Definition{
"query": { "query": {
@@ -86,8 +86,8 @@ func (g *GithubIssueSearch) Definition() action.ActionDefinition {
Required: []string{"query"}, Required: []string{"query"},
} }
} }
return action.ActionDefinition{ return types.ActionDefinition{
Name: action.ActionDefinitionName(actionName), Name: types.ActionDefinitionName(actionName),
Description: "Search between github issues", Description: "Search between github issues",
Properties: map[string]jsonschema.Definition{ Properties: map[string]jsonschema.Definition{
"query": { "query": {

View File

@@ -5,7 +5,7 @@ import (
"fmt" "fmt"
"github.com/google/go-github/v69/github" "github.com/google/go-github/v69/github"
"github.com/mudler/LocalAgent/core/action" "github.com/mudler/LocalAgent/core/types"
"github.com/sashabaranov/go-openai/jsonschema" "github.com/sashabaranov/go-openai/jsonschema"
) )
@@ -31,7 +31,7 @@ func NewGithubRepositoryCreateOrUpdateContent(ctx context.Context, config map[st
} }
} }
func (g *GithubRepositoryCreateOrUpdateContent) Run(ctx context.Context, params action.ActionParams) (action.ActionResult, error) { func (g *GithubRepositoryCreateOrUpdateContent) Run(ctx context.Context, params types.ActionParams) (types.ActionResult, error) {
result := struct { result := struct {
Path string `json:"path"` Path string `json:"path"`
Repository string `json:"repository"` Repository string `json:"repository"`
@@ -44,7 +44,7 @@ func (g *GithubRepositoryCreateOrUpdateContent) Run(ctx context.Context, params
if err != nil { if err != nil {
fmt.Printf("error: %v", err) fmt.Printf("error: %v", err)
return action.ActionResult{}, err return types.ActionResult{}, err
} }
if result.Branch == "" { if result.Branch == "" {
@@ -82,13 +82,13 @@ func (g *GithubRepositoryCreateOrUpdateContent) Run(ctx context.Context, params
}) })
if err != nil { if err != nil {
resultString := fmt.Sprintf("Error creating content : %v", err) resultString := fmt.Sprintf("Error creating content : %v", err)
return action.ActionResult{Result: resultString}, err return types.ActionResult{Result: resultString}, err
} }
return action.ActionResult{Result: fmt.Sprintf("File created/updated: %s\n", fileContent.GetURL())}, err return types.ActionResult{Result: fmt.Sprintf("File created/updated: %s\n", fileContent.GetURL())}, err
} }
func (g *GithubRepositoryCreateOrUpdateContent) Definition() action.ActionDefinition { func (g *GithubRepositoryCreateOrUpdateContent) Definition() types.ActionDefinition {
actionName := "github_repository_create_or_update_content" actionName := "github_repository_create_or_update_content"
actionDescription := "Create or update a file in a GitHub repository" actionDescription := "Create or update a file in a GitHub repository"
if g.customActionName != "" { if g.customActionName != "" {
@@ -117,8 +117,8 @@ func (g *GithubRepositoryCreateOrUpdateContent) Definition() action.ActionDefini
} }
if g.repository != "" && g.owner != "" { if g.repository != "" && g.owner != "" {
return action.ActionDefinition{ return types.ActionDefinition{
Name: action.ActionDefinitionName(actionName), Name: types.ActionDefinitionName(actionName),
Description: actionDescription, Description: actionDescription,
Properties: properties, Properties: properties,
Required: []string{"path", "content"}, Required: []string{"path", "content"},
@@ -135,8 +135,8 @@ func (g *GithubRepositoryCreateOrUpdateContent) Definition() action.ActionDefini
Description: "The repository to search in", Description: "The repository to search in",
} }
return action.ActionDefinition{ return types.ActionDefinition{
Name: action.ActionDefinitionName(actionName), Name: types.ActionDefinitionName(actionName),
Description: actionDescription, Description: actionDescription,
Properties: properties, Properties: properties,
Required: []string{"path", "repository", "owner", "content"}, Required: []string{"path", "repository", "owner", "content"},

View File

@@ -5,7 +5,7 @@ import (
"fmt" "fmt"
"github.com/google/go-github/v69/github" "github.com/google/go-github/v69/github"
"github.com/mudler/LocalAgent/core/action" "github.com/mudler/LocalAgent/core/types"
"github.com/sashabaranov/go-openai/jsonschema" "github.com/sashabaranov/go-openai/jsonschema"
) )
@@ -28,7 +28,7 @@ func NewGithubRepositoryGetContent(ctx context.Context, config map[string]string
} }
} }
func (g *GithubRepositoryGetContent) Run(ctx context.Context, params action.ActionParams) (action.ActionResult, error) { func (g *GithubRepositoryGetContent) Run(ctx context.Context, params types.ActionParams) (types.ActionResult, error) {
result := struct { result := struct {
Path string `json:"path"` Path string `json:"path"`
Repository string `json:"repository"` Repository string `json:"repository"`
@@ -38,7 +38,7 @@ func (g *GithubRepositoryGetContent) Run(ctx context.Context, params action.Acti
if err != nil { if err != nil {
fmt.Printf("error: %v", err) fmt.Printf("error: %v", err)
return action.ActionResult{}, err return types.ActionResult{}, err
} }
if g.repository != "" && g.owner != "" { if g.repository != "" && g.owner != "" {
@@ -49,7 +49,7 @@ func (g *GithubRepositoryGetContent) Run(ctx context.Context, params action.Acti
fileContent, directoryContent, _, err := g.client.Repositories.GetContents(g.context, result.Owner, result.Repository, result.Path, nil) fileContent, directoryContent, _, err := g.client.Repositories.GetContents(g.context, result.Owner, result.Repository, result.Path, nil)
if err != nil { if err != nil {
resultString := fmt.Sprintf("Error getting content : %v", err) resultString := fmt.Sprintf("Error getting content : %v", err)
return action.ActionResult{Result: resultString}, err return types.ActionResult{Result: resultString}, err
} }
if len(directoryContent) > 0 { if len(directoryContent) > 0 {
@@ -57,26 +57,26 @@ func (g *GithubRepositoryGetContent) Run(ctx context.Context, params action.Acti
for _, f := range directoryContent { for _, f := range directoryContent {
resultString += fmt.Sprintf("File: %s\n", f.GetName()) resultString += fmt.Sprintf("File: %s\n", f.GetName())
} }
return action.ActionResult{Result: resultString}, err return types.ActionResult{Result: resultString}, err
} }
content, err := fileContent.GetContent() content, err := fileContent.GetContent()
if err != nil { if err != nil {
return action.ActionResult{}, err return types.ActionResult{}, err
} }
return action.ActionResult{Result: fmt.Sprintf("File %s\nContent:%s\n", result.Path, content)}, err return types.ActionResult{Result: fmt.Sprintf("File %s\nContent:%s\n", result.Path, content)}, err
} }
func (g *GithubRepositoryGetContent) Definition() action.ActionDefinition { func (g *GithubRepositoryGetContent) Definition() types.ActionDefinition {
actionName := "get_github_repository_content" actionName := "get_github_repository_content"
actionDescription := "Get content of a file or directory in a github repository" actionDescription := "Get content of a file or directory in a github repository"
if g.customActionName != "" { if g.customActionName != "" {
actionName = g.customActionName actionName = g.customActionName
} }
if g.repository != "" && g.owner != "" { if g.repository != "" && g.owner != "" {
return action.ActionDefinition{ return types.ActionDefinition{
Name: action.ActionDefinitionName(actionName), Name: types.ActionDefinitionName(actionName),
Description: actionDescription, Description: actionDescription,
Properties: map[string]jsonschema.Definition{ Properties: map[string]jsonschema.Definition{
"path": { "path": {
@@ -87,8 +87,8 @@ func (g *GithubRepositoryGetContent) Definition() action.ActionDefinition {
Required: []string{"path"}, Required: []string{"path"},
} }
} }
return action.ActionDefinition{ return types.ActionDefinition{
Name: action.ActionDefinitionName(actionName), Name: types.ActionDefinitionName(actionName),
Description: actionDescription, Description: actionDescription,
Properties: map[string]jsonschema.Definition{ Properties: map[string]jsonschema.Definition{
"path": { "path": {

View File

@@ -5,7 +5,7 @@ import (
"fmt" "fmt"
"github.com/google/go-github/v69/github" "github.com/google/go-github/v69/github"
"github.com/mudler/LocalAgent/core/action" "github.com/mudler/LocalAgent/core/types"
"github.com/sashabaranov/go-openai/jsonschema" "github.com/sashabaranov/go-openai/jsonschema"
) )
@@ -26,7 +26,7 @@ func NewGithubRepositoryREADME(ctx context.Context, config map[string]string) *G
} }
} }
func (g *GithubRepositoryREADME) Run(ctx context.Context, params action.ActionParams) (action.ActionResult, error) { func (g *GithubRepositoryREADME) Run(ctx context.Context, params types.ActionParams) (types.ActionResult, error) {
result := struct { result := struct {
Repository string `json:"repository"` Repository string `json:"repository"`
Owner string `json:"owner"` Owner string `json:"owner"`
@@ -35,30 +35,30 @@ func (g *GithubRepositoryREADME) Run(ctx context.Context, params action.ActionPa
if err != nil { if err != nil {
fmt.Printf("error: %v", err) fmt.Printf("error: %v", err)
return action.ActionResult{}, err return types.ActionResult{}, err
} }
fileContent, _, err := g.client.Repositories.GetReadme(g.context, result.Owner, result.Repository, &github.RepositoryContentGetOptions{}) fileContent, _, err := g.client.Repositories.GetReadme(g.context, result.Owner, result.Repository, &github.RepositoryContentGetOptions{})
if err != nil { if err != nil {
resultString := fmt.Sprintf("Error getting content : %v", err) resultString := fmt.Sprintf("Error getting content : %v", err)
return action.ActionResult{Result: resultString}, err return types.ActionResult{Result: resultString}, err
} }
content, err := fileContent.GetContent() content, err := fileContent.GetContent()
if err != nil { if err != nil {
return action.ActionResult{}, err return types.ActionResult{}, err
} }
return action.ActionResult{Result: content}, err return types.ActionResult{Result: content}, err
} }
func (g *GithubRepositoryREADME) Definition() action.ActionDefinition { func (g *GithubRepositoryREADME) Definition() types.ActionDefinition {
actionName := "github_readme" actionName := "github_readme"
actionDescription := "Get the README file of a GitHub repository to have a basic understanding of the project." actionDescription := "Get the README file of a GitHub repository to have a basic understanding of the project."
if g.customActionName != "" { if g.customActionName != "" {
actionName = g.customActionName actionName = g.customActionName
} }
return action.ActionDefinition{ return types.ActionDefinition{
Name: action.ActionDefinitionName(actionName), Name: types.ActionDefinitionName(actionName),
Description: actionDescription, Description: actionDescription,
Properties: map[string]jsonschema.Definition{ Properties: map[string]jsonschema.Definition{
"repository": { "repository": {

View File

@@ -4,7 +4,7 @@ import (
"context" "context"
"fmt" "fmt"
"github.com/mudler/LocalAgent/core/action" "github.com/mudler/LocalAgent/core/types"
"github.com/sashabaranov/go-openai/jsonschema" "github.com/sashabaranov/go-openai/jsonschema"
"github.com/tmc/langchaingo/tools/scraper" "github.com/tmc/langchaingo/tools/scraper"
) )
@@ -16,7 +16,7 @@ func NewScraper(config map[string]string) *ScraperAction {
type ScraperAction struct{} type ScraperAction struct{}
func (a *ScraperAction) Run(ctx context.Context, params action.ActionParams) (action.ActionResult, error) { func (a *ScraperAction) Run(ctx context.Context, params types.ActionParams) (types.ActionResult, error) {
result := struct { result := struct {
URL string `json:"url"` URL string `json:"url"`
}{} }{}
@@ -24,25 +24,25 @@ func (a *ScraperAction) Run(ctx context.Context, params action.ActionParams) (ac
if err != nil { if err != nil {
fmt.Printf("error: %v", err) fmt.Printf("error: %v", err)
return action.ActionResult{}, err return types.ActionResult{}, err
} }
scraper, err := scraper.New() scraper, err := scraper.New()
if err != nil { if err != nil {
fmt.Printf("error: %v", err) fmt.Printf("error: %v", err)
return action.ActionResult{}, err return types.ActionResult{}, err
} }
res, err := scraper.Call(ctx, result.URL) res, err := scraper.Call(ctx, result.URL)
if err != nil { if err != nil {
fmt.Printf("error: %v", err) fmt.Printf("error: %v", err)
return action.ActionResult{}, err return types.ActionResult{}, err
} }
return action.ActionResult{Result: res}, nil return types.ActionResult{Result: res}, nil
} }
func (a *ScraperAction) Definition() action.ActionDefinition { func (a *ScraperAction) Definition() types.ActionDefinition {
return action.ActionDefinition{ return types.ActionDefinition{
Name: "scrape", Name: "scrape",
Description: "Scrapes a full website content and returns the entire site data.", Description: "Scrapes a full website content and returns the entire site data.",
Properties: map[string]jsonschema.Definition{ Properties: map[string]jsonschema.Definition{

View File

@@ -6,7 +6,7 @@ import (
"log/slog" "log/slog"
"strings" "strings"
"github.com/mudler/LocalAgent/core/action" "github.com/mudler/LocalAgent/core/types"
"github.com/sashabaranov/go-openai/jsonschema" "github.com/sashabaranov/go-openai/jsonschema"
"github.com/tmc/langchaingo/tools/duckduckgo" "github.com/tmc/langchaingo/tools/duckduckgo"
"mvdan.cc/xurls/v2" "mvdan.cc/xurls/v2"
@@ -34,7 +34,7 @@ func NewSearch(config map[string]string) *SearchAction {
type SearchAction struct{ results int } type SearchAction struct{ results int }
func (a *SearchAction) Run(ctx context.Context, params action.ActionParams) (action.ActionResult, error) { func (a *SearchAction) Run(ctx context.Context, params types.ActionParams) (types.ActionResult, error) {
result := struct { result := struct {
Query string `json:"query"` Query string `json:"query"`
}{} }{}
@@ -42,19 +42,19 @@ func (a *SearchAction) Run(ctx context.Context, params action.ActionParams) (act
if err != nil { if err != nil {
fmt.Printf("error: %v", err) fmt.Printf("error: %v", err)
return action.ActionResult{}, err return types.ActionResult{}, err
} }
ddg, err := duckduckgo.New(a.results, "LocalAgent") ddg, err := duckduckgo.New(a.results, "LocalAgent")
if err != nil { if err != nil {
fmt.Printf("error: %v", err) fmt.Printf("error: %v", err)
return action.ActionResult{}, err return types.ActionResult{}, err
} }
res, err := ddg.Call(ctx, result.Query) res, err := ddg.Call(ctx, result.Query)
if err != nil { if err != nil {
fmt.Printf("error: %v", err) fmt.Printf("error: %v", err)
return action.ActionResult{}, err return types.ActionResult{}, err
} }
rxStrict := xurls.Strict() rxStrict := xurls.Strict()
@@ -69,11 +69,11 @@ func (a *SearchAction) Run(ctx context.Context, params action.ActionParams) (act
results = append(results, u) results = append(results, u)
} }
return action.ActionResult{Result: res, Metadata: map[string]interface{}{MetadataUrls: results}}, nil return types.ActionResult{Result: res, Metadata: map[string]interface{}{MetadataUrls: results}}, nil
} }
func (a *SearchAction) Definition() action.ActionDefinition { func (a *SearchAction) Definition() types.ActionDefinition {
return action.ActionDefinition{ return types.ActionDefinition{
Name: "search_internet", Name: "search_internet",
Description: "Search the internet for something.", Description: "Search the internet for something.",
Properties: map[string]jsonschema.Definition{ Properties: map[string]jsonschema.Definition{

View File

@@ -5,7 +5,7 @@ import (
"fmt" "fmt"
"net/smtp" "net/smtp"
"github.com/mudler/LocalAgent/core/action" "github.com/mudler/LocalAgent/core/types"
"github.com/sashabaranov/go-openai/jsonschema" "github.com/sashabaranov/go-openai/jsonschema"
) )
@@ -27,7 +27,7 @@ type SendMailAction struct {
smtpPort string smtpPort string
} }
func (a *SendMailAction) Run(ctx context.Context, params action.ActionParams) (action.ActionResult, error) { func (a *SendMailAction) Run(ctx context.Context, params types.ActionParams) (types.ActionResult, error) {
result := struct { result := struct {
Message string `json:"message"` Message string `json:"message"`
To string `json:"to"` To string `json:"to"`
@@ -37,7 +37,7 @@ func (a *SendMailAction) Run(ctx context.Context, params action.ActionParams) (a
if err != nil { if err != nil {
fmt.Printf("error: %v", err) fmt.Printf("error: %v", err)
return action.ActionResult{}, err return types.ActionResult{}, err
} }
// Authentication. // Authentication.
@@ -50,13 +50,13 @@ func (a *SendMailAction) Run(ctx context.Context, params action.ActionParams) (a
result.To, result.To,
}, []byte(result.Message)) }, []byte(result.Message))
if err != nil { if err != nil {
return action.ActionResult{}, err return types.ActionResult{}, err
} }
return action.ActionResult{Result: fmt.Sprintf("Email sent to %s", result.To)}, nil return types.ActionResult{Result: fmt.Sprintf("Email sent to %s", result.To)}, nil
} }
func (a *SendMailAction) Definition() action.ActionDefinition { func (a *SendMailAction) Definition() types.ActionDefinition {
return action.ActionDefinition{ return types.ActionDefinition{
Name: "send_email", Name: "send_email",
Description: "Send an email.", Description: "Send an email.",
Properties: map[string]jsonschema.Definition{ Properties: map[string]jsonschema.Definition{

View File

@@ -5,7 +5,7 @@ import (
"fmt" "fmt"
"log" "log"
"github.com/mudler/LocalAgent/core/action" "github.com/mudler/LocalAgent/core/types"
"github.com/sashabaranov/go-openai/jsonschema" "github.com/sashabaranov/go-openai/jsonschema"
"golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh"
) )
@@ -27,7 +27,7 @@ type ShellAction struct {
customDescription string customDescription string
} }
func (a *ShellAction) Run(ctx context.Context, params action.ActionParams) (action.ActionResult, error) { func (a *ShellAction) Run(ctx context.Context, params types.ActionParams) (types.ActionResult, error) {
result := struct { result := struct {
Command string `json:"command"` Command string `json:"command"`
Host string `json:"host"` Host string `json:"host"`
@@ -37,7 +37,7 @@ func (a *ShellAction) Run(ctx context.Context, params action.ActionParams) (acti
if err != nil { if err != nil {
fmt.Printf("error: %v", err) fmt.Printf("error: %v", err)
return action.ActionResult{}, err return types.ActionResult{}, err
} }
if a.host != "" && a.user != "" { if a.host != "" && a.user != "" {
@@ -47,13 +47,13 @@ func (a *ShellAction) Run(ctx context.Context, params action.ActionParams) (acti
output, err := sshCommand(a.privateKey, result.Command, result.User, result.Host) output, err := sshCommand(a.privateKey, result.Command, result.User, result.Host)
if err != nil { if err != nil {
return action.ActionResult{}, err return types.ActionResult{}, err
} }
return action.ActionResult{Result: output}, nil return types.ActionResult{Result: output}, nil
} }
func (a *ShellAction) Definition() action.ActionDefinition { func (a *ShellAction) Definition() types.ActionDefinition {
name := "shell" name := "shell"
description := "Run a shell command on a remote server." description := "Run a shell command on a remote server."
if a.customName != "" { if a.customName != "" {
@@ -63,8 +63,8 @@ func (a *ShellAction) Definition() action.ActionDefinition {
description = a.customDescription description = a.customDescription
} }
if a.host != "" && a.user != "" { if a.host != "" && a.user != "" {
return action.ActionDefinition{ return types.ActionDefinition{
Name: action.ActionDefinitionName(name), Name: types.ActionDefinitionName(name),
Description: description, Description: description,
Properties: map[string]jsonschema.Definition{ Properties: map[string]jsonschema.Definition{
"command": { "command": {
@@ -75,8 +75,8 @@ func (a *ShellAction) Definition() action.ActionDefinition {
Required: []string{"command"}, Required: []string{"command"},
} }
} }
return action.ActionDefinition{ return types.ActionDefinition{
Name: action.ActionDefinitionName(name), Name: types.ActionDefinitionName(name),
Description: description, Description: description,
Properties: map[string]jsonschema.Definition{ Properties: map[string]jsonschema.Definition{
"command": { "command": {

View File

@@ -4,7 +4,7 @@ import (
"context" "context"
"fmt" "fmt"
"github.com/mudler/LocalAgent/core/action" "github.com/mudler/LocalAgent/core/types"
"github.com/mudler/LocalAgent/services/connectors/twitter" "github.com/mudler/LocalAgent/services/connectors/twitter"
"github.com/sashabaranov/go-openai/jsonschema" "github.com/sashabaranov/go-openai/jsonschema"
) )
@@ -21,7 +21,7 @@ type PostTweetAction struct {
noCharacterLimit bool noCharacterLimit bool
} }
func (a *PostTweetAction) Run(ctx context.Context, params action.ActionParams) (action.ActionResult, error) { func (a *PostTweetAction) Run(ctx context.Context, params types.ActionParams) (types.ActionResult, error) {
result := struct { result := struct {
Text string `json:"text"` Text string `json:"text"`
}{} }{}
@@ -29,24 +29,24 @@ func (a *PostTweetAction) Run(ctx context.Context, params action.ActionParams) (
if err != nil { if err != nil {
fmt.Printf("error: %v", err) fmt.Printf("error: %v", err)
return action.ActionResult{}, err return types.ActionResult{}, err
} }
if !a.noCharacterLimit && len(result.Text) > 280 { if !a.noCharacterLimit && len(result.Text) > 280 {
return action.ActionResult{}, fmt.Errorf("tweet is too long, max 280 characters") return types.ActionResult{}, fmt.Errorf("tweet is too long, max 280 characters")
} }
client := twitter.NewTwitterClient(a.token) client := twitter.NewTwitterClient(a.token)
if err := client.Post(result.Text); err != nil { if err := client.Post(result.Text); err != nil {
return action.ActionResult{}, err return types.ActionResult{}, err
} }
return action.ActionResult{Result: fmt.Sprintf("twitter post created")}, nil return types.ActionResult{Result: fmt.Sprintf("twitter post created")}, nil
} }
func (a *PostTweetAction) Definition() action.ActionDefinition { func (a *PostTweetAction) Definition() types.ActionDefinition {
return action.ActionDefinition{ return types.ActionDefinition{
Name: "post_tweet", Name: "post_tweet",
Description: "Post a tweet", Description: "Post a tweet",
Properties: map[string]jsonschema.Definition{ Properties: map[string]jsonschema.Definition{

View File

@@ -4,7 +4,7 @@ import (
"context" "context"
"fmt" "fmt"
"github.com/mudler/LocalAgent/core/action" "github.com/mudler/LocalAgent/core/types"
"github.com/sashabaranov/go-openai/jsonschema" "github.com/sashabaranov/go-openai/jsonschema"
"github.com/tmc/langchaingo/tools/wikipedia" "github.com/tmc/langchaingo/tools/wikipedia"
) )
@@ -15,7 +15,7 @@ func NewWikipedia(config map[string]string) *WikipediaAction {
type WikipediaAction struct{} type WikipediaAction struct{}
func (a *WikipediaAction) Run(ctx context.Context, params action.ActionParams) (action.ActionResult, error) { func (a *WikipediaAction) Run(ctx context.Context, params types.ActionParams) (types.ActionResult, error) {
result := struct { result := struct {
Query string `json:"query"` Query string `json:"query"`
}{} }{}
@@ -23,20 +23,20 @@ func (a *WikipediaAction) Run(ctx context.Context, params action.ActionParams) (
if err != nil { if err != nil {
fmt.Printf("error: %v", err) fmt.Printf("error: %v", err)
return action.ActionResult{}, err return types.ActionResult{}, err
} }
wiki := wikipedia.New("LocalAgent") wiki := wikipedia.New("LocalAgent")
res, err := wiki.Call(ctx, result.Query) res, err := wiki.Call(ctx, result.Query)
if err != nil { if err != nil {
fmt.Printf("error: %v", err) fmt.Printf("error: %v", err)
return action.ActionResult{}, err return types.ActionResult{}, err
} }
return action.ActionResult{Result: res}, nil return types.ActionResult{Result: res}, nil
} }
func (a *WikipediaAction) Definition() action.ActionDefinition { func (a *WikipediaAction) Definition() types.ActionDefinition {
return action.ActionDefinition{ return types.ActionDefinition{
Name: "wikipedia", Name: "wikipedia",
Description: "Find wikipedia pages using the wikipedia api", Description: "Find wikipedia pages using the wikipedia api",
Properties: map[string]jsonschema.Definition{ Properties: map[string]jsonschema.Definition{

View File

@@ -5,6 +5,7 @@ import (
"github.com/bwmarrin/discordgo" "github.com/bwmarrin/discordgo"
"github.com/mudler/LocalAgent/core/agent" "github.com/mudler/LocalAgent/core/agent"
"github.com/mudler/LocalAgent/core/types"
"github.com/mudler/LocalAgent/pkg/xlog" "github.com/mudler/LocalAgent/pkg/xlog"
) )
@@ -24,14 +25,14 @@ func NewDiscord(config map[string]string) *Discord {
} }
} }
func (d *Discord) AgentResultCallback() func(state agent.ActionState) { func (d *Discord) AgentResultCallback() func(state types.ActionState) {
return func(state agent.ActionState) { return func(state types.ActionState) {
// Send the result to the bot // Send the result to the bot
} }
} }
func (d *Discord) AgentReasoningCallback() func(state agent.ActionCurrentState) bool { func (d *Discord) AgentReasoningCallback() func(state types.ActionCurrentState) bool {
return func(state agent.ActionCurrentState) bool { return func(state types.ActionCurrentState) bool {
// Send the reasoning to the bot // Send the reasoning to the bot
return true return true
} }
@@ -84,7 +85,7 @@ func (d *Discord) messageCreate(a *agent.Agent) func(s *discordgo.Session, m *di
content = strings.ReplaceAll(content, "<@"+s.State.User.ID+"> ", "") content = strings.ReplaceAll(content, "<@"+s.State.User.ID+"> ", "")
xlog.Info("Received message", "content", content) xlog.Info("Received message", "content", content)
job := a.Ask( job := a.Ask(
agent.WithText( types.WithText(
content, content,
), ),
) )

View File

@@ -7,6 +7,7 @@ import (
"github.com/google/go-github/v69/github" "github.com/google/go-github/v69/github"
"github.com/mudler/LocalAgent/core/agent" "github.com/mudler/LocalAgent/core/agent"
"github.com/mudler/LocalAgent/core/types"
"github.com/mudler/LocalAgent/pkg/xlog" "github.com/mudler/LocalAgent/pkg/xlog"
"github.com/sashabaranov/go-openai" "github.com/sashabaranov/go-openai"
@@ -50,14 +51,14 @@ func NewGithubIssueWatcher(config map[string]string) *GithubIssues {
} }
} }
func (g *GithubIssues) AgentResultCallback() func(state agent.ActionState) { func (g *GithubIssues) AgentResultCallback() func(state types.ActionState) {
return func(state agent.ActionState) { return func(state types.ActionState) {
// Send the result to the bot // Send the result to the bot
} }
} }
func (g *GithubIssues) AgentReasoningCallback() func(state agent.ActionCurrentState) bool { func (g *GithubIssues) AgentReasoningCallback() func(state types.ActionCurrentState) bool {
return func(state agent.ActionCurrentState) bool { return func(state types.ActionCurrentState) bool {
// Send the reasoning to the bot // Send the reasoning to the bot
return true return true
} }
@@ -175,7 +176,7 @@ func (g *GithubIssues) issuesService() {
} }
res := g.agent.Ask( res := g.agent.Ask(
agent.WithConversationHistory(messages), types.WithConversationHistory(messages),
) )
if res.Error != nil { if res.Error != nil {
xlog.Error("Error asking", "error", res.Error, "agent", g.agent.Character.Name) xlog.Error("Error asking", "error", res.Error, "agent", g.agent.Character.Name)

View File

@@ -7,6 +7,7 @@ import (
"github.com/google/go-github/v69/github" "github.com/google/go-github/v69/github"
"github.com/mudler/LocalAgent/core/agent" "github.com/mudler/LocalAgent/core/agent"
"github.com/mudler/LocalAgent/core/types"
"github.com/mudler/LocalAgent/pkg/xlog" "github.com/mudler/LocalAgent/pkg/xlog"
"github.com/sashabaranov/go-openai" "github.com/sashabaranov/go-openai"
@@ -50,14 +51,14 @@ func NewGithubPRWatcher(config map[string]string) *GithubPRs {
} }
} }
func (g *GithubPRs) AgentResultCallback() func(state agent.ActionState) { func (g *GithubPRs) AgentResultCallback() func(state types.ActionState) {
return func(state agent.ActionState) { return func(state types.ActionState) {
// Send the result to the bot // Send the result to the bot
} }
} }
func (g *GithubPRs) AgentReasoningCallback() func(state agent.ActionCurrentState) bool { func (g *GithubPRs) AgentReasoningCallback() func(state types.ActionCurrentState) bool {
return func(state agent.ActionCurrentState) bool { return func(state types.ActionCurrentState) bool {
// Send the reasoning to the bot // Send the reasoning to the bot
return true return true
} }
@@ -175,7 +176,7 @@ func (g *GithubPRs) prService() {
} }
res := g.agent.Ask( res := g.agent.Ask(
agent.WithConversationHistory(messages), types.WithConversationHistory(messages),
) )
if res.Error != nil { if res.Error != nil {
xlog.Error("Error asking", "error", res.Error, "agent", g.agent.Character.Name) xlog.Error("Error asking", "error", res.Error, "agent", g.agent.Character.Name)

View File

@@ -6,6 +6,7 @@ import (
"time" "time"
"github.com/mudler/LocalAgent/core/agent" "github.com/mudler/LocalAgent/core/agent"
"github.com/mudler/LocalAgent/core/types"
"github.com/mudler/LocalAgent/pkg/xlog" "github.com/mudler/LocalAgent/pkg/xlog"
"github.com/mudler/LocalAgent/services/actions" "github.com/mudler/LocalAgent/services/actions"
irc "github.com/thoj/go-ircevent" irc "github.com/thoj/go-ircevent"
@@ -30,14 +31,14 @@ func NewIRC(config map[string]string) *IRC {
} }
} }
func (i *IRC) AgentResultCallback() func(state agent.ActionState) { func (i *IRC) AgentResultCallback() func(state types.ActionState) {
return func(state agent.ActionState) { return func(state types.ActionState) {
// Send the result to the bot // Send the result to the bot
} }
} }
func (i *IRC) AgentReasoningCallback() func(state agent.ActionCurrentState) bool { func (i *IRC) AgentReasoningCallback() func(state types.ActionCurrentState) bool {
return func(state agent.ActionCurrentState) bool { return func(state types.ActionCurrentState) bool {
// Send the reasoning to the bot // Send the reasoning to the bot
return true return true
} }
@@ -105,7 +106,7 @@ func (i *IRC) Start(a *agent.Agent) {
go func() { go func() {
res := a.Ask( res := a.Ask(
agent.WithText(cleanedMessage), types.WithText(cleanedMessage),
) )
xlog.Info("Sending message", "message", res.Response, "channel", channel) xlog.Info("Sending message", "message", res.Response, "channel", channel)

View File

@@ -14,6 +14,7 @@ import (
"github.com/sashabaranov/go-openai" "github.com/sashabaranov/go-openai"
"github.com/mudler/LocalAgent/core/agent" "github.com/mudler/LocalAgent/core/agent"
"github.com/mudler/LocalAgent/core/types"
"github.com/slack-go/slack/socketmode" "github.com/slack-go/slack/socketmode"
@@ -39,14 +40,14 @@ func NewSlack(config map[string]string) *Slack {
} }
} }
func (t *Slack) AgentResultCallback() func(state agent.ActionState) { func (t *Slack) AgentResultCallback() func(state types.ActionState) {
return func(state agent.ActionState) { return func(state types.ActionState) {
// Send the result to the bot // Send the result to the bot
} }
} }
func (t *Slack) AgentReasoningCallback() func(state agent.ActionCurrentState) bool { func (t *Slack) AgentReasoningCallback() func(state types.ActionCurrentState) bool {
return func(state agent.ActionCurrentState) bool { return func(state types.ActionCurrentState) bool {
// Send the reasoning to the bot // Send the reasoning to the bot
return true return true
} }
@@ -71,7 +72,7 @@ func uniqueStringSlice(s []string) []string {
return list return list
} }
func generateAttachmentsFromJobResponse(j *agent.JobResult) (attachments []slack.Attachment) { func generateAttachmentsFromJobResponse(j *types.JobResult) (attachments []slack.Attachment) {
for _, state := range j.State { for _, state := range j.State {
// coming from the search action // coming from the search action
if urls, exists := state.Metadata[actions.MetadataUrls]; exists { if urls, exists := state.Metadata[actions.MetadataUrls]; exists {
@@ -148,7 +149,7 @@ func (t *Slack) handleChannelMessage(
} }
} }
agentOptions := []agent.JobOption{agent.WithText(message)} agentOptions := []types.JobOption{types.WithText(message)}
// If the last message has an image, we send it as a multi content message // If the last message has an image, we send it as a multi content message
if len(imageBytes.Bytes()) > 0 { if len(imageBytes.Bytes()) > 0 {
@@ -158,7 +159,7 @@ func (t *Slack) handleChannelMessage(
if err != nil { if err != nil {
xlog.Error(fmt.Sprintf("Error encoding image to base64: %v", err)) xlog.Error(fmt.Sprintf("Error encoding image to base64: %v", err))
} else { } else {
agentOptions = append(agentOptions, agent.WithImage(fmt.Sprintf("data:%s;base64,%s", mimeType, imgBase64))) agentOptions = append(agentOptions, types.WithImage(fmt.Sprintf("data:%s;base64,%s", mimeType, imgBase64)))
} }
} }
@@ -350,8 +351,8 @@ func (t *Slack) handleMention(
} }
res := a.Ask( res := a.Ask(
// agent.WithText(message), // types.WithText(message),
agent.WithConversationHistory(threadMessages), types.WithConversationHistory(threadMessages),
) )
res.Response = githubmarkdownconvertergo.Slack(res.Response) res.Response = githubmarkdownconvertergo.Slack(res.Response)

View File

@@ -9,6 +9,7 @@ import (
"github.com/go-telegram/bot" "github.com/go-telegram/bot"
"github.com/go-telegram/bot/models" "github.com/go-telegram/bot/models"
"github.com/mudler/LocalAgent/core/agent" "github.com/mudler/LocalAgent/core/agent"
"github.com/mudler/LocalAgent/core/types"
) )
type Telegram struct { type Telegram struct {
@@ -20,16 +21,16 @@ type Telegram struct {
// Send any text message to the bot after the bot has been started // Send any text message to the bot after the bot has been started
func (t *Telegram) AgentResultCallback() func(state agent.ActionState) { func (t *Telegram) AgentResultCallback() func(state types.ActionState) {
return func(state agent.ActionState) { return func(state types.ActionState) {
t.bot.SetMyDescription(t.agent.Context(), &bot.SetMyDescriptionParams{ t.bot.SetMyDescription(t.agent.Context(), &bot.SetMyDescriptionParams{
Description: state.Reasoning, Description: state.Reasoning,
}) })
} }
} }
func (t *Telegram) AgentReasoningCallback() func(state agent.ActionCurrentState) bool { func (t *Telegram) AgentReasoningCallback() func(state types.ActionCurrentState) bool {
return func(state agent.ActionCurrentState) bool { return func(state types.ActionCurrentState) bool {
t.bot.SetMyDescription(t.agent.Context(), &bot.SetMyDescriptionParams{ t.bot.SetMyDescription(t.agent.Context(), &bot.SetMyDescriptionParams{
Description: state.Reasoning, Description: state.Reasoning,
}) })
@@ -45,7 +46,7 @@ func (t *Telegram) Start(a *agent.Agent) {
bot.WithDefaultHandler(func(ctx context.Context, b *bot.Bot, update *models.Update) { bot.WithDefaultHandler(func(ctx context.Context, b *bot.Bot, update *models.Update) {
go func() { go func() {
res := a.Ask( res := a.Ask(
agent.WithText( types.WithText(
update.Message.Text, update.Message.Text,
), ),
) )

View File

@@ -7,6 +7,7 @@ import (
"os/signal" "os/signal"
"github.com/mudler/LocalAgent/core/agent" "github.com/mudler/LocalAgent/core/agent"
"github.com/mudler/LocalAgent/core/types"
"github.com/mudler/LocalAgent/pkg/xlog" "github.com/mudler/LocalAgent/pkg/xlog"
"github.com/mudler/LocalAgent/services/connectors/twitter" "github.com/mudler/LocalAgent/services/connectors/twitter"
"github.com/sashabaranov/go-openai" "github.com/sashabaranov/go-openai"
@@ -19,14 +20,14 @@ type Twitter struct {
noCharacterLimit bool noCharacterLimit bool
} }
func (t *Twitter) AgentResultCallback() func(state agent.ActionState) { func (t *Twitter) AgentResultCallback() func(state types.ActionState) {
return func(state agent.ActionState) { return func(state types.ActionState) {
} }
} }
func (t *Twitter) AgentReasoningCallback() func(state agent.ActionCurrentState) bool { func (t *Twitter) AgentReasoningCallback() func(state types.ActionCurrentState) bool {
return func(state agent.ActionCurrentState) bool { return func(state types.ActionCurrentState) bool {
return true return true
} }
@@ -98,7 +99,7 @@ func (t *Twitter) run(a *agent.Agent) error {
} }
res := a.Ask( res := a.Ask(
agent.WithConversationHistory( types.WithConversationHistory(
[]openai.ChatCompletionMessage{ []openai.ChatCompletionMessage{
{ {
Role: "system", Role: "system",

View File

@@ -9,14 +9,13 @@ import (
"strings" "strings"
"time" "time"
coreTypes "github.com/mudler/LocalAgent/core/types"
"github.com/mudler/LocalAgent/pkg/llm" "github.com/mudler/LocalAgent/pkg/llm"
"github.com/mudler/LocalAgent/pkg/xlog" "github.com/mudler/LocalAgent/pkg/xlog"
"github.com/mudler/LocalAgent/services" "github.com/mudler/LocalAgent/services"
"github.com/mudler/LocalAgent/webui/types" "github.com/mudler/LocalAgent/webui/types"
"github.com/sashabaranov/go-openai/jsonschema" "github.com/sashabaranov/go-openai/jsonschema"
"github.com/mudler/LocalAgent/core/action"
"github.com/mudler/LocalAgent/core/agent"
"github.com/mudler/LocalAgent/core/sse" "github.com/mudler/LocalAgent/core/sse"
"github.com/mudler/LocalAgent/core/state" "github.com/mudler/LocalAgent/core/state"
@@ -72,7 +71,7 @@ func (a *App) Notify(pool *state.AgentPool) func(c *fiber.Ctx) error {
a := pool.GetAgent(c.Params("name")) a := pool.GetAgent(c.Params("name"))
a.Ask( a.Ask(
agent.WithText(query), coreTypes.WithText(query),
) )
_, _ = c.Write([]byte("Message sent")) _, _ = c.Write([]byte("Message sent"))
@@ -275,7 +274,7 @@ func (a *App) Chat(pool *state.AgentPool) func(c *fiber.Ctx) error {
return return
} }
res := a.Ask( res := a.Ask(
agent.WithText(query), coreTypes.WithText(query),
) )
if res.Error != nil { if res.Error != nil {
xlog.Error("Error asking agent", "agent", agentName, "error", res.Error) xlog.Error("Error asking agent", "agent", agentName, "error", res.Error)
@@ -307,8 +306,8 @@ func (a *App) Chat(pool *state.AgentPool) func(c *fiber.Ctx) error {
func (a *App) ExecuteAction(pool *state.AgentPool) func(c *fiber.Ctx) error { func (a *App) ExecuteAction(pool *state.AgentPool) func(c *fiber.Ctx) error {
return func(c *fiber.Ctx) error { return func(c *fiber.Ctx) error {
payload := struct { payload := struct {
Config map[string]string `json:"config"` Config map[string]string `json:"config"`
Params action.ActionParams `json:"params"` Params coreTypes.ActionParams `json:"params"`
}{} }{}
if err := c.BodyParser(&payload); err != nil { if err := c.BodyParser(&payload); err != nil {
@@ -365,7 +364,7 @@ func (a *App) Responses(pool *state.AgentPool) func(c *fiber.Ctx) error {
} }
res := a.Ask( res := a.Ask(
agent.WithConversationHistory(messages), coreTypes.WithConversationHistory(messages),
) )
if res.Error != nil { if res.Error != nil {
xlog.Error("Error asking agent", "agent", agentName, "error", res.Error) xlog.Error("Error asking agent", "agent", agentName, "error", res.Error)

View File

@@ -12,9 +12,9 @@ import (
fiber "github.com/gofiber/fiber/v2" fiber "github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/filesystem" "github.com/gofiber/fiber/v2/middleware/filesystem"
"github.com/gofiber/fiber/v2/middleware/keyauth" "github.com/gofiber/fiber/v2/middleware/keyauth"
"github.com/mudler/LocalAgent/core/agent"
"github.com/mudler/LocalAgent/core/sse" "github.com/mudler/LocalAgent/core/sse"
"github.com/mudler/LocalAgent/core/state" "github.com/mudler/LocalAgent/core/state"
"github.com/mudler/LocalAgent/core/types"
"github.com/mudler/LocalAgent/pkg/xlog" "github.com/mudler/LocalAgent/pkg/xlog"
"github.com/mudler/LocalAgent/services" "github.com/mudler/LocalAgent/services"
) )
@@ -95,7 +95,7 @@ func (app *App) registerRoutes(pool *state.AgentPool, webapp *fiber.App) {
webapp.Get("/status/:name", func(c *fiber.Ctx) error { webapp.Get("/status/:name", func(c *fiber.Ctx) error {
history := pool.GetStatusHistory(c.Params("name")) history := pool.GetStatusHistory(c.Params("name"))
if history == nil { if history == nil {
history = &state.Status{ActionResults: []agent.ActionState{}} history = &state.Status{ActionResults: []types.ActionState{}}
} }
// reverse history // reverse history