Changeset 0.13.1 (#65)

This commit is contained in:
2026-02-25 23:56:27 +00:00
parent 8292a6efa8
commit 113b98ace4
24 changed files with 1565 additions and 24 deletions

View File

@@ -38,6 +38,7 @@ type completionRequest struct {
TopP *float64 `json:"top_p,omitempty"`
Stream *bool `json:"stream,omitempty"`
AttachmentIDs []string `json:"attachment_ids,omitempty"` // staged attachment UUIDs to include in request
DisabledTools []string `json:"disabled_tools,omitempty"` // tool names to exclude from this request
}
// CompletionHandler proxies LLM requests through the backend.
@@ -207,7 +208,7 @@ func (h *CompletionHandler) Complete(c *gin.Context) {
// Attach tool definitions if model supports tool calling and tools are available
hasBrowserTools := h.hub != nil && h.hub.IsConnected(userID)
if caps.ToolCalling && (tools.HasTools() || hasBrowserTools) {
provReq.Tools = h.buildToolDefs(c.Request.Context(), userID, hasBrowserTools)
provReq.Tools = h.buildToolDefs(c.Request.Context(), userID, hasBrowserTools, req.DisabledTools)
}
// Determine streaming
@@ -225,8 +226,15 @@ func (h *CompletionHandler) Complete(c *gin.Context) {
// buildToolDefs converts registered tools to provider-format tool definitions.
// If includeBrowser is true, also fetches tool schemas from enabled browser extensions.
func (h *CompletionHandler) buildToolDefs(ctx context.Context, userID string, includeBrowser bool) []providers.ToolDef {
allTools := tools.AllDefinitions()
// Tools whose names appear in disabledTools are excluded.
func (h *CompletionHandler) buildToolDefs(ctx context.Context, userID string, includeBrowser bool, disabledTools []string) []providers.ToolDef {
// Build disabled set for O(1) lookup
disabled := make(map[string]bool, len(disabledTools))
for _, name := range disabledTools {
disabled[name] = true
}
allTools := tools.AllDefinitionsFiltered(disabled)
defs := make([]providers.ToolDef, 0, len(allTools))
for _, t := range allTools {
defs = append(defs, providers.ToolDef{
@@ -262,6 +270,9 @@ func (h *CompletionHandler) buildToolDefs(ctx context.Context, userID string, in
continue
}
for _, t := range manifest.Tools {
if disabled[t.Name] {
continue
}
defs = append(defs, providers.ToolDef{
Type: "function",
Function: providers.FunctionDef{
@@ -277,6 +288,65 @@ func (h *CompletionHandler) buildToolDefs(ctx context.Context, userID string, in
return defs
}
// ── List Available Tools ────────────────────
// GET /api/v1/tools
//
// Returns all registered server-side tools plus browser extension tools
// for the current user. Used by the frontend to build the tools toggle menu.
type toolInfo struct {
Name string `json:"name"`
DisplayName string `json:"display_name"`
Description string `json:"description"`
Category string `json:"category"`
}
func (h *CompletionHandler) ListTools(c *gin.Context) {
userID := c.GetString("user_id")
// Server-side tools
allDefs := tools.AllDefinitions()
result := make([]toolInfo, 0, len(allDefs))
for _, d := range allDefs {
result = append(result, toolInfo{
Name: d.Name,
DisplayName: d.DisplayName,
Description: d.Description,
Category: d.Category,
})
}
// Browser extension tools
if h.hub != nil && h.hub.IsConnected(userID) {
exts, err := h.stores.Extensions.ListForUser(c.Request.Context(), userID)
if err == nil {
for _, ext := range exts {
if ext.Tier != "browser" {
continue
}
var manifest struct {
Tools []struct {
Name string `json:"name"`
Description string `json:"description"`
} `json:"tools"`
}
if err := json.Unmarshal(ext.Manifest, &manifest); err != nil {
continue
}
for _, t := range manifest.Tools {
result = append(result, toolInfo{
Name: t.Name,
Description: t.Description,
Category: "browser",
})
}
}
}
}
c.JSON(http.StatusOK, gin.H{"data": result})
}
// ── Streaming Completion (SSE) with Tool Loop ──
const maxToolIterations = 10 // safety limit on tool call rounds