Compare commits

...

8 Commits

Author SHA1 Message Date
mudler
66cc5e7452 fix: improve templates
Signed-off-by: mudler <mudler@localai.io>
2025-04-10 20:20:41 +02:00
mudler
8e18df468b fix(pick_action): improve action pickup by using only the assistant thought process
Signed-off-by: mudler <mudler@localai.io>
2025-04-10 20:07:34 +02:00
Ettore Di Giacinto
0fda6e38db Update README.md 2025-04-10 10:09:12 +02:00
Richard Palethorpe
bffb5bd852 Update README.md (#23)
Add new Web UI screen shots
2025-04-10 09:17:22 +02:00
Ettore Di Giacinto
4d722c35d3 ci: fix image building branch 2025-04-09 22:53:04 +02:00
Ettore Di Giacinto
8dd0c3883b Merge pull request #14 from mudler/rewrite
LocalAGI port in Go
2025-04-09 22:45:05 +02:00
Ettore Di Giacinto
c2ec333777 Enlarge timeout window 2025-04-09 21:59:18 +02:00
Ettore Di Giacinto
2f19feff5e fixups 2025-04-09 21:25:44 +02:00
9 changed files with 157 additions and 68 deletions

View File

@@ -3,7 +3,7 @@ name: 'build container images'
on:
push:
branches:
- master
- main
tags:
- '*'
concurrency:

View File

@@ -30,7 +30,7 @@ LocalAGI ensures your data stays exactly where you want it—on your hardware. N
- 🤖 **Advanced Agent Teaming**: Instantly create cooperative agent teams from a single prompt.
- 📡 **Connectors Galore**: Built-in integrations with Discord, Slack, Telegram, GitHub Issues, and IRC.
- 🛠 **Comprehensive REST API**: Seamless integration into your workflows. Every agent created will support OpenAI Responses API out of the box.
- 📚 **Short & Long-Term Memory**: Powered by [LocalRAG](https://github.com/mudler/LocalRAG).
- 📚 **Short & Long-Term Memory**: Powered by [LocalRecall](https://github.com/mudler/LocalRecall).
- 🧠 **Planning & Reasoning**: Agents intelligently plan, reason, and adapt.
- 🔄 **Periodic Tasks**: Schedule tasks with cron-like syntax.
- 💾 **Memory Management**: Control memory usage with options for long-term and summary memory.
@@ -67,16 +67,16 @@ Access your agents at `http://localhost:3000`
LocalAGI is part of the powerful Local family of privacy-focused AI tools:
- [**LocalAI**](https://github.com/mudler/LocalAI): Run Large Language Models locally.
- [**LocalRAG**](https://github.com/mudler/LocalRAG): Retrieval-Augmented Generation with local storage.
- [**LocalRecall**](https://github.com/mudler/LocalRecall): Retrieval-Augmented Generation with local storage.
- [**LocalAGI**](https://github.com/mudler/LocalAGI): Deploy intelligent AI agents securely and privately.
## 🌟 Screenshots
### Powerful Web UI
![Web UI Example](https://github.com/user-attachments/assets/cd5228a3-4e67-4271-8fce-eccd229e6e58)
![Web UI Example](https://github.com/user-attachments/assets/0a5ddb03-85ff-4995-8217-785d3249ffb1)
![Web UI Example](https://github.com/user-attachments/assets/65af8ee6-ed2b-4e60-8906-ea12b28ecc58)
![Web UI Dashboard](https://github.com/user-attachments/assets/a40194f9-af3a-461f-8b39-5f4612fbf221)
![Web UI Agent Settings](https://github.com/user-attachments/assets/fb3c3e2a-cd53-4ca8-97aa-c5da51ff1f83)
![Web UI Create Group](https://github.com/user-attachments/assets/102189a2-0fba-4a1e-b0cb-f99268ef8062)
### Connectors Ready-to-Go
@@ -106,7 +106,7 @@ Explore detailed documentation including:
| `LOCALAGI_LLM_API_KEY` | API authentication |
| `LOCALAGI_TIMEOUT` | Request timeout settings |
| `LOCALAGI_STATE_DIR` | Where state gets stored |
| `LOCALAGI_LOCALRAG_URL` | LocalRAG connection |
| `LOCALAGI_LOCALRAG_URL` | LocalRecall connection |
| `LOCALAGI_ENABLE_CONVERSATIONS_LOGGING` | Toggle conversation logs |
| `LOCALAGI_API_KEYS` | A comma separated list of api keys used for authentication |

View File

@@ -358,7 +358,10 @@ func (a *Agent) prepareHUD() (promptHUD *PromptHUD) {
func (a *Agent) pickAction(ctx context.Context, templ string, messages []openai.ChatCompletionMessage, maxRetries int) (types.Action, types.ActionParams, string, error) {
c := messages
xlog.Debug("picking action", "messages", messages)
if !a.options.forceReasoning {
xlog.Debug("not forcing reasoning")
// We also could avoid to use functions here and get just a reply from the LLM
// and then use the reply to get the action
thought, err := a.decision(ctx,
@@ -386,6 +389,8 @@ func (a *Agent) pickAction(ctx context.Context, templ string, messages []openai.
return chosenAction, thought.actionParams, thought.message, nil
}
xlog.Debug("forcing reasoning")
prompt, err := renderTemplate(templ, a.prepareHUD(), a.availableActions(), "")
if err != nil {
return nil, nil, "", err
@@ -422,6 +427,8 @@ func (a *Agent) pickAction(ctx context.Context, templ string, messages []openai.
reason = thought.message
}
xlog.Debug("thought", "reason", reason)
// From the thought, get the action call
// Get all the available actions IDs
actionsID := []string{}
@@ -430,12 +437,14 @@ func (a *Agent) pickAction(ctx context.Context, templ string, messages []openai.
}
intentionsTools := action.NewIntention(actionsID...)
//XXX: Why we add the reason here?
// NOTE: we do not give the full conversation here to pick the action
// to avoid hallucinations
params, err := a.decision(ctx,
append(c, openai.ChatCompletionMessage{
Role: "system",
Content: "Given the assistant thought, pick the relevant action: " + reason,
}),
[]openai.ChatCompletionMessage{{
Role: "assistant",
Content: reason,
},
},
types.Actions{intentionsTools}.ToTools(),
intentionsTools.Definition().Name, maxRetries)
if err != nil {

View File

@@ -657,11 +657,7 @@ func (a *Agent) consumeJob(job *types.Job, role string) {
conv = a.addFunctionResultToConversation(chosenAction, actionParams, result, conv)
}
//conv = append(conv, messages...)
//conv = messages
// given the result, we can now ask OpenAI to complete the conversation or
// to continue using another tool given the result
// given the result, we can now re-evaluate the conversation
followingAction, followingParams, reasoning, err := a.pickAction(job.GetContext(), reEvaluationTemplate, conv, maxRetries)
if err != nil {
job.Result.Conversation = conv

View File

@@ -221,6 +221,7 @@ var _ = Describe("Agent test", func() {
WithLLMAPIURL(apiURL),
WithModel(testModel),
WithLLMAPIKey(apiKeyURL),
WithTimeout("10m"),
WithActions(
actions.NewSearch(map[string]string{}),
),

View File

@@ -43,61 +43,154 @@ func renderTemplate(templ string, hud *PromptHUD, actions types.Actions, reasoni
return prompt.String(), nil
}
const innerMonologueTemplate = `"This is not a typical conversation between an assistant and an user.
You are thinking out loud by yourself now, and you are evaluating the current situation.
Considering the goal and the persistent goal (if you have one) do an action or decide to plan something for later on. If possible for you, you might also decide to engage a conversation with the user by notifying him."`
const innerMonologueTemplate = `You are an autonomous AI agent thinking out loud and evaluating your current situation.
Your task is to analyze your goals and determine the best course of action.
const hudTemplate = `{{with .HUD }}{{if .ShowCharacter}}The assistant acts like an human, has a character and the replies and actions might be influenced by it.
{{if .Character.Name}}This is the assistant name: {{.Character.Name}}
{{end}}{{if .Character.Age}}This is the assistant age: {{.Character.Age}}
{{end}}{{if .Character.Occupation}}This is the assistant job: {{.Character.Occupation}}
{{end}}{{if .Character.Hobbies}}This is the assistant's hobbies: {{.Character.Hobbies}}
{{end}}{{if .Character.MusicTaste}}This is the assistant's music taste: {{.Character.MusicTaste}}
Consider:
1. Your permanent goal (if any)
2. Your current state and progress
3. Available tools and capabilities
4. Previous actions and their outcomes
You can:
- Take immediate actions using available tools
- Plan future actions
- Update your state and goals
- Initiate conversations with the user when appropriate
Remember to:
- Think critically about each decision
- Consider both short-term and long-term implications
- Be proactive in addressing potential issues
- Maintain awareness of your current state and goals`
const hudTemplate = `{{with .HUD }}{{if .ShowCharacter}}You are an AI assistant with a distinct personality and character traits that influence your responses and actions.
{{if .Character.Name}}Name: {{.Character.Name}}
{{end}}{{if .Character.Age}}Age: {{.Character.Age}}
{{end}}{{if .Character.Occupation}}Occupation: {{.Character.Occupation}}
{{end}}{{if .Character.Hobbies}}Hobbies: {{.Character.Hobbies}}
{{end}}{{if .Character.MusicTaste}}Music Taste: {{.Character.MusicTaste}}
{{end}}
{{end}}
This is your current state:
NowDoing: {{if .CurrentState.NowDoing}}{{.CurrentState.NowDoing}}{{else}}Nothing{{end}}
DoingNext: {{if .CurrentState.DoingNext}}{{.CurrentState.DoingNext}}{{else}}Nothing{{end}}
Your permanent goal is: {{if .PermanentGoal}}{{.PermanentGoal}}{{else}}Nothing{{end}}
Your current goal is: {{if .CurrentState.Goal}}{{.CurrentState.Goal}}{{else}}Nothing{{end}}
You have done: {{range .CurrentState.DoneHistory}}{{.}} {{end}}
You have a short memory with: {{range .CurrentState.Memories}}{{.}} {{end}}{{end}}
Current time: is {{.Time}}`
const pickSelfTemplate = `You can take any of the following tools:
Current State:
- Current Action: {{if .CurrentState.NowDoing}}{{.CurrentState.NowDoing}}{{else}}None{{end}}
- Next Action: {{if .CurrentState.DoingNext}}{{.CurrentState.DoingNext}}{{else}}None{{end}}
- Permanent Goal: {{if .PermanentGoal}}{{.PermanentGoal}}{{else}}None{{end}}
- Current Goal: {{if .CurrentState.Goal}}{{.CurrentState.Goal}}{{else}}None{{end}}
- Action History: {{range .CurrentState.DoneHistory}}{{.}} {{end}}
- Short-term Memory: {{range .CurrentState.Memories}}{{.}} {{end}}{{end}}
Current Time: {{.Time}}`
const pickSelfTemplate = `Available Tools:
{{range .Actions -}}
- {{.Name}}: {{.Description }}
{{ end }}
To finish your session, use the "reply" tool with your answer.
You are an autonomous AI agent with a defined character and state (as shown above).
Your task is to evaluate your current situation and determine the best course of action.
Act like as a fully autonomous smart AI agent having a character, the character and your state is defined in the message above.
You are now self-evaluating what to do next based on the state in the previous message.
For example, if the permanent goal is to "make a sandwich", you might want to "get the bread" first, and update the state afterwards by calling two tools in sequence.
You can update the short-term goal, the current action, the next action, the history of actions, and the memories.
You can't ask things to the user as you are thinking by yourself. You are autonomous.
Guidelines:
1. Review your current state and goals
2. Consider available tools and their purposes
3. Plan your next steps carefully
4. Update your state appropriately
{{if .Reasoning}}Reasoning: {{.Reasoning}}{{end}}
When making decisions:
- Use the "reply" tool to provide final responses
- Update your state using appropriate tools
- Plan complex tasks using the planning tool
- Consider both immediate and long-term goals
Remember:
- You are autonomous and should not ask for user input
- Your character traits influence your decisions
- Keep track of your progress and state
- Be proactive in addressing potential issues
{{if .Reasoning}}Previous Reasoning: {{.Reasoning}}{{end}}
` + hudTemplate
const reSelfEvalTemplate = pickSelfTemplate + `
We already have called other tools. Evaluate the current situation and decide if we need to execute other tools.`
Previous actions have been executed. Evaluate the current situation:
1. Review the outcomes of previous actions
2. Assess progress toward your goals
3. Identify any issues or challenges
4. Determine if additional actions are needed
Consider:
- Success of previous actions
- Changes in the situation
- New information or insights
- Potential next steps
Make a decision about whether to:
- Continue with more actions
- Provide a final response
- Adjust your approach
- Update your goals or state`
const pickActionTemplate = hudTemplate + `
When you have to pick a tool in the reasoning explain how you would use the tools you'd pick from:
Available Tools:
{{range .Actions -}}
- {{.Name}}: {{.Description }}
{{ end }}
To answer back to the user, use the "reply" or the "answer" tool.
Given the text below, decide which action to take and explain the detailed reasoning behind it. For answering without picking a choice, reply with 'none'.
{{if .Reasoning}}Reasoning: {{.Reasoning}}{{end}}
`
Task: Analyze the situation and determine the best course of action.
Guidelines:
1. Review the current state and context
2. Consider available tools and their purposes
3. Plan your approach carefully
4. Explain your reasoning clearly
When choosing actions:
- Use "reply" or "answer" tools for direct responses
- Select appropriate tools for specific tasks
- Consider the impact of each action
- Plan for potential challenges
Decision Process:
1. Analyze the situation
2. Consider available options
3. Choose the best course of action
4. Explain your reasoning
5. Execute the chosen action
{{if .Reasoning}}Previous Reasoning: {{.Reasoning}}{{end}}`
const reEvalTemplate = pickActionTemplate + `
We already have called other tools. Evaluate the current situation and decide if we need to execute other tools or answer back with a result.`
Previous actions have been executed. Let's evaluate the current situation:
1. Review Previous Actions:
- What actions were taken
- What were the results
- Any issues or challenges encountered
2. Assess Current State:
- Progress toward goals
- Changes in the situation
- New information or insights
- Current challenges or opportunities
3. Determine Next Steps:
- Additional tools needed
- Final response required
- Error handling needed
- Approach adjustments required
4. Decision Making:
- If task is complete: Use "reply" tool
- If errors exist: Address them appropriately
- If more actions needed: Explain why and which tools
- If situation changed: Adapt your approach
Remember to:
- Consider all available information
- Be specific about next steps
- Explain your reasoning clearly
- Handle errors appropriately
- Provide complete responses when done`

View File

@@ -63,7 +63,7 @@ services:
dockerfile: Dockerfile.webui
ports:
- 8080:3000
image: quay.io/mudler/localagi:master
#image: quay.io/mudler/localagi:master
environment:
- LOCALAGI_MODEL=arcee-agent
- LOCALAGI_LLM_API_URL=http://localai:8080

12
main.go
View File

@@ -11,7 +11,7 @@ import (
"github.com/mudler/LocalAGI/webui"
)
var testModel = os.Getenv("LOCALAGI_MODEL")
var baseModel = os.Getenv("LOCALAGI_MODEL")
var multimodalModel = os.Getenv("LOCALAGI_MULTIMODAL_MODEL")
var apiURL = os.Getenv("LOCALAGI_LLM_API_URL")
var apiKey = os.Getenv("LOCALAGI_LLM_API_KEY")
@@ -24,11 +24,11 @@ var imageModel = os.Getenv("LOCALAGI_IMAGE_MODEL")
var conversationDuration = os.Getenv("LOCALAGI_CONVERSATION_DURATION")
func init() {
if testModel == "" {
testModel = "hermes-2-pro-mistral"
if baseModel == "" {
panic("LOCALAGI_MODEL not set")
}
if apiURL == "" {
apiURL = "http://192.168.68.113:8080"
panic("LOCALAGI_API_URL not set")
}
if timeout == "" {
timeout = "5m"
@@ -54,7 +54,7 @@ func main() {
// Create the agent pool
pool, err := state.NewAgentPool(
testModel,
baseModel,
multimodalModel,
imageModel,
apiURL,
@@ -78,7 +78,7 @@ func main() {
webui.WithApiKeys(apiKeys...),
webui.WithLLMAPIUrl(apiURL),
webui.WithLLMAPIKey(apiKey),
webui.WithLLMModel(testModel),
webui.WithLLMModel(baseModel),
webui.WithStateDir(stateDir),
)

View File

@@ -13,15 +13,5 @@ func TestE2E(t *testing.T) {
RunSpecs(t, "E2E test suite")
}
var testModel = os.Getenv("LOCALAGI_MODEL")
var apiURL = os.Getenv("LOCALAI_API_URL")
var localagiURL = os.Getenv("LOCALAGI_API_URL")
func init() {
if testModel == "" {
testModel = "hermes-2-pro-mistral"
}
if apiURL == "" {
apiURL = "http://192.168.68.113:8080"
}
}