mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-02 08:44:53 +00:00
Summary: - Replace the legacy iOS shell with Pro Command, Chat, Agents, and Settings tabs. - Wire iOS chat/session/settings/diagnostics and realtime Talk flows through gateway-backed APIs. - Add gateway/session and shared chat coverage for the new iOS flow. Verification: - git diff --check - node scripts/run-vitest.mjs src/gateway/server.sessions.create.test.ts src/gateway/talk-realtime-relay.test.ts - swift test --filter ChatViewModelTests (apps/shared/OpenClawKit) - xcodebuild build for Nimrod's iPhone succeeded; install succeeded; launch was blocked because the phone was locked Known follow-up: - Preserve traceLevel in sessions.create parent runtime inheritance and keep the changelog credit in the follow-up patch.
71 lines
2.5 KiB
Swift
71 lines
2.5 KiB
Swift
import Foundation
|
|
|
|
public struct SharedContentPayload: Sendable, Equatable {
|
|
public let title: String?
|
|
public let url: URL?
|
|
public let text: String?
|
|
|
|
public init(title: String?, url: URL?, text: String?) {
|
|
self.title = title
|
|
self.url = url
|
|
self.text = text
|
|
}
|
|
}
|
|
|
|
public enum ShareToAgentDeepLink {
|
|
public static func buildURL(from payload: SharedContentPayload, instruction: String? = nil) -> URL? {
|
|
let message = self.buildMessage(from: payload, instruction: instruction)
|
|
guard !message.isEmpty else { return nil }
|
|
|
|
var components = URLComponents()
|
|
components.scheme = "openclaw"
|
|
components.host = "agent"
|
|
components.queryItems = [
|
|
URLQueryItem(name: "message", value: message),
|
|
URLQueryItem(name: "thinking", value: "low"),
|
|
]
|
|
return components.url
|
|
}
|
|
|
|
public static func buildMessage(from payload: SharedContentPayload, instruction: String? = nil) -> String {
|
|
let title = self.clean(payload.title)
|
|
let text = self.clean(payload.text)
|
|
let urlText = payload.url?.absoluteString.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
let resolvedInstruction = self.clean(instruction) ?? self.clean(ShareToAgentSettings.loadDefaultInstruction())
|
|
let hasSharedContent = title != nil || text != nil || self.clean(urlText) != nil
|
|
|
|
guard hasSharedContent || resolvedInstruction != nil else { return "" }
|
|
|
|
var lines: [String] = []
|
|
if hasSharedContent {
|
|
lines.append("Shared from iOS.")
|
|
}
|
|
if let title, !title.isEmpty {
|
|
lines.append("Title: \(title)")
|
|
}
|
|
if let urlText, !urlText.isEmpty {
|
|
lines.append("URL: \(urlText)")
|
|
}
|
|
if let text, !text.isEmpty {
|
|
lines.append("Text:\n\(text)")
|
|
}
|
|
if let resolvedInstruction {
|
|
lines.append(resolvedInstruction)
|
|
}
|
|
|
|
let message = lines.joined(separator: "\n\n")
|
|
return self.limit(message, maxCharacters: 2400)
|
|
}
|
|
|
|
private static func clean(_ value: String?) -> String? {
|
|
guard let value else { return nil }
|
|
let trimmed = value.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
return trimmed.isEmpty ? nil : trimmed
|
|
}
|
|
|
|
private static func limit(_ value: String, maxCharacters: Int) -> String {
|
|
guard value.count > maxCharacters else { return value }
|
|
return String(value.prefix(maxCharacters))
|
|
}
|
|
}
|