feat(ai): unify reply center and refresh keyboard AI features

- Merge invitation, task, blessing, clarification, and empathy actions
  into a single Reply flow, with three fixed, clearly labeled stance
  choices whenever user intent must not be guessed.
- Refine clipboard semantic routing with bilingual schedule,
  confirmation, and follow-up models, conservative language thresholds,
  and explicit-assignment guard for complaint-only text.
- Persist Apple account refresh state, harden session recovery, and
  surface durable account diagnostics across keyboard and app.
- Derive personal-style prompts through two-stage corpus evidence and
  apply real low-confidence ASR tendencies instead of neutral templates.
- Localize the new reply center, clipboard semantics, and personal-style
  surfaces in both English and Simplified Chinese.
This commit is contained in:
Rocky
2026-08-29 11:51:21 +08:00
parent f91a8f2456
commit 3c10d73d7f
30 changed files with 2090 additions and 447 deletions
@@ -122,7 +122,7 @@ public struct AISessionState: Equatable, Sendable {
phase == .ready
&& answer == nil
&& selectedReplyVariant == nil
&& replyVariants.count == AIReplyVariant.Kind.allCases.count
&& AIReplyVariantSet.resolve(kinds: Set(replyVariants.map(\.kind))) != nil
}
public var canSend: Bool {
@@ -201,12 +201,12 @@ public struct AISessionState: Equatable, Sendable {
) {
guard isActive, activeUtteranceID == utteranceID else { return }
let kinds = Set(variants.map(\.kind))
guard variants.count == AIReplyVariant.Kind.allCases.count,
kinds == Set(AIReplyVariant.Kind.allCases) else {
guard let variantSet = AIReplyVariantSet.resolve(kinds: kinds),
variants.count == variantSet.kinds.count else {
return
}
answer = nil
replyVariants = AIReplyVariant.Kind.allCases.compactMap { kind in
replyVariants = variantSet.kinds.compactMap { kind in
variants.first { $0.kind == kind }
}
selectedReplyVariant = nil