mirror of
https://github.com/mudler/LocalAI.git
synced 2026-11-07 13:03:20 -05:00
A chat now enables a set of connections for an add-on whose tools run with
a credential, and the model names one of them in each call. This applies to
every add-on that declares a credential in its manifest.
- The Tools menu row of the add-on lists the connections with a checkbox
each. The saved agent names a set too (an empty set means each chat
chooses). A chat that a connector binding started keeps that binding
alone. With one connection, it is the set. With none enabled, the tools
are not offered.
- With one connection enabled the tools are unchanged. With two or more,
the host adds a required `connection` argument to every tool of the
add-on in the definitions it gives the model: an enum of the connection
names (the display name folded to lower case, digits and hyphens; the
description keeps the display name). The add-on never sees the argument.
- The name is checked against the set the chat has now, not against all the
connections of the person. A missing or unknown name returns a sentence
that lists the allowed names, and nothing is sent. A write tool never runs
without the name. Text in a tool result cannot widen the set, and the
owner checks the chosen binding against the set again.
- The resource list of the named connection is the only one that applies.
Results, the approval card and the text for a pending change name the
connection; the audit line has the binding ID.
- A connection name must be unique per person and add-on among the
credential-only connections, compared by name fold. Older duplicates get
a numeric suffix in the model's list.
- The stored chat, draft and agent values move from one binding ID per
add-on to a list of IDs. A single string is read as a set of one in the
stores and in every request, so older data and clients keep working.
PUT /api/chats/{id}/connections takes `connections`; the older
`connection` field still works.
Assisted-by: Claude:claude-sonnet-5-5 go gofmt ginkgo node eslint playwright swag
106 lines
5.8 KiB
Go
106 lines
5.8 KiB
Go
package studio
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"github.com/labstack/echo/v4"
|
|
"github.com/mudler/LocalAI/core/schema"
|
|
studiosvc "github.com/mudler/LocalAI/core/services/studio"
|
|
)
|
|
|
|
func addonList(c echo.Context, h *Handlers) error {
|
|
list, err := h.svc.Addons(c.Request().Context(), userID(c), c.Param("id"))
|
|
if err != nil {
|
|
return failFor(c, err)
|
|
}
|
|
cmds, err := h.svc.CommandRunner(c.Request().Context(), userID(c), c.Param("id"))
|
|
if err != nil {
|
|
return failFor(c, err)
|
|
}
|
|
return writeAddonList(c, list, cmds)
|
|
}
|
|
|
|
func writeAddonList(c echo.Context, list []studiosvc.AddonInfo, cmds studiosvc.Commands) error {
|
|
out := schema.ChatsAddonList{Addons: make([]schema.ChatsAddon, 0, len(list)), Commands: string(cmds.State), CommandsReason: cmds.Reason,
|
|
CommandsIsolation: cmds.Isolation, CommandsProvider: cmds.Provider, CommandsConsent: cmds.Consent,
|
|
CommandsFallback: cmds.Fallback, CommandsFallbackReason: cmds.FallbackReason}
|
|
if v := cmds.ExecutionStatus; v != nil {
|
|
out.ExecutionStatus = &schema.ChatsExecutionStatus{Readiness: v.Readiness, Isolation: v.Isolation, Explanation: v.Explanation, UnknownReason: v.UnknownReason, Generation: v.Generation, Incarnation: v.Incarnation}
|
|
}
|
|
for _, a := range list {
|
|
out.Addons = append(out.Addons, addonOut(a))
|
|
}
|
|
return c.JSON(http.StatusOK, out)
|
|
}
|
|
|
|
// addonOut is one add-on row with its switch and, for an add-on that runs
|
|
// with a credential, the connections and the ones this chat may use.
|
|
func addonOut(a studiosvc.AddonInfo) schema.ChatsAddon {
|
|
row := schema.ChatsAddon{ID: a.ID, Tools: a.Tools, Off: a.Off, Title: a.Title, Description: a.Description, Credentialed: a.Credentialed,
|
|
Enabled: a.Enabled.IDs(), ConnectionBy: a.Enabled.By, NeedsConnection: a.Credentialed && len(a.Enabled.Items) == 0}
|
|
if len(row.Enabled) == 0 {
|
|
row.Enabled = nil
|
|
}
|
|
for _, x := range a.Connections {
|
|
row.Connections = append(row.Connections, schema.ChatsConnection{ID: x.ID, Name: x.Name, Handle: x.Handle})
|
|
}
|
|
return row
|
|
}
|
|
|
|
// ListChatAddons lists the add-ons a chat can use.
|
|
// @Summary List the add-ons a chat can use.
|
|
// @Description The add-ons whose tools the signed-in user may use now, each with the chat's switch, and whether the chat can run commands at its next turn (commands: available, off, unavailable, none, or switched_off when the chat switched the built-in group shell off). When commands is available, commands_provider says who serves bash (builtin: directly on this machine with no isolation and with its network, or the add-on's ID) and commands_isolation says isolated or host; commands_consent is ask when each command waits for a yes in the chat, and commands_fallback names an add-on that would serve but does not (commands_fallback_reason: off, or why it cannot run). Without the add-on host the list is empty.
|
|
// @Tags chats
|
|
// @Param id path string true "conversation id"
|
|
// @Success 200 {object} schema.ChatsAddonList "The add-ons and their switches"
|
|
// @Failure 400 {object} schema.ErrorResponse "The request is not valid"
|
|
// @Failure 404 {object} schema.ErrorResponse "No such conversation, or it is another user's"
|
|
// @Router /api/chats/{id}/addons [get]
|
|
func (h *Handlers) ListChatAddons(c echo.Context) error { return addonList(c, h) }
|
|
|
|
// SetChatAddons sets the add-ons a chat has switched off.
|
|
// @Summary Switch the tools of add-ons on and off for a chat.
|
|
// @Description The list replaces the earlier one. The next turn of the chat gets the tools of the add-ons that are on.
|
|
// @Tags chats
|
|
// @Param id path string true "conversation id"
|
|
// @Param request body schema.ChatsAddonSwitches true "the IDs of the add-ons that are off"
|
|
// @Success 200 {object} schema.ChatsAddonList "The add-ons and their switches now in force"
|
|
// @Failure 400 {object} schema.ErrorResponse "The request is not valid"
|
|
// @Failure 404 {object} schema.ErrorResponse "No such conversation, or it is another user's"
|
|
// @Router /api/chats/{id}/addons [put]
|
|
func (h *Handlers) SetChatAddons(c echo.Context) error {
|
|
req, ok := bind[schema.ChatsAddonSwitches](c, "off is required")
|
|
if !ok {
|
|
return nil
|
|
}
|
|
if err := h.svc.SetAddonsOff(c.Request().Context(), userID(c), c.Param("id"), req.Off); err != nil {
|
|
return failFor(c, err)
|
|
}
|
|
return addonList(c, h)
|
|
}
|
|
|
|
// SetChatConnection sets the connections a chat may use for an add-on.
|
|
// @Summary Choose the connections a chat may use for an add-on.
|
|
// @Description For an add-on whose tools run with the token of one of your connections, the host never picks connections for you. With exactly one it is enabled; with several, choose the set here, and until then the tools of the add-on are not offered to the model. With two or more enabled, the model names the connection in every tool call by a generic connection argument; it can only name an enabled one. An empty list clears the choice. Choosing connections switches the add-on on for the chat. If the saved agent of the chat names the set, the answer is 400: the agent decides. A request with the older single connection field is read as a set of one.
|
|
// @Tags chats
|
|
// @Param id path string true "conversation id"
|
|
// @Param request body schema.ChatsConnectionSwitch true "the add-on and the connections"
|
|
// @Success 200 {object} schema.ChatsAddonList "The add-ons and their switches now in force"
|
|
// @Failure 400 {object} schema.ErrorResponse "The request is not valid, or the agent names the connection"
|
|
// @Failure 404 {object} schema.ErrorResponse "No such conversation, or it is another user's"
|
|
// @Router /api/chats/{id}/connections [put]
|
|
func (h *Handlers) SetChatConnection(c echo.Context) error {
|
|
req, ok := bind[schema.ChatsConnectionSwitch](c, "addon is required")
|
|
if !ok {
|
|
return nil
|
|
}
|
|
ids := req.Connections
|
|
if len(ids) == 0 && req.Connection != "" {
|
|
ids = []string{req.Connection}
|
|
}
|
|
if err := h.svc.SetConnections(c.Request().Context(), userID(c), c.Param("id"), req.Addon, ids); err != nil {
|
|
return failFor(c, err)
|
|
}
|
|
return addonList(c, h)
|
|
}
|