feat(account): add managed credits and cloud gateway
Introduce optional Apple account-backed credits with scoped gateway access while preserving local and BYOK paths. Refresh assistant behavior, tests, privacy disclosures, docs, and the website for the 2.0 experience.
This commit is contained in:
@@ -110,7 +110,11 @@ final class AIKeyboardCoordinator {
|
||||
if case .materialUnavailable = resolution {
|
||||
AIAgentShortcutRun.trace("keyboard.submit rejected clipboardUnavailable skill=\(skill.id)")
|
||||
}
|
||||
submitResolvedPrompt(resolution, thinkingEnabled: skill.thinkingEnabled)
|
||||
submitResolvedPrompt(
|
||||
resolution,
|
||||
taskKind: skill.managedGatewayTaskKind,
|
||||
thinkingEnabled: skill.thinkingEnabled
|
||||
)
|
||||
}
|
||||
|
||||
/// Tap an idle hint card: resolve its material, skip the mic, ask the host.
|
||||
@@ -121,7 +125,7 @@ final class AIKeyboardCoordinator {
|
||||
for: card,
|
||||
clipboardText: ClipboardHistoryStore.shared.newestAIHintEligibleEntry()?.text
|
||||
)
|
||||
submitResolvedPrompt(resolution)
|
||||
submitResolvedPrompt(resolution, taskKind: .aiQuestion)
|
||||
}
|
||||
|
||||
private var canAcceptIdleSubmit: Bool {
|
||||
@@ -136,6 +140,7 @@ final class AIKeyboardCoordinator {
|
||||
|
||||
private func submitResolvedPrompt(
|
||||
_ resolution: AIClipboardPrompt.Resolution,
|
||||
taskKind: ManagedGatewayTaskKind,
|
||||
thinkingEnabled: Bool? = nil
|
||||
) {
|
||||
guard case .ready(let prompt) = resolution else {
|
||||
@@ -154,6 +159,7 @@ final class AIKeyboardCoordinator {
|
||||
let disposition = flow.submitAIQuestion(
|
||||
text: prompt,
|
||||
conversationID: conversationID,
|
||||
taskKind: taskKind,
|
||||
thinkingEnabled: thinkingEnabled
|
||||
)
|
||||
if case .rejected(let rejection) = disposition {
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
// (changeCount-driven). Writes accepted text into ClipboardHistoryStore.
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
import OSGKeyboardShared
|
||||
import UIKit
|
||||
|
||||
@MainActor
|
||||
protocol ClipboardPasteboardProviding: AnyObject {
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
//
|
||||
// Flow session start, recording, watchdogs, and result delivery handling.
|
||||
|
||||
import UIKit
|
||||
import OSGKeyboardShared
|
||||
import UIKit
|
||||
|
||||
@MainActor
|
||||
final class KeyboardFlowCoordinator {
|
||||
@@ -681,6 +681,7 @@ final class KeyboardFlowCoordinator {
|
||||
func submitAIQuestion(
|
||||
text: String,
|
||||
conversationID: UUID,
|
||||
taskKind: ManagedGatewayTaskKind = .aiQuestion,
|
||||
thinkingEnabled: Bool? = nil
|
||||
) -> FlowUtteranceStartDisposition {
|
||||
let trimmed = text.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
@@ -689,6 +690,7 @@ final class KeyboardFlowCoordinator {
|
||||
.aiQuestion(
|
||||
conversationID: conversationID,
|
||||
prefilledQuestion: trimmed,
|
||||
taskKind: taskKind,
|
||||
thinkingEnabled: thinkingEnabled
|
||||
)
|
||||
)
|
||||
@@ -1191,6 +1193,7 @@ final class KeyboardFlowCoordinator {
|
||||
sourceHistoryEntryID: request.sourceHistoryEntryID,
|
||||
sourceHistoryEntryRevision: request.sourceHistoryEntryRevision,
|
||||
aiConversationID: request.aiConversationID,
|
||||
aiTaskKind: request.aiTaskKind,
|
||||
startDeadlineAt: action == .startRecording ? currentStartDeadlineAt : nil,
|
||||
processingDeadlineAt: action == .stopRecording && request.isEdit
|
||||
? Date().timeIntervalSince1970
|
||||
@@ -1898,6 +1901,7 @@ final class KeyboardFlowCoordinator {
|
||||
utteranceMode: .aiQuestion,
|
||||
aiConversationID: currentUtteranceRequest?.aiConversationID,
|
||||
aiQuestionText: text,
|
||||
aiTaskKind: currentUtteranceRequest?.aiTaskKind,
|
||||
aiThinkingEnabled: currentUtteranceRequest?.aiThinkingEnabled,
|
||||
startDeadlineAt: currentStartDeadlineAt
|
||||
)
|
||||
@@ -2034,7 +2038,7 @@ final class KeyboardFlowCoordinator {
|
||||
onAIStreamingAnswer(result.text ?? "", result.utteranceId)
|
||||
return
|
||||
}
|
||||
if (result.status == .partial || result.status == .rawReady),
|
||||
if result.status == .partial || result.status == .rawReady,
|
||||
let partial = result.text,
|
||||
!partial.isEmpty {
|
||||
if result.resolvedUtteranceMode == .aiQuestion,
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
// without re-running LLM polish in the extension. Also tracks the last
|
||||
// voice insertion so the undo button can roll it back safely.
|
||||
|
||||
import UIKit
|
||||
import OSGKeyboardShared
|
||||
import UIKit
|
||||
|
||||
@MainActor
|
||||
final class KeyboardTextInserter {
|
||||
|
||||
Reference in New Issue
Block a user