mirror of
https://github.com/mudler/LocalAI.git
synced 2026-11-06 04:23:15 -05:00
fix(chat): preserve complete tool source URLs
Keep balanced parentheses in source URLs and decode MCP text arrays before
extracting links. This preserves Wikipedia paths and escaped query
separators instead of appending truncated citations.
Assisted-by: Codex:gpt-6
Signed-off-by: Stefan Walcz <stefan.walcz@walcz.de>
(cherry picked from commit 9b81cb20ab)
This commit is contained in:
1 parent
23012a7c4a
commit
041f2337df
3 files changed
+32
-4
No files matched your search
@@ -1,6 +1,7 @@
|
||||
package openai
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
@@ -12,9 +13,9 @@ import (
|
||||
var numberToken = regexp.MustCompile(`\b\d+(?:[.,]\d+)?\b`)
|
||||
|
||||
// urlToken matches an http(s) URL up to the first character that cannot be
|
||||
// part of one in tool output: whitespace, a quote, a closing bracket of
|
||||
// Markdown or JSON, or the backslash of a JSON escape.
|
||||
var urlToken = regexp.MustCompile(`https?://[^\s"'<>()\[\]{}\\]+`)
|
||||
// part of one in tool output. Parentheses are allowed inside URL paths;
|
||||
// sourceURLs removes unmatched closing parentheses from Markdown links.
|
||||
var urlToken = regexp.MustCompile(`https?://[^\s"'<>\[\]{}\\]+`)
|
||||
|
||||
// maxSourceURLs caps the appended source line; a search tool can return
|
||||
// dozens of links, and the first ones are the ones it ranked highest.
|
||||
@@ -27,8 +28,20 @@ func sourceURLs(texts []string) []string {
|
||||
var urls []string
|
||||
seen := map[string]struct{}{}
|
||||
for _, text := range texts {
|
||||
// ExecuteMCPToolCall JSON-encodes multiple TextContent results.
|
||||
// Decode that envelope so escaped query separators remain intact.
|
||||
var parts []string
|
||||
var single string
|
||||
if json.Unmarshal([]byte(text), &parts) == nil {
|
||||
text = strings.Join(parts, "\n")
|
||||
} else if json.Unmarshal([]byte(text), &single) == nil {
|
||||
text = single
|
||||
}
|
||||
for _, token := range urlToken.FindAllString(text, -1) {
|
||||
token = strings.TrimRight(token, ".,;:!?")
|
||||
for strings.HasSuffix(token, ")") && strings.Count(token, ")") > strings.Count(token, "(") {
|
||||
token = strings.TrimRight(strings.TrimSuffix(token, ")"), ".,;:!?")
|
||||
}
|
||||
if _, ok := seen[token]; ok || strings.HasSuffix(token, "://") {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -1,11 +1,25 @@
|
||||
package openai
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("sourceURLs", func() {
|
||||
It("preserves parentheses inside URLs and removes surrounding Markdown punctuation", func() {
|
||||
url := "https://en.wikipedia.org/wiki/Mercury_(planet)"
|
||||
Expect(sourceURLs([]string{"[Mercury](" + url + "). (" + url + ")"})).To(Equal([]string{url}))
|
||||
})
|
||||
|
||||
It("decodes multiple MCP text results before extracting URLs", func() {
|
||||
url := "https://example.com/search?a=1&b=2"
|
||||
encoded, err := json.Marshal([]string{"First " + url + "\n", "Second https://example.com/other"})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(sourceURLs([]string{string(encoded)})).To(Equal([]string{url, "https://example.com/other"}))
|
||||
})
|
||||
|
||||
It("returns unique URLs in order of appearance, at most five", func() {
|
||||
text := "x https://1.example/a, y (https://2.example/b) z https://1.example/a " +
|
||||
"[l](https://3.example/c). \"https://4.example/d\" http://5.example/e; https://6.example/f"
|
||||
|
||||
@@ -160,7 +160,8 @@ deterministic and applies to each request on its own:
|
||||
3. Otherwise the distinct URLs of those tool results are collected in the order
|
||||
they first appear, at most five, and appended after a blank line as one line:
|
||||
`Quellen: https://a.example/test, https://b.example/oil`. Punctuation that
|
||||
ends a sentence is not taken as part of a URL.
|
||||
ends a sentence is not taken as part of a URL. Parentheses inside URL paths
|
||||
and query parameters in JSON-encoded MCP text results are preserved.
|
||||
4. If no tool result contains a URL, nothing is appended. No URL is ever made
|
||||
up: every link on the line was returned by a tool.
|
||||
|
||||
|
||||
Reference in new issue
Block a user