Files
Ettore Di Giacinto 73a6be8264 feat: consume cogito for agent reasoning (#320)
* WIP

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>

* Drop old webui

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>

* Almost there

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>

* It builds

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>

* Make it build

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>

* fixups, still doesn't work

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>

* unused now

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>

* Send result before closing

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>

* Fix observability

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>

* Drop MCP code and wire-up in cogito

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>

* Drop some templates

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>

* Keep reporting into conv

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>

* tests fixups

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>

* tests fixups

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>

* fixups

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>

* Do not complete observable during thought process

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>

* Update cogito

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>

* Fixups

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>

* Fixups

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>

* Fixups

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>

* Drop unneded option now

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>

* Fixups

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>

* Better handling of user tools

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>

* TEST

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>

* Add flake attempts

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>

* Revert "TEST"

This reverts commit 8b12a9fd03.

* tKeep indexing MCP actions

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>

* Split CI jobs to improve speed

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>

* CI optimizations

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>

* Bump timeout

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>

* Bump cogito

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>

* fix: always commit last progress

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>

* chore: better management of observables

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>

---------

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
2025-10-27 18:41:28 +01:00

154 lines
3.1 KiB
Go

package agent
import (
"encoding/json"
"os"
"github.com/mudler/LocalAGI/core/action"
"github.com/mudler/LocalAGI/core/types"
"golang.org/x/exp/slices"
"github.com/mudler/LocalAGI/pkg/xlog"
"github.com/sashabaranov/go-openai"
)
type Messages []openai.ChatCompletionMessage
func (m Messages) ToOpenAI() []openai.ChatCompletionMessage {
return []openai.ChatCompletionMessage(m)
}
func (m Messages) RemoveIf(f func(msg openai.ChatCompletionMessage) bool) Messages {
for i := len(m) - 1; i >= 0; i-- {
if f(m[i]) {
m = append(m[:i], m[i+1:]...)
}
}
return m
}
func (m Messages) String() string {
s := ""
for _, cc := range m {
s += cc.Role + ": " + cc.Content + "\n"
}
return s
}
func (m Messages) Exist(content string) bool {
for _, cc := range m {
if cc.Content == content {
return true
}
}
return false
}
func (m Messages) RemoveLastUserMessage() Messages {
if len(m) == 0 {
return m
}
for i := len(m) - 1; i >= 0; i-- {
if m[i].Role == UserRole {
return append(m[:i], m[i+1:]...)
}
}
return m
}
func (m Messages) Save(path string) error {
content, err := json.MarshalIndent(m, "", " ")
if err != nil {
return err
}
f, err := os.Create(path)
if err != nil {
return err
}
defer f.Close()
if _, err := f.Write(content); err != nil {
return err
}
return nil
}
func (m Messages) GetLatestUserMessage() *openai.ChatCompletionMessage {
xlog.Debug("Getting latest user message", "messages", m)
for i := len(m) - 1; i >= 0; i-- {
msg := m[i]
if msg.Role == UserRole {
return &msg
}
}
return nil
}
// getAvailableActionsForJob returns available actions including user-defined ones for a specific job
func (a *Agent) getAvailableActionsForJob(job *types.Job) types.Actions {
// Start with regular available actions
baseActions := a.availableActions()
// Add user-defined actions from the job
userTools := job.GetUserTools()
if len(userTools) > 0 {
userDefinedActions := types.CreateUserDefinedActions(userTools)
baseActions = append(baseActions, userDefinedActions...)
xlog.Debug("Added user-defined actions", "definitions", userTools)
}
return baseActions
}
func (a *Agent) availableActions() types.Actions {
// defaultActions := append(a.options.userActions, action.NewReply())
defaultActions := slices.Clone(a.options.userActions)
if a.options.initiateConversations && a.selfEvaluationInProgress { // && self-evaluation..
acts := append(defaultActions, action.NewConversation())
if a.options.enableHUD {
acts = append(acts, action.NewState())
}
//if a.options.canStopItself {
// acts = append(acts, action.NewStop())
// }
return acts
}
if a.options.canStopItself {
acts := append(defaultActions, action.NewStop())
if a.options.enableHUD {
acts = append(acts, action.NewState())
}
return acts
}
if a.options.enableHUD {
return append(defaultActions, action.NewState())
}
return defaultActions
}
func (a *Agent) prepareHUD() (promptHUD *PromptHUD) {
if !a.options.enableHUD {
return nil
}
return &PromptHUD{
Character: a.Character,
CurrentState: *a.currentState,
PermanentGoal: a.options.permanentGoal,
ShowCharacter: a.options.showCharacter,
}
}