Files
Termind/Frameworks/TermindPresentation/Strings/Notifications.swift
T
Kaede Akino 4d6e4481c0 feat(mcp): add OAuth and 2025-03-26 compatibility
Integrate AgentKit 0.18.1 with native authorization on macOS and iOS, device-local OAuth credentials, V43 configuration persistence, and Assistant authorization prompts.

Add HTTPS callback metadata, keep native callbacks safe across actor boundaries, and distinguish authorization setup failures from cancellation. Extend the external MCP server to negotiate 2025-03-26.
2026-09-28 12:36:32 +08:00

69 lines
3.5 KiB
Swift

import AgentKit
import Foundation
import TermindApplication
extension AppStrings {
public nonisolated enum Notifications {
public static var title: LocalizedStringResource { "Notifications" }
public static var enabled: LocalizedStringResource { "Enabled" }
public static var allow: LocalizedStringResource { "Allow Notifications" }
public static var delivery: LocalizedStringResource { "Notification Type" }
public static var system: LocalizedStringResource { "System Notifications" }
public static var bell: LocalizedStringResource { "Bell" }
public static var unfocused: LocalizedStringResource { "Unfocused" }
public static var markRead: LocalizedStringResource { "Mark as Read" }
public static var markUnread: LocalizedStringResource { "Mark as Unread" }
public static func transfersCompleted(succeeded: Int, failed: Int) -> LocalizedStringResource {
if failed == 0 {
return succeeded == 1 ? "The transfer is complete." : "All \(succeeded) transfers are complete."
}
if succeeded == 0 {
return failed == 1 ? "The transfer failed." : "All \(failed) transfers failed."
}
return "Transfers finished: \(succeeded) completed, \(failed) failed."
}
public static func unread(_ count: Int) -> LocalizedStringResource { "Unread notifications: \(count)" }
public static func body(_ kind: AssistantNotificationKind) -> LocalizedStringResource {
switch kind {
case .mcpAuthorization: "Please authorize the MCP connection to continue."
case .completed: "The task is complete."
case .failed: "The task failed. Open the conversation for details."
case .questions: "Please provide some information to continue."
case .secret: "Please enter your credentials to continue."
case .approval: "An action needs your approval."
case .authentication: "Please complete SSH authentication to continue."
case .passphrase: "Please enter your SSH key passphrase."
case .hostKey: "Please confirm this host's key to continue."
}
}
}
}
public enum AssistantNotificationContent {
public static func make(
_ conversation: ConversationModel, kind: AssistantNotificationKind, runID: UUID? = nil
) -> (title: String, body: String) {
let title = conversation.derivedTitle
let sanitized = title.unicodeScalars.map {
CharacterSet.controlCharacters.contains($0) ? " " : String($0)
}.joined()
var body = String(localized: AppStrings.Notifications.body(kind))
if kind == .completed, let runID,
let reply = conversation.transcript.last(where: {
$0.role == .assistant && $0.toolCalls.isEmpty && conversation.messageRunIDs[$0.id] == runID
&& !$0.text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
})
{
body = AgentSensitiveDataRedactor.visibleText(
reply.text.trimmingCharacters(in: .whitespacesAndNewlines), maximumCharacters: 2_000)
} else if kind == .failed, let runID,
let reason = conversation.runSummaries[runID]?.failure?.trimmingCharacters(in: .whitespacesAndNewlines),
!reason.isEmpty
{
body = AgentSensitiveDataRedactor.visibleText(reason, maximumCharacters: 500)
}
return (String(sanitized.prefix(160)), body)
}
}