mirror of
https://github.com/mudler/LocalAI.git
synced 2026-11-07 21:13:27 -05:00
feat(memory): add a Memory On/Off switch and private chats
Memory now has one switch, On or Off, in the Memory tab of the account settings. Off means nothing from the notes is put in the prompt, the model has no memory skill, tool or note kind, nothing is proposed or saved (also by triggers and other runs that start by themselves), and the model is told in one line that memory is off. The notes stay and can still be read, exported and deleted. A chat can be private: the Memory row of its Tools menu is the memory switch group, stored with the chat. The narrowest level wins: chat, agent, person, server. A saved agent cannot widen the choice of the person. The tools list says which level is off (memory.code, blocked_by, fix); the chat shows a chip and one line, and the agent form shows the person's switch as a read-only line. New API: GET and PUT /api/chats/memory for the switch and the save level, and GET /api/chats/memory/export for a zip of the notes. The Memory tab gains the switch, the three save levels, Export and Forget everything. Assisted-by: Claude:claude-sonnet-5-5
This commit is contained in:
55 files changed
+2255
-80
No files matched your search
File diff suppressed because one or more lines are too long.
@@ -217,6 +217,7 @@ func writeToolsPanel(c echo.Context, p studiosvc.ToolsPanel) error {
|
||||
Usable: g.Usable, Reason: g.Reason, Provider: g.Provider, Providers: g.Providers,
|
||||
Title: g.Title, Description: g.Description, WhenOff: g.WhenOff})
|
||||
}
|
||||
out.Memory = memoryStateOut(p.Memory)
|
||||
for _, a := range p.Addons {
|
||||
out.Addons = append(out.Addons, addonOut(a))
|
||||
}
|
||||
@@ -234,7 +235,7 @@ func writeToolsPanel(c echo.Context, p studiosvc.ToolsPanel) error {
|
||||
|
||||
// ListChatTools lists what a chat can use besides its built-in tools.
|
||||
// @Summary List the tools a chat can switch on and off.
|
||||
// @Description The groups of built-in tools (shell, web, files, media, collections, subagents, triggers and saved_agents; a group the server does not offer is absent, and shell is listed even when nothing can run commands, not usable with the reason), add-ons, the MCP servers of the chat's model and your MCP connectors, each with the chat's switch and whether it can be used now (with the reason when not). A chat with a saved agent lists only what the agent grants. fallbacks lists the built-in tools (bash, web_search, web_fetch) that an installed add-on replaces but that no add-on serves in this chat now, with the add-on and whether the built-in serves instead.
|
||||
// @Description The groups of built-in tools (shell, web, files, media, collections, subagents, triggers, memory and saved_agents; a group the server does not offer is absent, and shell is listed even when nothing can run commands, not usable with the reason), add-ons, the MCP servers of the chat's model and your MCP connectors, each with the chat's switch and whether it can be used now (with the reason when not). A chat with a saved agent lists only what the agent grants. memory says whether memory works in the chat and, when it does not, the level that turned it off (code, blocked_by) and where to turn it on (fix). fallbacks lists the built-in tools (bash, web_search, web_fetch) that an installed add-on replaces but that no add-on serves in this chat now, with the add-on and whether the built-in serves instead.
|
||||
// @Tags chats
|
||||
// @Param id path string true "conversation id"
|
||||
// @Success 200 {object} schema.ChatsToolsPanel "The tools and their switches"
|
||||
@@ -246,7 +247,7 @@ func (h *Handlers) ListChatTools(c echo.Context) error { return toolsPanel(c, h)
|
||||
// SetChatBuiltins sets the groups of built-in tools a chat has switched off,
|
||||
// and the opt-in groups it has switched on.
|
||||
// @Summary Switch groups of built-in tools on and off for a chat.
|
||||
// @Description off replaces the earlier list of groups that are off. The groups are shell (bash, whether the Sandbox add-on or the built-in bash on this machine serves it), web (web_search and web_fetch), files (list_files, read_file, write_file, edit_file, move_file, delete_file, search_files and read_document), media (describe_image and transcribe_audio), collections (list_collections and search_collection), subagents (spawn_agent), triggers (propose_trigger, list_triggers, update_trigger and delete_trigger) and saved_agents. A sub-agent follows the switches of its parent chat. An opt-in group (opt_in in the list, such as saved_agents: list_agents and the agent argument of spawn_agent) is off until on names it; on replaces the earlier list of opt-in groups that are on, and an opt-in group in off is ignored. Omit on to keep it. A switch never adds what the administrator has off or the user may not use. The next turn of the chat gets the tools that are on.
|
||||
// @Description off replaces the earlier list of groups that are off. The groups are shell (bash, whether the Sandbox add-on or the built-in bash on this machine serves it), web (web_search and web_fetch), files (list_files, read_file, write_file, edit_file, move_file, delete_file, search_files and read_document), media (describe_image and transcribe_audio), collections (list_collections and search_collection), subagents (spawn_agent), triggers (propose_trigger, list_triggers, update_trigger and delete_trigger), memory (your notes: off makes the chat a private chat that neither reads nor saves memory) and saved_agents. A sub-agent follows the switches of its parent chat. An opt-in group (opt_in in the list, such as saved_agents: list_agents and the agent argument of spawn_agent) is off until on names it; on replaces the earlier list of opt-in groups that are on, and an opt-in group in off is ignored. Omit on to keep it. A switch never adds what the administrator has off or the user may not use. The next turn of the chat gets the tools that are on.
|
||||
// @Tags chats
|
||||
// @Param id path string true "conversation id"
|
||||
// @Param request body schema.ChatsBuiltinSwitches true "the groups that are off"
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
package studio
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/http"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
|
||||
"github.com/mudler/LocalAI/core/schema"
|
||||
studiosvc "github.com/mudler/LocalAI/core/services/studio"
|
||||
)
|
||||
|
||||
var memoryRules = []errRule{
|
||||
fixed(http.StatusServiceUnavailable, "unavailable", "the memory settings cannot be stored on this server", studiosvc.ErrMemorySettings),
|
||||
fixed(http.StatusNotFound, typeNotFound, "there are no notes to export", studiosvc.ErrNoNotes),
|
||||
}
|
||||
|
||||
func failMemory(c echo.Context, err error) error { return mapErr(c, err, memoryRules, failFor) }
|
||||
|
||||
func memorySettingsOut(m studiosvc.MemorySettings) schema.ChatsMemorySettings {
|
||||
return schema.ChatsMemorySettings{Enabled: m.Enabled, EnabledSet: m.EnabledSet, SaveMode: m.SaveMode,
|
||||
SaveModeSet: m.SaveModeSet, Provider: m.Provider, Available: m.Available}
|
||||
}
|
||||
|
||||
func memoryStateOut(m studiosvc.MemoryReason) schema.ChatsMemoryState {
|
||||
out := schema.ChatsMemoryState{On: m.On, Code: m.Code, BlockedBy: m.By, Reason: m.Reason}
|
||||
if m.Fix != nil {
|
||||
out.Fix = &schema.ChatsMemoryFix{Kind: m.Fix.Kind, Target: m.Fix.Target, Field: m.Fix.Field}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// GetMemory reads your memory choices.
|
||||
// @Summary Read your memory settings.
|
||||
// @Description Memory is the short notes the assistant reads before it answers and may save. enabled is the switch for all your chats and agents: a private chat (the memory group of a chat, see PUT /api/chats/{id}/builtins), an agent that turns memory off, or this switch off each make memory off in a chat, and the narrowest wins; a saved agent cannot widen your choice. enabled_set is false until you choose; before that memory is on, unless you had disabled the Memory add-on to stop it. save_mode is how a note is saved (ask, auto or never) and applies as the strictest rule with the rules of the host; a chat from a messaging app always asks. Your notes stay and can be listed, exported and deleted while memory is off.
|
||||
// @Tags chats
|
||||
// @Success 200 {object} schema.ChatsMemorySettings "Your memory settings"
|
||||
// @Router /api/chats/memory [get]
|
||||
func (h *Handlers) GetMemory(c echo.Context) error {
|
||||
m, err := h.svc.MemorySettings(c.Request().Context(), userID(c))
|
||||
if err != nil {
|
||||
return failMemory(c, err)
|
||||
}
|
||||
return c.JSON(http.StatusOK, memorySettingsOut(m))
|
||||
}
|
||||
|
||||
// PutMemory changes your memory choices.
|
||||
// @Summary Change your memory settings.
|
||||
// @Description Sets enabled (memory On or Off for every chat and agent) and save_mode (ask, auto or never). A field left out stays as it is. Off means nothing is put in the prompt, the model has no tool or skill for notes, nothing is proposed or saved (also by triggers and other runs that start by themselves) and the model is told in one line that memory is off. The settings are kept per person with the account, so every frontend of a cluster reads the same answer. 400 for a value that is not allowed.
|
||||
// @Tags chats
|
||||
// @Accept json
|
||||
// @Param request body schema.ChatsMemoryRequest true "the choices to change"
|
||||
// @Success 200 {object} schema.ChatsMemorySettings "Your memory settings now in force"
|
||||
// @Failure 400 {object} schema.ErrorResponse "A value is not allowed"
|
||||
// @Failure 503 {object} schema.ErrorResponse "The settings cannot be stored on this server"
|
||||
// @Router /api/chats/memory [put]
|
||||
func (h *Handlers) PutMemory(c echo.Context) error {
|
||||
req, ok := bind[schema.ChatsMemoryRequest](c, "the body must be {enabled, save_mode}")
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
m, err := h.svc.SetMemory(c.Request().Context(), userID(c), studiosvc.MemoryUpdate{Enabled: req.Enabled, SaveMode: req.SaveMode})
|
||||
if err != nil {
|
||||
return failMemory(c, err)
|
||||
}
|
||||
return c.JSON(http.StatusOK, memorySettingsOut(m))
|
||||
}
|
||||
|
||||
// ExportMemory downloads your notes.
|
||||
// @Summary Download your memory notes as a zip file.
|
||||
// @Description The Markdown files of your memory folders (yours, each agent's and each messaging conversation's) with their paths. scope (user, agent or channel) and key (the agent ID or the conversation folder name, as GET /api/chats/context-files lists them) narrow it to one group. It works while memory is off. 404 when there is nothing to export.
|
||||
// @Tags chats
|
||||
// @Produce application/zip
|
||||
// @Param scope query string false "user, agent or channel"
|
||||
// @Param key query string false "the agent ID or the conversation folder, with scope"
|
||||
// @Success 200 {file} file "A zip file of the notes"
|
||||
// @Failure 404 {object} schema.ErrorResponse "No notes"
|
||||
// @Router /api/chats/memory/export [get]
|
||||
func (h *Handlers) ExportMemory(c echo.Context) error {
|
||||
var buf bytes.Buffer
|
||||
if _, err := h.svc.ExportMemory(c.Request().Context(), userID(c), &buf, c.QueryParam("scope"), c.QueryParam("key")); err != nil {
|
||||
return failMemory(c, err)
|
||||
}
|
||||
c.Response().Header().Set(echo.HeaderContentDisposition, `attachment; filename="memory-notes.zip"`)
|
||||
return c.Blob(http.StatusOK, "application/zip", buf.Bytes())
|
||||
}
|
||||
Reference in new issue
Block a user