Download apps/shared/OpenClawKit/Tests/OpenClawKitTests/ChatSourcePreviewTests.swift from SaylorTwift/openclaw: direct link, hf CLI and curl.
- Browser
- Download file 18.8 kB
-
https://huggingface.co/SaylorTwift/openclaw/resolve/main/apps/shared/OpenClawKit/Tests/OpenClawKitTests/ChatSourcePreviewTests.swift
- Command line
-
hf download hf://SaylorTwift/openclaw/apps/shared/OpenClawKit/Tests/OpenClawKitTests/ChatSourcePreviewTests.swift
-
curl -L -o ChatSourcePreviewTests.swift https://huggingface.co/SaylorTwift/openclaw/resolve/main/apps/shared/OpenClawKit/Tests/OpenClawKitTests/ChatSourcePreviewTests.swift
18.8 kB
| import Foundation | |
| import OpenClawKit | |
| import Testing | |
| @testable import OpenClawChatUI | |
| ("Chat source previews") | |
| struct ChatSourcePreviewTests { | |
| private let runID = "source-run" | |
| private let first = "https://example.com/article" | |
| private let second = "https://example.org/page" | |
| func `completed answer uses cited normalized results from its own run`() { | |
| let answer = self.answer("[First](\(self.first)#section) and [second](\(self.second)).") | |
| let search = self.search([ | |
| self.row(self.first, title: "**Useful** title", snippet: "Recorded search snippet."), | |
| self.row(self.second, title: "Second page", snippet: "A second snippet."), | |
| self.row("https://uncited.example.com/", title: "Uncited", snippet: "Never shown."), | |
| ]) | |
| let page = String(repeating: "A readable paragraph recorded from the fetched page. ", count: 3) | |
| var projector = ChatSourcePreviewProjector() | |
| let result = projector.project([ | |
| self.search([self.row(self.first, title: "Wrong run", snippet: "Wrong run")], run: "other-run"), | |
| search, | |
| self.fetch(self.first, final: self.first, title: "Fetched title", text: "# Heading\n\n\(page)"), | |
| answer, | |
| ])[answer.id] ?? [] | |
| #expect(result.map(\.title) == ["Fetched title", "Second page"]) | |
| #expect(result.map(\.excerptKind) == [.page, .search]) | |
| #expect(result.first?.excerpt == page.trimmingCharacters(in: .whitespacesAndNewlines)) | |
| } | |
| func `Markdown code images and uncited text do not become sources`() { | |
| let answer = self.answer(""" | |
| `[inline](\(self.first))` | |
| ```markdown | |
| [fenced](\(self.first)) | |
| ``` | |
| ) | |
| [Actual][ref] | |
| [ref]: \(self.second) | |
| """) | |
| var projector = ChatSourcePreviewProjector() | |
| let result = projector.project([ | |
| self.search([self.row(self.first), self.row(self.second)]), answer, | |
| ])[answer.id] ?? [] | |
| #expect(result.map(\.url.absoluteString) == [self.second]) | |
| } | |
| func `failures mismatched tool identity and unproven payloads are excluded`() throws { | |
| let answer = self.answer("[source](\(self.first))") | |
| let payload = self.searchPayload([self.row(self.first)]) | |
| let cases: [[OpenClawChatMessage]] = [ | |
| [self.tool(payload, name: "web_search", error: true)], | |
| [self.tool(payload, name: "exec")], | |
| [self.call("web_fetch"), self.tool(payload, name: "web_search")], | |
| [self.tool(["kind": "results", "results": [self.row(self.first)]], name: "web_search")], | |
| [self.fetch(self.first, final: self.first, status: 403)], | |
| [self.tool(payload, name: "web_search", run: "other-run")], | |
| ] | |
| for messages in cases { | |
| var projector = ChatSourcePreviewProjector() | |
| #expect((projector.project(messages + [answer])[answer.id] ?? []).isEmpty) | |
| } | |
| let raw: [String: Any] = [ | |
| "role": "assistant", "__openclaw": ["runId": self.runID], | |
| "content": [[ | |
| "type": "tool_result", | |
| "tool_use_id": "call", | |
| "name": "web_search", | |
| "runId": "other-run", | |
| "details": payload, | |
| ]], | |
| ] | |
| let contradictory = try JSONDecoder().decode( | |
| OpenClawChatMessage.self, from: JSONSerialization.data(withJSONObject: raw)) | |
| var projector = ChatSourcePreviewProjector() | |
| #expect((projector.project([self.call("web_search"), contradictory, answer])[answer.id] ?? []).isEmpty) | |
| #expect(contradictory.content.first?.id == "call") | |
| let roundTrip = try JSONDecoder().decode( | |
| OpenClawChatMessage.self, from: JSONEncoder().encode(contradictory)) | |
| #expect(roundTrip.content.first?.runId == "other-run") | |
| } | |
| func `recorded redirects collapse aliases and later fetches refresh the destination`() { | |
| let answer = self.answer("[original](\(self.first)) and [destination](\(self.second))") | |
| let page = String(repeating: "Fresh page paragraph. ", count: 5) | |
| var projector = ChatSourcePreviewProjector() | |
| let result = projector.project([ | |
| self.search([self.row(self.first, snippet: "Old search snippet")]), | |
| self.fetch(self.first, final: self.second, title: "Initial destination"), | |
| self.fetch(self.second, final: self.second, title: "Refreshed destination", text: page), | |
| answer, | |
| ])[answer.id] ?? [] | |
| #expect(result.count == 1) | |
| #expect(result.first?.url.absoluteString == self.second) | |
| #expect(result.first?.title == "Refreshed destination") | |
| #expect(result.first?.excerptKind == .page) | |
| } | |
| func `page headings and provider answers never masquerade as recorded excerpts`() { | |
| let answer = self.answer("[source](\(self.first))") | |
| var projector = ChatSourcePreviewProjector() | |
| let result = projector.project([ | |
| self.tool([ | |
| "kind": "answer", "externalContent": self.external("web_search"), | |
| "answer": self.wrap("Combined answer", name: "web_search"), | |
| "citations": [self.row(self.first)], | |
| ], name: "web_search"), | |
| self.fetch(self.first, final: self.first, text: "# Heading\n\n- Navigation\n- More navigation"), | |
| answer, | |
| ])[answer.id] ?? [] | |
| #expect(result.count == 1) | |
| #expect(result.first?.excerpt == nil) | |
| } | |
| func `credentials unsafe schemes and dedicated GitHub items are excluded before card limit`() { | |
| let excluded = (1...9).map { "https://github.com/example/project/issues/\($0)" } | |
| + ["https://user:password@example.com/private", "javascript:alert(1)"] | |
| let valid = ["https://github.com/example/project", "https://docs.example.com/chat/guide"] | |
| let links = excluded + valid + [self.first] | |
| let answer = self.answer(links.map { "[link](\($0))" }.joined(separator: " ")) | |
| var projector = ChatSourcePreviewProjector() | |
| let result = projector.project([ | |
| self.search(links.map { self.row($0) }), | |
| self.fetch(self.first, final: "https://github.com/example/project/pull/42"), | |
| answer, | |
| ])[answer.id] ?? [] | |
| #expect(result.map(\.url.absoluteString) == valid) | |
| } | |
| func `session links and redirect targets are excluded only at the configured origins before the limit`() throws { | |
| let context = try OpenClawChatSourceContext( | |
| gatewayURL: #require(URL(string: "https://gateway.example.com/control/")), | |
| basePath: "/control", | |
| publicOrigin: URL(string: "https://public.example.com")) | |
| let sessions = (1...9).map { "https://gateway.example.com/control/chat/main/session-\($0)" } | |
| let links = sessions + [ | |
| "https://public.example.com/control/dashboard/main", | |
| self.first, | |
| "https://external.example.com/control/chat/main", | |
| "https://gateway.example.com/control/chat", | |
| "https://gateway.example.com/docs/chat/guide", | |
| ] | |
| let answer = self.answer(links.map { "[link](\($0))" }.joined(separator: " ")) | |
| var projector = ChatSourcePreviewProjector() | |
| let result = projector.project([ | |
| self.search(links.map { self.row($0) }), | |
| self.fetch(self.first, final: "https://gateway.example.com/control/chat/main/redirect"), answer, | |
| ], context: context)[answer.id] ?? [] | |
| #expect(result.map(\.url.absoluteString) == Array(links.suffix(3))) | |
| } | |
| (arguments: [ | |
| (native: "/team%20a", configured: "", encoded: "/team%20a", distinct: "/team%2520a"), | |
| (native: "/%E7%A0%94%E7%A9%B6", configured: "", encoded: "/%E7%A0%94%E7%A9%B6", distinct: "/research"), | |
| (native: "/team%2Fa", configured: "", encoded: "/team%2Fa", distinct: "/team/a"), | |
| (native: "/socket", configured: "/team a", encoded: "/team%20a", distinct: "/team%2520a"), | |
| (native: "/socket", configured: "/研究", encoded: "/%E7%A0%94%E7%A9%B6", distinct: "/research"), | |
| ]) | |
| func `loaded context excludes encoded mounted sessions without collapsing distinct paths`( | |
| mount: (native: String, configured: String, encoded: String, distinct: String)) async throws | |
| { | |
| let origin = "https://gateway.example.com" | |
| let publicOrigin = "https://public.example.com" | |
| let config = try JSONSerialization.data(withJSONObject: [ | |
| "runtimeConfig": ["gateway": [ | |
| "controlUi": ["basePath": mount.configured], | |
| "publicOrigin": publicOrigin, | |
| ]], | |
| ]) | |
| let gatewayURL = try #require(URL(string: "wss://gateway.example.com/socket")) | |
| let controlPageURL = try #require(URL(string: origin + mount.native)) | |
| let resources = OpenClawChatSourceResources( | |
| gatewayURL: gatewayURL, | |
| nativeControlPageURL: controlPageURL, | |
| request: { _, _ in | |
| Issue.record("Accepted configuration should not require an HTTP bootstrap request") | |
| throw URLError(.unsupportedURL) | |
| }, | |
| loadConfig: { config }, | |
| isCurrent: { true }) | |
| let loadedContext = await resources.loadContext() | |
| let context = try #require(loadedContext) | |
| let session = origin + mount.encoded + "/chat/main/~key/session" | |
| let dashboard = publicOrigin + mount.encoded + "/dashboard/main/session" | |
| let distinct = origin + mount.distinct + "/chat/main/session" | |
| let external = "https://external.example.com" + mount.encoded + "/chat/main/session" | |
| let links = [session, dashboard, self.first, distinct, external, self.second] | |
| let answer = self.answer(links.map { "[link](\($0))" }.joined(separator: " ")) | |
| var projector = ChatSourcePreviewProjector() | |
| let result = projector.project([ | |
| self.search(links.map { self.row($0) }), | |
| self.fetch(self.first, final: session), | |
| answer, | |
| ], context: context)[answer.id] ?? [] | |
| #expect(context.basePath == mount.encoded) | |
| #expect(result.map(\.url.absoluteString) == [distinct, external, self.second]) | |
| } | |
| func `caps cards in citation order while keeping observed aliases for generic link suppression`() throws { | |
| let links = (1...10).map { "https://example.com/article-\($0)" } | |
| let answer = self.answer(links.map { "[link](\($0))" }.joined(separator: " ")) | |
| var projector = ChatSourcePreviewProjector() | |
| let result = projector.project([ | |
| self.search(links.map { self.row($0) }), | |
| self.fetch(links[0], final: self.second), answer, | |
| ])[answer.id] ?? [] | |
| #expect(result.count == 8) | |
| #expect(result.first?.url.absoluteString == self.second) | |
| #expect(result.first?.represents(URL(string: links[0] + "#section")!) == true) | |
| #expect(try result.first? | |
| .represents(#require(URL(string: "https://github.com/example/project/issues/1"))) == false) | |
| } | |
| (arguments: [ | |
| "https://example.com", | |
| "https://EXAMPLE.com/", | |
| "https://example.com:443", | |
| "https://EXAMPLE.com:443/#section", | |
| "http://EXAMPLE.com:80", | |
| ]) | |
| func `generic preview aliases match the projected source`(citation: String) throws { | |
| let markdown = "[Source](\(citation))" | |
| let answer = self.answer(markdown) | |
| var projector = ChatSourcePreviewProjector() | |
| let sources = projector.project([self.search([self.row(citation)]), answer])[answer.id] ?? [] | |
| let source = try #require(sources.first) | |
| let genericPreview = try #require(chatFirstPreviewURL(in: markdown)) | |
| #expect(source.represents(genericPreview)) | |
| #expect(try !source.represents(#require(URL(string: "https://example.com:8443/")))) | |
| #expect(try !source.represents(#require(URL(string: "https://user:password@example.com/")))) | |
| } | |
| func `refresh invalidates only changed transcript inputs and removes deleted sources`() { | |
| let answer = self.answer("[source](\(self.first))") | |
| let resultID = UUID() | |
| var projector = ChatSourcePreviewProjector() | |
| let original = self.tool( | |
| self.searchPayload([self.row(self.first, title: "Original")]), | |
| name: "web_search", | |
| id: resultID) | |
| #expect(projector.project([original, answer])[answer.id]?.first?.title == "Original") | |
| #expect(projector.project([original, answer])[answer.id]?.first?.title == "Original") | |
| let refreshed = self.tool( | |
| self.searchPayload([self.row(self.first, title: "Refreshed")]), | |
| name: "web_search", | |
| id: resultID) | |
| #expect(projector.project([refreshed, answer])[answer.id]?.first?.title == "Refreshed") | |
| #expect((projector.project([answer])[answer.id] ?? []).isEmpty) | |
| } | |
| func `inline results and JSON result text retain invocation and canonical run ownership`() throws { | |
| let payload = self.searchPayload([self.row(self.first, snippet: "The <think> tag is literal source content.")]) | |
| let answer = self.answer("[source](\(self.first))") | |
| let raw: [String: Any] = [ | |
| "role": "assistant", "runId": "ignored-transport-run", "__openclaw": ["runId": self.runID], | |
| "content": [ | |
| ["type": "toolCall", "id": "call", "name": "web_search", "arguments": [:]], | |
| ["type": "tool_result", "tool_use_id": "call", "details": payload], | |
| ], | |
| ] | |
| let inline = try JSONDecoder().decode( | |
| OpenClawChatMessage.self, from: JSONSerialization.data(withJSONObject: raw)) | |
| let jsonText = try String(decoding: JSONSerialization.data(withJSONObject: payload), as: UTF8.self) | |
| let textResult = OpenClawChatMessage( | |
| role: "toolResult", | |
| content: [.init(type: "text", text: jsonText, mimeType: nil, fileName: nil, content: nil)], | |
| timestamp: 2, transcriptRunID: self.runID, toolName: "web_search") | |
| var projector = ChatSourcePreviewProjector() | |
| #expect(projector.project([inline, answer])[answer.id]?.first?.title == "Source title") | |
| #expect(projector.project([textResult, answer])[answer.id]?.first?.title == "Source title") | |
| #expect((projector.project([answer, inline])[answer.id] ?? []).isEmpty) | |
| } | |
| func `unfinished replies and unwrapped source prose never become completed previews`() { | |
| let commentary = OpenClawChatMessage( | |
| role: "assistant", | |
| content: [.init(type: "text", text: "[source](\(self.first))", mimeType: nil, fileName: nil, content: nil)], | |
| timestamp: 3, transcriptRunID: self.runID, phase: "commentary") | |
| let answer = self.answer("[source](\(self.first))") | |
| let result = self.search([["url": self.first, "title": "Unwrapped title", "snippet": "Unwrapped snippet"]]) | |
| var projector = ChatSourcePreviewProjector() | |
| let previews = projector.project([result, commentary, answer]) | |
| #expect(previews[commentary.id] == nil) | |
| #expect(previews[answer.id]?.first?.title == "example.com") | |
| #expect(previews[answer.id]?.first?.excerpt == nil) | |
| } | |
| func `bare cited URLs retain reading order without using URLs inside code`() { | |
| let answer = self.answer(""" | |
| `https://code.example.com/inline` | |
| ```text | |
| https://code.example.com/fenced | |
| ``` | |
| Read \(self.second), followed by \(self.first)#section. | |
| """) | |
| var projector = ChatSourcePreviewProjector() | |
| let result = projector.project([ | |
| self.search([ | |
| self.row("https://code.example.com/inline"), | |
| self.row("https://code.example.com/fenced"), | |
| self.row(self.first), self.row(self.second), | |
| ]), answer, | |
| ])[answer.id] ?? [] | |
| #expect(result.map(\.url.absoluteString) == [self.second, self.first]) | |
| } | |
| private func answer(_ text: String) -> OpenClawChatMessage { | |
| OpenClawChatMessage( | |
| role: "assistant", content: [.init(type: "text", text: text, mimeType: nil, fileName: nil, content: nil)], | |
| timestamp: 3, transcriptRunID: self.runID, stopReason: "stop", phase: "final_answer") | |
| } | |
| private func call(_ name: String) -> OpenClawChatMessage { | |
| OpenClawChatMessage( | |
| role: "assistant", content: [.init( | |
| type: "toolCall", text: nil, mimeType: nil, fileName: nil, content: nil, | |
| id: "call", name: name, arguments: AnyCodable([:]))], | |
| timestamp: 1, transcriptRunID: self.runID) | |
| } | |
| private func tool( | |
| _ payload: [String: Any], name: String, error: Bool = false, | |
| run: String? = nil, id: UUID = UUID()) -> OpenClawChatMessage | |
| { | |
| OpenClawChatMessage( | |
| id: id, role: "toolResult", content: [], timestamp: 2, transcriptRunID: run ?? self.runID, | |
| toolCallId: "call", toolName: name, details: AnyCodable(payload), isError: error) | |
| } | |
| private func search(_ rows: [[String: Any]], run: String? = nil) -> OpenClawChatMessage { | |
| self.tool(self.searchPayload(rows), name: "web_search", run: run) | |
| } | |
| private func searchPayload(_ rows: [[String: Any]]) -> [String: Any] { | |
| ["kind": "results", "results": rows, "externalContent": self.external("web_search")] | |
| } | |
| private func row( | |
| _ url: String, | |
| title: String = "Source title", | |
| snippet: String = "Recorded snippet") -> [String: Any] | |
| { | |
| ["url": url, "title": self.wrap(title, name: "web_search"), "snippet": self.wrap(snippet, name: "web_search")] | |
| } | |
| private func fetch( | |
| _ url: String, final: String, status: Int = 200, title: String = "Page title", | |
| text: String = "") -> OpenClawChatMessage | |
| { | |
| self.tool([ | |
| "url": url, "finalUrl": final, "status": status, "externalContent": self.external("web_fetch"), | |
| "title": self.wrap(title, name: "web_fetch"), "text": self.wrap(text, name: "web_fetch"), | |
| ], name: "web_fetch") | |
| } | |
| private func external(_ name: String) -> [String: Any] { | |
| ["source": name, "untrusted": true, "wrapped": true] | |
| } | |
| private func wrap(_ text: String, name: String) -> String { | |
| """ | |
| <<<EXTERNAL_UNTRUSTED_CONTENT id="0123456789abcdef">>> | |
| Source: \(name == "web_search" ? "Web Search" : "Web Fetch") | |
| --- | |
| \(text) | |
| <<<END_EXTERNAL_UNTRUSTED_CONTENT id="0123456789abcdef">>> | |
| """ | |
| } | |
| } | |