@swiftbrowser/swift 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Package.swift +200 -9
- package/README.md +7 -9
- package/Sources/AVFoundation/AVFoundation.swift +131 -0
- package/Sources/AVFoundation/Asset.swift +487 -0
- package/Sources/AVFoundation/AudioSession.swift +144 -0
- package/Sources/AVFoundation/CMTime.swift +303 -0
- package/Sources/AVFoundation/Capture.swift +688 -0
- package/Sources/AVFoundation/Player.swift +749 -0
- package/Sources/AVFoundation/PlayerView.swift +117 -0
- package/Sources/AVKit/AVKit.swift +132 -0
- package/Sources/Accelerate/Accelerate.swift +122 -0
- package/Sources/AppIntents/AppIntents.swift +144 -0
- package/Sources/AppIntents/Parameters.swift +220 -0
- package/Sources/AppIntents/Shortcuts.swift +159 -0
- package/Sources/AudioToolbox/AudioToolbox.swift +55 -0
- package/Sources/AuthenticationServices/AuthenticationServices.swift +257 -0
- package/Sources/AuthenticationServices/Authorization.swift +251 -0
- package/Sources/Charts/Charts.swift +0 -4
- package/Sources/Combine/AnyCancellable.swift +65 -0
- package/Sources/Combine/AnyPublisher.swift +148 -0
- package/Sources/Combine/AnySubscriber.swift +230 -0
- package/Sources/Combine/Cancellable.swift +35 -0
- package/Sources/Combine/Codable.swift +29 -0
- package/Sources/Combine/CombineIdentifier.swift +45 -0
- package/Sources/Combine/Concurrency/ConcurrencyHelpers.swift +24 -0
- package/Sources/Combine/Concurrency/Future+Concurrency.swift +136 -0
- package/Sources/Combine/Concurrency/GENERATED-Publisher+Concurrency.swift +397 -0
- package/Sources/Combine/CurrentValueSubject.swift +252 -0
- package/Sources/Combine/CustomCombineIdentifierConvertible.swift +28 -0
- package/Sources/Combine/Future.swift +228 -0
- package/Sources/Combine/GENERATED-RootProtocols.swift +426 -0
- package/Sources/Combine/Helpers/ConduitBase.swift +40 -0
- package/Sources/Combine/Helpers/ConduitList.swift +59 -0
- package/Sources/Combine/Helpers/DebugHook.swift +177 -0
- package/Sources/Combine/Helpers/FilterProducer.swift +174 -0
- package/Sources/Combine/Helpers/Locking.swift +30 -0
- package/Sources/Combine/Helpers/PartialCompletion.swift +26 -0
- package/Sources/Combine/Helpers/ReduceProducer.swift +249 -0
- package/Sources/Combine/Helpers/SubjectSubscriber.swift +96 -0
- package/Sources/Combine/Helpers/SubscriberTap.swift +69 -0
- package/Sources/Combine/Helpers/SubscriptionStatus.swift +33 -0
- package/Sources/Combine/Helpers/SubscriptionTap.swift +33 -0
- package/Sources/Combine/Helpers/Utils.swift +30 -0
- package/Sources/Combine/Helpers/Violations.swift +33 -0
- package/Sources/Combine/ImmediateScheduler.swift +178 -0
- package/Sources/Combine/LICENSE +21 -0
- package/Sources/Combine/NotificationPublisher.swift +48 -0
- package/Sources/Combine/ObjectWillChange.swift +46 -0
- package/Sources/Combine/PassthroughSubject.swift +222 -0
- package/Sources/Combine/Publisher+Subscribe.swift +53 -0
- package/Sources/Combine/Publishers/Deferred.swift +48 -0
- package/Sources/Combine/Publishers/Empty.swift +54 -0
- package/Sources/Combine/Publishers/Fail.swift +42 -0
- package/Sources/Combine/Publishers/GENERATED-Publishers.Catch.swift +673 -0
- package/Sources/Combine/Publishers/GENERATED-Publishers.Encode.swift +388 -0
- package/Sources/Combine/Publishers/GENERATED-Publishers.MapKeyPath.swift +384 -0
- package/Sources/Combine/Publishers/Just.swift +313 -0
- package/Sources/Combine/Publishers/Optional.Publisher.swift +315 -0
- package/Sources/Combine/Publishers/Publishers.AllSatisfy.swift +217 -0
- package/Sources/Combine/Publishers/Publishers.AssertNoFailure.swift +158 -0
- package/Sources/Combine/Publishers/Publishers.Autoconnect.swift +193 -0
- package/Sources/Combine/Publishers/Publishers.Breakpoint.swift +231 -0
- package/Sources/Combine/Publishers/Publishers.Buffer.swift +356 -0
- package/Sources/Combine/Publishers/Publishers.Collect.swift +102 -0
- package/Sources/Combine/Publishers/Publishers.CollectByCount.swift +195 -0
- package/Sources/Combine/Publishers/Publishers.CompactMap.swift +241 -0
- package/Sources/Combine/Publishers/Publishers.Comparison.swift +371 -0
- package/Sources/Combine/Publishers/Publishers.Concatenate.swift +474 -0
- package/Sources/Combine/Publishers/Publishers.Contains.swift +293 -0
- package/Sources/Combine/Publishers/Publishers.Count.swift +87 -0
- package/Sources/Combine/Publishers/Publishers.Debounce.swift +332 -0
- package/Sources/Combine/Publishers/Publishers.Delay.swift +269 -0
- package/Sources/Combine/Publishers/Publishers.Drop.swift +155 -0
- package/Sources/Combine/Publishers/Publishers.DropUntilOutput.swift +283 -0
- package/Sources/Combine/Publishers/Publishers.DropWhile.swift +378 -0
- package/Sources/Combine/Publishers/Publishers.Filter.swift +248 -0
- package/Sources/Combine/Publishers/Publishers.First.swift +261 -0
- package/Sources/Combine/Publishers/Publishers.FlatMap.swift +533 -0
- package/Sources/Combine/Publishers/Publishers.HandleEvents.swift +260 -0
- package/Sources/Combine/Publishers/Publishers.IgnoreOutput.swift +109 -0
- package/Sources/Combine/Publishers/Publishers.Last.swift +252 -0
- package/Sources/Combine/Publishers/Publishers.MakeConnectable.swift +82 -0
- package/Sources/Combine/Publishers/Publishers.Map.swift +351 -0
- package/Sources/Combine/Publishers/Publishers.MapError.swift +140 -0
- package/Sources/Combine/Publishers/Publishers.MeasureInterval.swift +187 -0
- package/Sources/Combine/Publishers/Publishers.Multicast.swift +284 -0
- package/Sources/Combine/Publishers/Publishers.Output.swift +241 -0
- package/Sources/Combine/Publishers/Publishers.PrefixUntilOutput.swift +197 -0
- package/Sources/Combine/Publishers/Publishers.PrefixWhile.swift +176 -0
- package/Sources/Combine/Publishers/Publishers.Print.swift +206 -0
- package/Sources/Combine/Publishers/Publishers.ReceiveOn.swift +227 -0
- package/Sources/Combine/Publishers/Publishers.Reduce.swift +204 -0
- package/Sources/Combine/Publishers/Publishers.RemoveDuplicates.swift +264 -0
- package/Sources/Combine/Publishers/Publishers.ReplaceEmpty.swift +201 -0
- package/Sources/Combine/Publishers/Publishers.ReplaceError.swift +211 -0
- package/Sources/Combine/Publishers/Publishers.Retry.swift +274 -0
- package/Sources/Combine/Publishers/Publishers.Scan.swift +331 -0
- package/Sources/Combine/Publishers/Publishers.Sequence.swift +437 -0
- package/Sources/Combine/Publishers/Publishers.SetFailureType.swift +120 -0
- package/Sources/Combine/Publishers/Publishers.Share.swift +104 -0
- package/Sources/Combine/Publishers/Publishers.SubscribeOn.swift +197 -0
- package/Sources/Combine/Publishers/Publishers.SwitchToLatest.swift +444 -0
- package/Sources/Combine/Publishers/Publishers.Throttle.swift +359 -0
- package/Sources/Combine/Publishers/Publishers.Timeout.swift +301 -0
- package/Sources/Combine/Publishers/Publishers.Zip.swift +720 -0
- package/Sources/Combine/Publishers/Publishers.swift +13 -0
- package/Sources/Combine/Publishers/Record.swift +237 -0
- package/Sources/Combine/Publishers/Result.Publisher.swift +337 -0
- package/Sources/Combine/Result.swift +46 -0
- package/Sources/Combine/Scheduler.swift +89 -0
- package/Sources/Combine/Schedulers.swift +211 -0
- package/Sources/Combine/Subject+Void.swift +17 -0
- package/Sources/Combine/Subscriber+Void.swift +20 -0
- package/Sources/Combine/Subscribers/Subscribers.Assign.swift +175 -0
- package/Sources/Combine/Subscribers/Subscribers.Completion.swift +90 -0
- package/Sources/Combine/Subscribers/Subscribers.Demand.swift +476 -0
- package/Sources/Combine/Subscribers/Subscribers.Sink.swift +206 -0
- package/Sources/Combine/Subscribers/Subscribers.swift +9 -0
- package/Sources/Combine/Subscription.swift +22 -0
- package/Sources/Combine/Subscriptions.swift +42 -0
- package/Sources/Combine/SwiftUIObservation.swift +10 -0
- package/Sources/Combine/_Introspection.swift +107 -0
- package/Sources/CommonCrypto/CommonCrypto.swift +80 -0
- package/Sources/Compression/Compression.swift +365 -0
- package/Sources/Compression/Deflate.swift +407 -0
- package/Sources/Compression/Zlib.swift +179 -0
- package/Sources/CoreFoundationTypes/CoreFoundationTypes.swift +101 -0
- package/Sources/CoreGraphics/CoreGraphics.swift +411 -0
- package/Sources/CoreGraphics/ProjectionTransforms.swift +28 -0
- package/Sources/CoreHaptics/CoreHaptics.swift +399 -0
- package/Sources/CoreImage/CIColor.swift +41 -0
- package/Sources/CoreImage/CIContext.swift +31 -0
- package/Sources/CoreImage/CIDetector.swift +57 -0
- package/Sources/CoreImage/CIFilter.swift +243 -0
- package/Sources/CoreImage/CIFilterBuiltins.swift +136 -0
- package/Sources/CoreImage/CIImage.swift +162 -0
- package/Sources/CoreImage/QRCode.swift +393 -0
- package/Sources/CoreLocation/Coordinate.swift +30 -0
- package/Sources/CoreLocation/Location.swift +65 -0
- package/Sources/CoreML/Evaluation.swift +414 -0
- package/Sources/CoreML/FeatureValue.swift +266 -0
- package/Sources/CoreML/Model.swift +269 -0
- package/Sources/CoreML/MultiArray.swift +92 -0
- package/Sources/CoreML/Specification.swift +233 -0
- package/Sources/CoreText/CoreText.swift +64 -0
- package/Sources/CoreTransferable/CoreTransferable.swift +606 -0
- package/Sources/CryptoKit/ChaChaPoly.swift +258 -0
- package/Sources/CryptoKit/CryptoKit.swift +375 -0
- package/Sources/CryptoKit/Curve25519.swift +317 -0
- package/Sources/CryptoKit/P256.swift +321 -0
- package/Sources/FoundationBridge/AppStorage.swift +165 -0
- package/Sources/FoundationBridge/AssetResources.swift +90 -0
- package/Sources/FoundationBridge/AsyncBytes.swift +128 -0
- package/Sources/FoundationBridge/AsyncImage.swift +116 -0
- package/Sources/FoundationBridge/AttributedStrings.swift +16 -0
- package/Sources/{_FoundationCommon → FoundationBridge}/Bundle.swift +41 -4
- package/Sources/FoundationBridge/CombineExports.swift +8 -0
- package/Sources/FoundationBridge/CoreFoundation.swift +77 -0
- package/Sources/FoundationBridge/Dispatch.swift +458 -0
- package/Sources/FoundationBridge/EnvironmentFoundation.swift +41 -0
- package/Sources/FoundationBridge/FileImporter.swift +128 -0
- package/Sources/FoundationBridge/FileSystem.swift +68 -0
- package/Sources/FoundationBridge/FoundationBridge.swift +24 -72
- package/Sources/FoundationBridge/HostResolution.swift +31 -0
- package/Sources/FoundationBridge/ItemProvider.swift +655 -0
- package/Sources/FoundationBridge/KeyValueObserving.swift +138 -0
- package/Sources/FoundationBridge/Links.swift +127 -0
- package/Sources/FoundationBridge/ListFormatter.swift +32 -0
- package/Sources/FoundationBridge/Localization.swift +149 -0
- package/Sources/FoundationBridge/Locks.swift +50 -0
- package/Sources/FoundationBridge/Markdown.swift +527 -0
- package/Sources/FoundationBridge/MeasurementFormat.swift +95 -0
- package/Sources/FoundationBridge/NotificationCenter.swift +154 -0
- package/Sources/FoundationBridge/OpenURLHandlers.swift +60 -0
- package/Sources/FoundationBridge/Operation.swift +195 -0
- package/Sources/FoundationBridge/ProcessInfo.swift +32 -0
- package/Sources/FoundationBridge/RelativeDateTimeFormatter.swift +136 -0
- package/Sources/FoundationBridge/SceneStorage.swift +78 -0
- package/Sources/FoundationBridge/SecurityExports.swift +8 -0
- package/Sources/FoundationBridge/Selector.swift +226 -0
- package/Sources/FoundationBridge/StringComparators.swift +17 -0
- package/Sources/FoundationBridge/Table.swift +211 -0
- package/Sources/FoundationBridge/TextAttributes.swift +42 -0
- package/Sources/FoundationBridge/Timer.swift +6 -1
- package/Sources/FoundationBridge/URLSession.swift +718 -0
- package/Sources/{_FoundationCommon → FoundationBridge}/UserDefaults.swift +17 -4
- package/Sources/FoundationBridge/WebAuthRedirects.swift +227 -0
- package/Sources/FoundationBridge/WebSocket.swift +187 -0
- package/Sources/FoundationModels/FoundationModels.swift +1098 -0
- package/Sources/ImageIO/GIF.swift +72 -0
- package/Sources/ImageIO/ImageIO.swift +248 -0
- package/Sources/ImageIO/ImageTypes.swift +28 -0
- package/Sources/LinkPresentation/LinkPresentation.swift +249 -0
- package/Sources/LocalAuthentication/LAContext.swift +86 -0
- package/Sources/MapKit/Geometry.swift +223 -0
- package/Sources/MapKit/Map.swift +638 -0
- package/Sources/MapKit/MapView.swift +229 -0
- package/Sources/MobileCoreServices/MobileCoreServices.swift +28 -0
- package/Sources/NaturalLanguage/LanguageIdentifier.swift +317 -0
- package/Sources/NaturalLanguage/NaturalLanguage.swift +135 -0
- package/Sources/OSLog/OSLog.swift +6 -0
- package/Sources/Photos/Photos.swift +572 -0
- package/Sources/PhotosUI/PhotosPicker.swift +248 -0
- package/Sources/PhotosUI/PhotosPickerItem.swift +261 -0
- package/Sources/QuickLook/QuickLook.swift +168 -0
- package/Sources/SafariServices/SafariServices.swift +106 -0
- package/Sources/Security/Security.swift +332 -0
- package/Sources/StoreKit/AppStore.swift +207 -0
- package/Sources/StoreKit/Products.swift +280 -0
- package/Sources/StoreKit/RequestReview.swift +28 -0
- package/Sources/StoreKit/StoreKit1.swift +486 -0
- package/Sources/StoreKit/StoreViews.swift +428 -0
- package/Sources/StoreKit/Transactions.swift +197 -0
- package/Sources/SwiftData/Macros.swift +58 -0
- package/Sources/SwiftData/ModelActor.swift +38 -0
- package/Sources/SwiftData/ModelContainer.swift +129 -0
- package/Sources/SwiftData/ModelContext.swift +451 -0
- package/Sources/SwiftData/PersistentModel.swift +238 -0
- package/Sources/SwiftData/Properties.swift +261 -0
- package/Sources/SwiftData/Query.swift +256 -0
- package/Sources/SwiftData/Schema.swift +192 -0
- package/Sources/SwiftData/Store.swift +146 -0
- package/Sources/SwiftData/StringPredicates.swift +125 -0
- package/Sources/SwiftDataMacros/EntryMacro.swift +82 -0
- package/Sources/SwiftDataMacros/GenerableMacro.swift +183 -0
- package/Sources/SwiftDataMacros/ModelActorMacro.swift +46 -0
- package/Sources/SwiftDataMacros/ModelMacro.swift +260 -0
- package/Sources/SwiftDataMacros/Plugin.swift +18 -0
- package/Sources/SwiftDataMacros/PredicateMacro.swift +1244 -0
- package/Sources/SwiftUI/API/Accessibility.swift +55 -6
- package/Sources/SwiftUI/API/AccessibilityExtras.swift +33 -0
- package/Sources/SwiftUI/API/AccessibilityFocus.swift +63 -0
- package/Sources/SwiftUI/API/Alert.swift +1 -1
- package/Sources/SwiftUI/API/AlignmentGuides.swift +68 -0
- package/Sources/SwiftUI/API/Animation.swift +37 -5
- package/Sources/SwiftUI/API/App.swift +31 -1
- package/Sources/SwiftUI/API/BindingCollections.swift +35 -0
- package/Sources/SwiftUI/API/BindingForEach.swift +27 -0
- package/Sources/SwiftUI/API/Bitmaps.swift +254 -0
- package/Sources/SwiftUI/API/ButtonStyles.swift +96 -0
- package/Sources/SwiftUI/API/Canvas.swift +337 -0
- package/Sources/SwiftUI/API/Color.swift +104 -28
- package/Sources/SwiftUI/API/ColorEffects.swift +52 -0
- package/Sources/SwiftUI/API/ColorPickerAndLabeledContent.swift +138 -0
- package/Sources/SwiftUI/API/ColorSpaces.swift +161 -0
- package/Sources/SwiftUI/API/Commands.swift +106 -0
- package/Sources/SwiftUI/API/ContainerBackground.swift +28 -0
- package/Sources/SwiftUI/API/ContentShape.swift +33 -0
- package/Sources/SwiftUI/API/ContentSizeCategory.swift +35 -0
- package/Sources/SwiftUI/API/ContentUnavailable.swift +101 -0
- package/Sources/SwiftUI/API/Controls.swift +59 -27
- package/Sources/SwiftUI/API/CustomLayout.swift +49 -10
- package/Sources/SwiftUI/API/CustomToolbarContent.swift +46 -0
- package/Sources/SwiftUI/API/Decorations.swift +1 -1
- package/Sources/SwiftUI/API/EditMode.swift +25 -82
- package/Sources/SwiftUI/API/Effects.swift +125 -10
- package/Sources/SwiftUI/API/Entry.swift +8 -0
- package/Sources/SwiftUI/API/Environment.swift +100 -9
- package/Sources/SwiftUI/API/EnvironmentSendable.swift +6 -0
- package/Sources/SwiftUI/API/Focus.swift +11 -3
- package/Sources/SwiftUI/API/Gauge.swift +26 -10
- package/Sources/SwiftUI/API/GeometryEffects.swift +232 -0
- package/Sources/SwiftUI/API/GeometryReader.swift +13 -2
- package/Sources/SwiftUI/API/GestureState.swift +65 -0
- package/Sources/SwiftUI/API/Gestures.swift +1 -1
- package/Sources/SwiftUI/API/Glass.swift +127 -0
- package/Sources/SwiftUI/API/Grid.swift +1 -1
- package/Sources/SwiftUI/API/GroupBoxAndControlGroup.swift +130 -0
- package/Sources/SwiftUI/API/KeyPress.swift +54 -0
- package/Sources/SwiftUI/API/LabelStyle.swift +13 -6
- package/Sources/SwiftUI/API/Layout.swift +71 -12
- package/Sources/SwiftUI/API/LazyStacks.swift +49 -0
- package/Sources/SwiftUI/API/LegacyAlert.swift +97 -0
- package/Sources/SwiftUI/API/Lists.swift +61 -6
- package/Sources/SwiftUI/API/Menu.swift +8 -1
- package/Sources/SwiftUI/API/Modifiers.swift +88 -12
- package/Sources/SwiftUI/API/MoreModifiers.swift +100 -0
- package/Sources/SwiftUI/API/Namespace.swift +44 -0
- package/Sources/SwiftUI/API/Navigation.swift +24 -9
- package/Sources/SwiftUI/API/NavigationDestinationBindings.swift +55 -0
- package/Sources/SwiftUI/API/ObservableObject.swift +16 -2
- package/Sources/SwiftUI/API/Path.swift +543 -0
- package/Sources/SwiftUI/API/Phase8Controls.swift +48 -31
- package/Sources/SwiftUI/API/PhaseAnimator.swift +130 -0
- package/Sources/SwiftUI/API/Picker.swift +14 -4
- package/Sources/SwiftUI/API/PointerAndKeyboard.swift +77 -0
- package/Sources/SwiftUI/API/Popover.swift +41 -0
- package/Sources/SwiftUI/API/Preferences.swift +262 -0
- package/Sources/SwiftUI/API/Presentation.swift +17 -4
- package/Sources/SwiftUI/API/PresentationExtras.swift +60 -0
- package/Sources/SwiftUI/API/Primitives.swift +168 -39
- package/Sources/SwiftUI/API/Publishers.swift +4 -4
- package/Sources/SwiftUI/API/Redaction.swift +75 -0
- package/Sources/SwiftUI/API/RowActions.swift +3 -2
- package/Sources/SwiftUI/API/Scenes.swift +131 -0
- package/Sources/SwiftUI/API/ScrollModifiers.swift +132 -0
- package/Sources/SwiftUI/API/ScrollTargets.swift +3 -3
- package/Sources/SwiftUI/API/ScrollViewReader.swift +144 -0
- package/Sources/SwiftUI/API/SectionSupplements.swift +86 -0
- package/Sources/SwiftUI/API/Shape.swift +214 -0
- package/Sources/SwiftUI/API/ShapeStyle.swift +187 -8
- package/Sources/SwiftUI/API/ShapeTrim.swift +78 -0
- package/Sources/SwiftUI/API/Sharing.swift +193 -0
- package/Sources/SwiftUI/API/StackLayouts.swift +199 -0
- package/Sources/SwiftUI/API/State.swift +18 -1
- package/Sources/SwiftUI/API/StatusGaps.swift +121 -0
- package/Sources/SwiftUI/API/SymbolEffects.swift +203 -0
- package/Sources/SwiftUI/API/TabContent.swift +841 -0
- package/Sources/SwiftUI/API/Table.swift +382 -0
- package/Sources/SwiftUI/API/Tabs.swift +148 -4
- package/Sources/SwiftUI/API/Tasks.swift +2 -2
- package/Sources/SwiftUI/API/Text.swift +386 -0
- package/Sources/SwiftUI/API/TextDates.swift +61 -0
- package/Sources/SwiftUI/API/TextDecorations.swift +52 -0
- package/Sources/SwiftUI/API/TextFieldAxis.swift +103 -0
- package/Sources/SwiftUI/API/TextFieldCommit.swift +52 -0
- package/Sources/SwiftUI/API/Toolbar.swift +52 -16
- package/Sources/SwiftUI/API/Transfer.swift +145 -0
- package/Sources/SwiftUI/API/UnevenRoundedRectangle.swift +66 -0
- package/Sources/SwiftUI/API/Video.swift +64 -0
- package/Sources/SwiftUI/API/View.swift +46 -2
- package/Sources/SwiftUI/API/ViewModifier.swift +4 -1
- package/Sources/SwiftUI/API/VisualEffect.swift +74 -1
- package/Sources/SwiftUI/API/Windows.swift +25 -0
- package/Sources/SwiftUI/Charts/Axis.swift +7 -1
- package/Sources/SwiftUI/Charts/AxisFormatsAndRanges.swift +68 -0
- package/Sources/SwiftUI/Charts/Chart.swift +17 -3
- package/Sources/SwiftUI/Charts/ChartProxy.swift +57 -0
- package/Sources/SwiftUI/Localization/Localization.swift +524 -0
- package/Sources/SwiftUI/Localization/PluralRules.swift +127 -0
- package/Sources/SwiftUI/Runtime/Executor.swift +2 -0
- package/Sources/SwiftUI/Runtime/Exports.swift +37 -1
- package/Sources/SwiftUI/Runtime/ImageSource.swift +310 -0
- package/Sources/SwiftUI/Runtime/JSON.swift +76 -4
- package/Sources/SwiftUI/Runtime/LazyRows.swift +99 -0
- package/Sources/SwiftUI/Runtime/Measurements.swift +140 -0
- package/Sources/SwiftUI/Runtime/Ops.swift +58 -12
- package/Sources/SwiftUI/Runtime/Reconciler.swift +10 -1
- package/Sources/SwiftUI/Runtime/Replay.swift +382 -0
- package/Sources/SwiftUI/Runtime/Runtime.swift +977 -198
- package/Sources/SwiftUI/Runtime/Sameness.swift +152 -0
- package/Sources/SwiftUI/Runtime/ViewPath.swift +89 -0
- package/Sources/SwiftUI/Runtime/ViewTraits.swift +175 -0
- package/Sources/SwiftUI/Runtime/WebAuthHeadless.swift +49 -0
- package/Sources/Symbols/Symbols.swift +25 -0
- package/Sources/Translation/Translation.swift +423 -0
- package/Sources/UIKit/Activity.swift +213 -0
- package/Sources/UIKit/Alerts.swift +69 -0
- package/Sources/UIKit/AppDelegate.swift +222 -0
- package/Sources/UIKit/Appearance.swift +84 -0
- package/Sources/UIKit/ColorConversions.swift +70 -0
- package/Sources/UIKit/Controls.swift +225 -0
- package/Sources/UIKit/Device.swift +200 -0
- package/Sources/UIKit/Feedback.swift +65 -0
- package/Sources/UIKit/Font.swift +307 -0
- package/Sources/UIKit/Graphics.swift +204 -0
- package/Sources/UIKit/HostingController.swift +185 -0
- package/Sources/UIKit/Identity.swift +24 -0
- package/Sources/UIKit/Introspectable.swift +510 -0
- package/Sources/UIKit/Pasteboard.swift +363 -0
- package/Sources/UIKit/PhotoAlbum.swift +81 -0
- package/Sources/UIKit/RemoteNotifications.swift +15 -0
- package/Sources/UIKit/Representable.swift +288 -0
- package/Sources/UIKit/SafeArea.swift +12 -0
- package/Sources/UIKit/SceneDelegates.swift +132 -0
- package/Sources/UIKit/Scenes.swift +40 -0
- package/Sources/UIKit/ScrollView.swift +157 -0
- package/Sources/UIKit/ShortcutItems.swift +67 -0
- package/Sources/UIKit/SymbolConfiguration.swift +124 -0
- package/Sources/UIKit/TargetAction.swift +123 -0
- package/Sources/UIKit/TextPaste.swift +161 -0
- package/Sources/UIKit/TextView.swift +538 -0
- package/Sources/UIKit/UIKit.swift +292 -0
- package/Sources/UIKit/UIView.swift +855 -0
- package/Sources/UIKit/ViewTranslation.swift +311 -0
- package/Sources/UniformTypeIdentifiers/UTType.swift +196 -0
- package/Sources/UserNotifications/Content.swift +370 -0
- package/Sources/UserNotifications/NotificationCenter.swift +309 -0
- package/Sources/WeatherKit/WeatherKit.swift +228 -0
- package/Sources/WebKit/WebKit.swift +245 -0
- package/Sources/os/os.swift +376 -0
- package/Sources/zlib/zlib.swift +6 -0
- package/index.d.ts +1 -1
- package/index.mjs +2 -2
- package/manifest.d.mts +2 -0
- package/manifest.mjs +41 -0
- package/package.json +5 -3
- package/sync-sources.mjs +21 -7
- package/Sources/FoundationLite/Common.swift +0 -3
- package/Sources/FoundationLite/FoundationLite.swift +0 -171
- package/Sources/FoundationLite/Interaction.swift +0 -146
- package/Sources/FoundationLite/Timer.swift +0 -48
- package/Sources/_FoundationCommon/_FoundationCommon.swift +0 -10
|
@@ -0,0 +1,1098 @@
|
|
|
1
|
+
// Foundation Models (iOS 26): Apple Intelligence's on-device language
|
|
2
|
+
// model. The browser has no such model to run: Chrome's Prompt API
|
|
3
|
+
// (`LanguageModel`) is offered to extensions and origin trials, not to pages
|
|
4
|
+
// in general, and nothing else answers prompts on the device. So the system
|
|
5
|
+
// model reports what an iPhone without Apple Intelligence reports:
|
|
6
|
+
// `availability` is `.unavailable(.deviceNotEligible)`, `isAvailable` is
|
|
7
|
+
// false, and a session's `respond` and `streamResponse` fail with
|
|
8
|
+
// `GenerationError.assetsUnavailable`. Apps check availability before
|
|
9
|
+
// offering their features (Ice Cubes' composer hides its assistant).
|
|
10
|
+
//
|
|
11
|
+
// The API is complete enough for such apps to compile and run unchanged:
|
|
12
|
+
// sessions with instructions (builders included), prompts, generation
|
|
13
|
+
// options, `Generable` with `@Generable` / `@Guide` (macros of the shim's
|
|
14
|
+
// SwiftDataMacros plugin), `GeneratedContent` with its JSON form, generation
|
|
15
|
+
// schemas and guides, tools, transcripts and response streams.
|
|
16
|
+
|
|
17
|
+
import Foundation
|
|
18
|
+
import FoundationBridge
|
|
19
|
+
import SwiftUI
|
|
20
|
+
|
|
21
|
+
// MARK: - The system model
|
|
22
|
+
|
|
23
|
+
/// The on-device model of Apple Intelligence: unavailable in the browser.
|
|
24
|
+
public final class SystemLanguageModel: Sendable {
|
|
25
|
+
/// What the model is tuned for.
|
|
26
|
+
public struct UseCase: Sendable, Hashable {
|
|
27
|
+
let name: String
|
|
28
|
+
/// Writing, summarizing, answering.
|
|
29
|
+
public static let general = UseCase(name: "general")
|
|
30
|
+
/// Tagging and extracting entities.
|
|
31
|
+
public static let contentTagging = UseCase(name: "contentTagging")
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/// The safety filters applied to prompts and responses.
|
|
35
|
+
public struct Guardrails: Sendable, Hashable {
|
|
36
|
+
let name: String
|
|
37
|
+
public static let `default` = Guardrails(name: "default")
|
|
38
|
+
/// Fewer refusals when transforming the user's own text.
|
|
39
|
+
public static let permissiveContentTransformations = Guardrails(name: "permissiveContentTransformations")
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/// Whether the model can be used.
|
|
43
|
+
public enum Availability: Sendable, Equatable {
|
|
44
|
+
public enum UnavailableReason: Sendable, Equatable, Hashable {
|
|
45
|
+
/// The device cannot run Apple Intelligence: the browser's answer.
|
|
46
|
+
case deviceNotEligible
|
|
47
|
+
/// Apple Intelligence is turned off.
|
|
48
|
+
case appleIntelligenceNotEnabled
|
|
49
|
+
/// The model is still downloading.
|
|
50
|
+
case modelNotReady
|
|
51
|
+
}
|
|
52
|
+
case available
|
|
53
|
+
case unavailable(UnavailableReason)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/// The general-purpose model.
|
|
57
|
+
public static let `default` = SystemLanguageModel()
|
|
58
|
+
|
|
59
|
+
public let useCase: UseCase
|
|
60
|
+
public let guardrails: Guardrails
|
|
61
|
+
|
|
62
|
+
public init(useCase: UseCase = .general, guardrails: Guardrails = .default) {
|
|
63
|
+
self.useCase = useCase
|
|
64
|
+
self.guardrails = guardrails
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/// `.unavailable(.deviceNotEligible)`: there is no on-device model in the browser.
|
|
68
|
+
public var availability: Availability { .unavailable(.deviceNotEligible) }
|
|
69
|
+
|
|
70
|
+
/// False (see `availability`).
|
|
71
|
+
public var isAvailable: Bool { availability == .available }
|
|
72
|
+
|
|
73
|
+
/// No languages: there is no model.
|
|
74
|
+
public var supportedLanguages: Set<Locale.Language> { [] }
|
|
75
|
+
|
|
76
|
+
/// False for every locale: there is no model.
|
|
77
|
+
public func supportsLocale(_ locale: Locale = Locale.current) -> Bool { false }
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// MARK: - Instructions and prompts
|
|
81
|
+
|
|
82
|
+
/// A value that can be part of a session's instructions.
|
|
83
|
+
public protocol InstructionsRepresentable {
|
|
84
|
+
var instructionsRepresentation: Instructions { get }
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/// What a session's model is told to do, before any prompt.
|
|
88
|
+
public struct Instructions: Sendable, Hashable, InstructionsRepresentable {
|
|
89
|
+
let text: String
|
|
90
|
+
|
|
91
|
+
public init(@InstructionsBuilder _ content: () throws -> Instructions) rethrows {
|
|
92
|
+
self = try content()
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
public init(_ representable: some InstructionsRepresentable) {
|
|
96
|
+
self = representable.instructionsRepresentation
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
init(text: String) { self.text = text }
|
|
100
|
+
|
|
101
|
+
public var instructionsRepresentation: Instructions { self }
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
extension String: InstructionsRepresentable {
|
|
105
|
+
public var instructionsRepresentation: Instructions { Instructions(text: self) }
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
extension Array: InstructionsRepresentable where Element: InstructionsRepresentable {
|
|
109
|
+
public var instructionsRepresentation: Instructions {
|
|
110
|
+
Instructions(text: map(\.instructionsRepresentation.text).joined(separator: "\n"))
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/// Builds instructions from strings and other instructions, one per line.
|
|
115
|
+
@resultBuilder
|
|
116
|
+
public struct InstructionsBuilder {
|
|
117
|
+
public static func buildExpression(_ expression: some InstructionsRepresentable) -> Instructions {
|
|
118
|
+
expression.instructionsRepresentation
|
|
119
|
+
}
|
|
120
|
+
public static func buildBlock(_ components: Instructions...) -> Instructions {
|
|
121
|
+
Instructions(text: components.map(\.text).filter { !$0.isEmpty }.joined(separator: "\n"))
|
|
122
|
+
}
|
|
123
|
+
public static func buildArray(_ components: [Instructions]) -> Instructions {
|
|
124
|
+
Instructions(text: components.map(\.text).filter { !$0.isEmpty }.joined(separator: "\n"))
|
|
125
|
+
}
|
|
126
|
+
public static func buildEither(first component: Instructions) -> Instructions { component }
|
|
127
|
+
public static func buildEither(second component: Instructions) -> Instructions { component }
|
|
128
|
+
public static func buildOptional(_ component: Instructions?) -> Instructions { component ?? Instructions(text: "") }
|
|
129
|
+
public static func buildLimitedAvailability(_ component: Instructions) -> Instructions { component }
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/// A value that can be part of a prompt.
|
|
133
|
+
public protocol PromptRepresentable {
|
|
134
|
+
var promptRepresentation: Prompt { get }
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/// What a session is asked.
|
|
138
|
+
public struct Prompt: Sendable, Hashable, PromptRepresentable {
|
|
139
|
+
let text: String
|
|
140
|
+
|
|
141
|
+
public init(@PromptBuilder _ content: () throws -> Prompt) rethrows {
|
|
142
|
+
self = try content()
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
public init(_ representable: some PromptRepresentable) {
|
|
146
|
+
self = representable.promptRepresentation
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
init(text: String) { self.text = text }
|
|
150
|
+
|
|
151
|
+
public var promptRepresentation: Prompt { self }
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
extension String: PromptRepresentable {
|
|
155
|
+
public var promptRepresentation: Prompt { Prompt(text: self) }
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
extension Array: PromptRepresentable where Element: PromptRepresentable {
|
|
159
|
+
public var promptRepresentation: Prompt {
|
|
160
|
+
Prompt(text: map(\.promptRepresentation.text).joined(separator: "\n"))
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/// Builds a prompt from strings and other prompts, one per line.
|
|
165
|
+
@resultBuilder
|
|
166
|
+
public struct PromptBuilder {
|
|
167
|
+
public static func buildExpression(_ expression: some PromptRepresentable) -> Prompt {
|
|
168
|
+
expression.promptRepresentation
|
|
169
|
+
}
|
|
170
|
+
public static func buildBlock(_ components: Prompt...) -> Prompt {
|
|
171
|
+
Prompt(text: components.map(\.text).filter { !$0.isEmpty }.joined(separator: "\n"))
|
|
172
|
+
}
|
|
173
|
+
public static func buildArray(_ components: [Prompt]) -> Prompt {
|
|
174
|
+
Prompt(text: components.map(\.text).filter { !$0.isEmpty }.joined(separator: "\n"))
|
|
175
|
+
}
|
|
176
|
+
public static func buildEither(first component: Prompt) -> Prompt { component }
|
|
177
|
+
public static func buildEither(second component: Prompt) -> Prompt { component }
|
|
178
|
+
public static func buildOptional(_ component: Prompt?) -> Prompt { component ?? Prompt(text: "") }
|
|
179
|
+
public static func buildLimitedAvailability(_ component: Prompt) -> Prompt { component }
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// MARK: - Options
|
|
183
|
+
|
|
184
|
+
/// How a response is sampled.
|
|
185
|
+
public struct GenerationOptions: Sendable, Equatable {
|
|
186
|
+
/// Greedy or random sampling.
|
|
187
|
+
public struct SamplingMode: Sendable, Equatable {
|
|
188
|
+
enum Mode: Sendable, Equatable {
|
|
189
|
+
case greedy
|
|
190
|
+
case top(Int, seed: UInt64?)
|
|
191
|
+
case threshold(Double, seed: UInt64?)
|
|
192
|
+
}
|
|
193
|
+
let mode: Mode
|
|
194
|
+
/// Always the most likely token.
|
|
195
|
+
public static let greedy = SamplingMode(mode: .greedy)
|
|
196
|
+
/// Among the `top` most likely tokens.
|
|
197
|
+
public static func random(top k: Int, seed: UInt64? = nil) -> SamplingMode { SamplingMode(mode: .top(k, seed: seed)) }
|
|
198
|
+
/// Among the most likely tokens whose probabilities add up to `probabilityThreshold`.
|
|
199
|
+
public static func random(probabilityThreshold: Double, seed: UInt64? = nil) -> SamplingMode {
|
|
200
|
+
SamplingMode(mode: .threshold(probabilityThreshold, seed: seed))
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
public var sampling: SamplingMode?
|
|
205
|
+
public var temperature: Double?
|
|
206
|
+
public var maximumResponseTokens: Int?
|
|
207
|
+
|
|
208
|
+
public init(sampling: SamplingMode? = nil, temperature: Double? = nil, maximumResponseTokens: Int? = nil) {
|
|
209
|
+
self.sampling = sampling
|
|
210
|
+
self.temperature = temperature
|
|
211
|
+
self.maximumResponseTokens = maximumResponseTokens
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// MARK: - Generated content
|
|
216
|
+
|
|
217
|
+
/// Identifies one generation of a value.
|
|
218
|
+
public struct GenerationID: Sendable, Hashable {
|
|
219
|
+
let uuid = UUID()
|
|
220
|
+
public init() {}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/// Structured output: null, a boolean, a number, a string, an array or a
|
|
224
|
+
/// structure of named properties (in order). It reads and writes JSON.
|
|
225
|
+
public struct GeneratedContent: Sendable, Equatable, CustomDebugStringConvertible {
|
|
226
|
+
public enum Kind: Sendable, Equatable {
|
|
227
|
+
case null
|
|
228
|
+
case bool(Bool)
|
|
229
|
+
case number(Double)
|
|
230
|
+
case string(String)
|
|
231
|
+
case array([GeneratedContent])
|
|
232
|
+
case structure(properties: [String: GeneratedContent], orderedKeys: [String])
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
public var kind: Kind
|
|
236
|
+
public var id: GenerationID?
|
|
237
|
+
|
|
238
|
+
/// Whether the content is complete: always, since nothing is streamed into it here.
|
|
239
|
+
public var isComplete: Bool { true }
|
|
240
|
+
|
|
241
|
+
public init(kind: Kind, id: GenerationID? = nil) {
|
|
242
|
+
self.kind = kind
|
|
243
|
+
self.id = id
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
public init(_ value: some ConvertibleToGeneratedContent) {
|
|
247
|
+
self = value.generatedContent
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
public init(_ value: some ConvertibleToGeneratedContent, id: GenerationID) {
|
|
251
|
+
self = value.generatedContent
|
|
252
|
+
self.id = id
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/// A structure with the properties in their order.
|
|
256
|
+
public init(properties: KeyValuePairs<String, any ConvertibleToGeneratedContent>, id: GenerationID? = nil) {
|
|
257
|
+
var values: [String: GeneratedContent] = [:]
|
|
258
|
+
var keys: [String] = []
|
|
259
|
+
for (key, value) in properties {
|
|
260
|
+
if values[key] == nil { keys.append(key) }
|
|
261
|
+
values[key] = value.generatedContent
|
|
262
|
+
}
|
|
263
|
+
self.init(kind: .structure(properties: values, orderedKeys: keys), id: id)
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/// An array of the elements.
|
|
267
|
+
public init<S: Sequence>(elements: S, id: GenerationID? = nil) where S.Element == any ConvertibleToGeneratedContent {
|
|
268
|
+
self.init(kind: .array(elements.map(\.generatedContent)), id: id)
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/// Parses JSON (object keys keep their order).
|
|
272
|
+
public init(json: String) throws {
|
|
273
|
+
var parser = _JSONParser(text: Array(json.unicodeScalars))
|
|
274
|
+
guard let content = parser.parseDocument() else {
|
|
275
|
+
throw LanguageModelSession.GenerationError.decodingFailure(.init(debugDescription: "The text is not valid JSON."))
|
|
276
|
+
}
|
|
277
|
+
self = content
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/// The content as JSON.
|
|
281
|
+
public var jsonString: String {
|
|
282
|
+
var out = ""
|
|
283
|
+
write(into: &out)
|
|
284
|
+
return out
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
public var debugDescription: String { jsonString }
|
|
288
|
+
|
|
289
|
+
/// The content as `type`.
|
|
290
|
+
public func value<Value: ConvertibleFromGeneratedContent>(_ type: Value.Type = Value.self) throws -> Value {
|
|
291
|
+
try Value(self)
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/// The structure's property `property` as `type`; a missing property fails.
|
|
295
|
+
public func value<Value: ConvertibleFromGeneratedContent>(_ type: Value.Type = Value.self, forProperty property: String) throws -> Value {
|
|
296
|
+
guard case .structure(let properties, _) = kind, let content = properties[property] else {
|
|
297
|
+
throw LanguageModelSession.GenerationError.decodingFailure(.init(debugDescription: "No property '\(property)' in \(jsonString)."))
|
|
298
|
+
}
|
|
299
|
+
return try Value(content)
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/// The structure's property `property` as `type`; nil when missing or null.
|
|
303
|
+
public func value<Value: ConvertibleFromGeneratedContent>(_ type: Value?.Type = Value?.self, forProperty property: String) throws -> Value? {
|
|
304
|
+
guard case .structure(let properties, _) = kind else {
|
|
305
|
+
throw LanguageModelSession.GenerationError.decodingFailure(.init(debugDescription: "\(jsonString) is not a structure."))
|
|
306
|
+
}
|
|
307
|
+
guard let content = properties[property], content.kind != .null else { return nil }
|
|
308
|
+
return try Value(content)
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/// The error for content that is not of the expected kind.
|
|
312
|
+
public static func _mismatch(_ content: GeneratedContent, _ type: Any.Type) -> LanguageModelSession.GenerationError {
|
|
313
|
+
.decodingFailure(.init(debugDescription: "\(content.jsonString) is not a \(type)."))
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
private func write(into out: inout String) {
|
|
317
|
+
switch kind {
|
|
318
|
+
case .null: out += "null"
|
|
319
|
+
case .bool(let value): out += value ? "true" : "false"
|
|
320
|
+
case .number(let value):
|
|
321
|
+
if value.isFinite, value == value.rounded(), abs(value) < 1e15 { out += String(Int64(value)) }
|
|
322
|
+
else if value.isFinite { out += "\(value)" }
|
|
323
|
+
else { out += "null" }
|
|
324
|
+
case .string(let value): Self.writeString(value, into: &out)
|
|
325
|
+
case .array(let items):
|
|
326
|
+
out += "["
|
|
327
|
+
for (index, item) in items.enumerated() {
|
|
328
|
+
if index > 0 { out += ", " }
|
|
329
|
+
item.write(into: &out)
|
|
330
|
+
}
|
|
331
|
+
out += "]"
|
|
332
|
+
case .structure(let properties, let keys):
|
|
333
|
+
out += "{"
|
|
334
|
+
for (index, key) in keys.enumerated() {
|
|
335
|
+
if index > 0 { out += ", " }
|
|
336
|
+
Self.writeString(key, into: &out)
|
|
337
|
+
out += ": "
|
|
338
|
+
(properties[key] ?? GeneratedContent(kind: .null)).write(into: &out)
|
|
339
|
+
}
|
|
340
|
+
out += "}"
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
private static func writeString(_ value: String, into out: inout String) {
|
|
345
|
+
out += "\""
|
|
346
|
+
for scalar in value.unicodeScalars {
|
|
347
|
+
switch scalar {
|
|
348
|
+
case "\"": out += "\\\""
|
|
349
|
+
case "\\": out += "\\\\"
|
|
350
|
+
case "\n": out += "\\n"
|
|
351
|
+
case "\r": out += "\\r"
|
|
352
|
+
case "\t": out += "\\t"
|
|
353
|
+
default:
|
|
354
|
+
if scalar.value < 0x20 {
|
|
355
|
+
let hex = String(scalar.value, radix: 16)
|
|
356
|
+
out += "\\u" + String(repeating: "0", count: 4 - hex.count) + hex
|
|
357
|
+
} else {
|
|
358
|
+
out.unicodeScalars.append(scalar)
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
out += "\""
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/// A small JSON reader that keeps the order of object keys.
|
|
367
|
+
struct _JSONParser {
|
|
368
|
+
let text: [Unicode.Scalar]
|
|
369
|
+
var index = 0
|
|
370
|
+
|
|
371
|
+
mutating func parseDocument() -> GeneratedContent? {
|
|
372
|
+
guard let value = parseValue() else { return nil }
|
|
373
|
+
skipSpace()
|
|
374
|
+
return index == text.count ? value : nil
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
mutating func skipSpace() {
|
|
378
|
+
while index < text.count, [" ", "\n", "\r", "\t"].contains(text[index]) { index += 1 }
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
mutating func parseValue() -> GeneratedContent? {
|
|
382
|
+
skipSpace()
|
|
383
|
+
guard index < text.count else { return nil }
|
|
384
|
+
switch text[index] {
|
|
385
|
+
case "{":
|
|
386
|
+
index += 1
|
|
387
|
+
var properties: [String: GeneratedContent] = [:]
|
|
388
|
+
var keys: [String] = []
|
|
389
|
+
skipSpace()
|
|
390
|
+
if index < text.count, text[index] == "}" { index += 1; return GeneratedContent(kind: .structure(properties: [:], orderedKeys: [])) }
|
|
391
|
+
while true {
|
|
392
|
+
skipSpace()
|
|
393
|
+
guard let key = parseString() else { return nil }
|
|
394
|
+
skipSpace()
|
|
395
|
+
guard index < text.count, text[index] == ":" else { return nil }
|
|
396
|
+
index += 1
|
|
397
|
+
guard let value = parseValue() else { return nil }
|
|
398
|
+
if properties[key] == nil { keys.append(key) }
|
|
399
|
+
properties[key] = value
|
|
400
|
+
skipSpace()
|
|
401
|
+
guard index < text.count else { return nil }
|
|
402
|
+
if text[index] == "," { index += 1; continue }
|
|
403
|
+
if text[index] == "}" { index += 1; break }
|
|
404
|
+
return nil
|
|
405
|
+
}
|
|
406
|
+
return GeneratedContent(kind: .structure(properties: properties, orderedKeys: keys))
|
|
407
|
+
case "[":
|
|
408
|
+
index += 1
|
|
409
|
+
var items: [GeneratedContent] = []
|
|
410
|
+
skipSpace()
|
|
411
|
+
if index < text.count, text[index] == "]" { index += 1; return GeneratedContent(kind: .array([])) }
|
|
412
|
+
while true {
|
|
413
|
+
guard let value = parseValue() else { return nil }
|
|
414
|
+
items.append(value)
|
|
415
|
+
skipSpace()
|
|
416
|
+
guard index < text.count else { return nil }
|
|
417
|
+
if text[index] == "," { index += 1; continue }
|
|
418
|
+
if text[index] == "]" { index += 1; break }
|
|
419
|
+
return nil
|
|
420
|
+
}
|
|
421
|
+
return GeneratedContent(kind: .array(items))
|
|
422
|
+
case "\"":
|
|
423
|
+
return parseString().map { GeneratedContent(kind: .string($0)) }
|
|
424
|
+
case "t": return literal("true", .bool(true))
|
|
425
|
+
case "f": return literal("false", .bool(false))
|
|
426
|
+
case "n": return literal("null", .null)
|
|
427
|
+
default:
|
|
428
|
+
let start = index
|
|
429
|
+
while index < text.count, "+-0123456789.eE".unicodeScalars.contains(text[index]) { index += 1 }
|
|
430
|
+
var number = ""
|
|
431
|
+
number.unicodeScalars.append(contentsOf: text[start..<index])
|
|
432
|
+
return Double(number).map { GeneratedContent(kind: .number($0)) }
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
mutating func literal(_ word: String, _ kind: GeneratedContent.Kind) -> GeneratedContent? {
|
|
437
|
+
let scalars = Array(word.unicodeScalars)
|
|
438
|
+
guard index + scalars.count <= text.count, Array(text[index..<index + scalars.count]) == scalars else { return nil }
|
|
439
|
+
index += scalars.count
|
|
440
|
+
return GeneratedContent(kind: kind)
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
mutating func parseString() -> String? {
|
|
444
|
+
guard index < text.count, text[index] == "\"" else { return nil }
|
|
445
|
+
index += 1
|
|
446
|
+
var out = String.UnicodeScalarView()
|
|
447
|
+
var pendingHigh: UInt32?
|
|
448
|
+
while index < text.count {
|
|
449
|
+
let scalar = text[index]
|
|
450
|
+
index += 1
|
|
451
|
+
if scalar == "\"" { return String(out) }
|
|
452
|
+
guard scalar == "\\" else { out.append(scalar); continue }
|
|
453
|
+
guard index < text.count else { return nil }
|
|
454
|
+
let escape = text[index]
|
|
455
|
+
index += 1
|
|
456
|
+
switch escape {
|
|
457
|
+
case "n": out.append("\n")
|
|
458
|
+
case "r": out.append("\r")
|
|
459
|
+
case "t": out.append("\t")
|
|
460
|
+
case "b": out.append("\u{8}")
|
|
461
|
+
case "f": out.append("\u{c}")
|
|
462
|
+
case "u":
|
|
463
|
+
guard index + 4 <= text.count else { return nil }
|
|
464
|
+
var hex = ""
|
|
465
|
+
hex.unicodeScalars.append(contentsOf: text[index..<index + 4])
|
|
466
|
+
index += 4
|
|
467
|
+
guard let code = UInt32(hex, radix: 16) else { return nil }
|
|
468
|
+
if (0xD800..<0xDC00).contains(code) { pendingHigh = code; continue }
|
|
469
|
+
if (0xDC00..<0xE000).contains(code), let high = pendingHigh {
|
|
470
|
+
pendingHigh = nil
|
|
471
|
+
if let combined = Unicode.Scalar(0x10000 + ((high - 0xD800) << 10) + (code - 0xDC00)) { out.append(combined) }
|
|
472
|
+
continue
|
|
473
|
+
}
|
|
474
|
+
if let decoded = Unicode.Scalar(code) { out.append(decoded) }
|
|
475
|
+
default: out.append(escape)
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
return nil
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// MARK: - Generable
|
|
483
|
+
|
|
484
|
+
/// A type that can be made from generated content.
|
|
485
|
+
public protocol ConvertibleFromGeneratedContent {
|
|
486
|
+
init(_ content: GeneratedContent) throws
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/// A type that can be written as generated content.
|
|
490
|
+
public protocol ConvertibleToGeneratedContent: InstructionsRepresentable, PromptRepresentable {
|
|
491
|
+
var generatedContent: GeneratedContent { get }
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
extension ConvertibleToGeneratedContent {
|
|
495
|
+
public var instructionsRepresentation: Instructions { Instructions(text: generatedContent.jsonString) }
|
|
496
|
+
public var promptRepresentation: Prompt { Prompt(text: generatedContent.jsonString) }
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/// A type a model can generate: it has a schema the output must follow.
|
|
500
|
+
/// `@Generable` makes a struct or an enum one.
|
|
501
|
+
public protocol Generable: ConvertibleFromGeneratedContent, ConvertibleToGeneratedContent {
|
|
502
|
+
/// The type a response stream delivers while the value is incomplete
|
|
503
|
+
/// (the type itself here: nothing is streamed).
|
|
504
|
+
associatedtype PartiallyGenerated: ConvertibleFromGeneratedContent = Self
|
|
505
|
+
static var generationSchema: GenerationSchema { get }
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
extension Generable {
|
|
509
|
+
/// The value as its partially generated type.
|
|
510
|
+
public func asPartiallyGenerated() -> PartiallyGenerated {
|
|
511
|
+
(try? PartiallyGenerated(generatedContent))!
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
/// Makes a struct or an enum `Generable` (see Sources/SwiftDataMacros/GenerableMacro.swift).
|
|
516
|
+
@attached(extension, conformances: Generable, names: named(init(_:)), named(generatedContent), named(generationSchema))
|
|
517
|
+
public macro Generable(description: String? = nil) = #externalMacro(module: "SwiftDataMacros", type: "GenerableMacro")
|
|
518
|
+
|
|
519
|
+
/// Describes and constrains a property of a `@Generable` type.
|
|
520
|
+
@attached(peer)
|
|
521
|
+
public macro Guide(description: String? = nil, _ guides: GenerationGuide<Any>...) = #externalMacro(module: "SwiftDataMacros", type: "GuideMacro")
|
|
522
|
+
|
|
523
|
+
/// Constrains a string property of a `@Generable` type to a pattern.
|
|
524
|
+
@attached(peer)
|
|
525
|
+
public macro Guide<RegexOutput>(description: String? = nil, _ guide: Regex<RegexOutput>) = #externalMacro(module: "SwiftDataMacros", type: "GuideMacro")
|
|
526
|
+
|
|
527
|
+
extension String: Generable {
|
|
528
|
+
public static var generationSchema: GenerationSchema { GenerationSchema(node: .string) }
|
|
529
|
+
public init(_ content: GeneratedContent) throws {
|
|
530
|
+
guard case .string(let value) = content.kind else { throw GeneratedContent._mismatch(content, String.self) }
|
|
531
|
+
self = value
|
|
532
|
+
}
|
|
533
|
+
public var generatedContent: GeneratedContent { GeneratedContent(kind: .string(self)) }
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
extension Bool: Generable {
|
|
537
|
+
public static var generationSchema: GenerationSchema { GenerationSchema(node: .boolean) }
|
|
538
|
+
public init(_ content: GeneratedContent) throws {
|
|
539
|
+
guard case .bool(let value) = content.kind else { throw GeneratedContent._mismatch(content, Bool.self) }
|
|
540
|
+
self = value
|
|
541
|
+
}
|
|
542
|
+
public var generatedContent: GeneratedContent { GeneratedContent(kind: .bool(self)) }
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
extension Int: Generable {
|
|
546
|
+
public static var generationSchema: GenerationSchema { GenerationSchema(node: .integer) }
|
|
547
|
+
public init(_ content: GeneratedContent) throws {
|
|
548
|
+
guard case .number(let value) = content.kind, let int = Int(exactly: value) else { throw GeneratedContent._mismatch(content, Int.self) }
|
|
549
|
+
self = int
|
|
550
|
+
}
|
|
551
|
+
public var generatedContent: GeneratedContent { GeneratedContent(kind: .number(Double(self))) }
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
extension Double: Generable {
|
|
555
|
+
public static var generationSchema: GenerationSchema { GenerationSchema(node: .number) }
|
|
556
|
+
public init(_ content: GeneratedContent) throws {
|
|
557
|
+
guard case .number(let value) = content.kind else { throw GeneratedContent._mismatch(content, Double.self) }
|
|
558
|
+
self = value
|
|
559
|
+
}
|
|
560
|
+
public var generatedContent: GeneratedContent { GeneratedContent(kind: .number(self)) }
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
extension Float: Generable {
|
|
564
|
+
public static var generationSchema: GenerationSchema { GenerationSchema(node: .number) }
|
|
565
|
+
public init(_ content: GeneratedContent) throws {
|
|
566
|
+
guard case .number(let value) = content.kind else { throw GeneratedContent._mismatch(content, Float.self) }
|
|
567
|
+
self = Float(value)
|
|
568
|
+
}
|
|
569
|
+
public var generatedContent: GeneratedContent { GeneratedContent(kind: .number(Double(self))) }
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
extension Decimal: Generable {
|
|
573
|
+
public static var generationSchema: GenerationSchema { GenerationSchema(node: .number) }
|
|
574
|
+
public init(_ content: GeneratedContent) throws {
|
|
575
|
+
guard case .number(let value) = content.kind else { throw GeneratedContent._mismatch(content, Decimal.self) }
|
|
576
|
+
self = Decimal(value)
|
|
577
|
+
}
|
|
578
|
+
public var generatedContent: GeneratedContent {
|
|
579
|
+
GeneratedContent(kind: .number(NSDecimalNumber(decimal: self).doubleValue))
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
extension Array: ConvertibleToGeneratedContent where Element: ConvertibleToGeneratedContent {
|
|
584
|
+
public var generatedContent: GeneratedContent { GeneratedContent(kind: .array(map(\.generatedContent))) }
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
extension Array: ConvertibleFromGeneratedContent where Element: ConvertibleFromGeneratedContent {
|
|
588
|
+
public init(_ content: GeneratedContent) throws {
|
|
589
|
+
guard case .array(let items) = content.kind else { throw GeneratedContent._mismatch(content, Array.self) }
|
|
590
|
+
self = try items.map { try Element($0) }
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
extension Array: Generable where Element: Generable {
|
|
595
|
+
public static var generationSchema: GenerationSchema { GenerationSchema(node: .array(Element.generationSchema.node, [])) }
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
extension Optional: ConvertibleToGeneratedContent, InstructionsRepresentable, PromptRepresentable where Wrapped: ConvertibleToGeneratedContent {
|
|
599
|
+
public var generatedContent: GeneratedContent { self?.generatedContent ?? GeneratedContent(kind: .null) }
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
extension GeneratedContent: Generable {
|
|
603
|
+
public static var generationSchema: GenerationSchema { GenerationSchema(node: .any) }
|
|
604
|
+
public init(_ content: GeneratedContent) throws { self = content }
|
|
605
|
+
public var generatedContent: GeneratedContent { self }
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
// MARK: - Schemas and guides
|
|
609
|
+
|
|
610
|
+
/// A constraint on a generated value: a count of elements, a range, choices.
|
|
611
|
+
/// Its type is not checked against the property's here.
|
|
612
|
+
public struct GenerationGuide<Value>: @unchecked Sendable {
|
|
613
|
+
typealias Constraint = _GuideConstraint
|
|
614
|
+
let constraints: [Constraint]
|
|
615
|
+
|
|
616
|
+
/// One of these strings.
|
|
617
|
+
public static func anyOf(_ values: [String]) -> GenerationGuide<Value> { .init(constraints: [.anyOf(values)]) }
|
|
618
|
+
/// Exactly this string.
|
|
619
|
+
public static func constant(_ value: String) -> GenerationGuide<Value> { .init(constraints: [.constant(value)]) }
|
|
620
|
+
/// Exactly `count` elements.
|
|
621
|
+
public static func count(_ count: Int) -> GenerationGuide<Value> { .init(constraints: [.count(count)]) }
|
|
622
|
+
/// Between the bounds' numbers of elements.
|
|
623
|
+
public static func count(_ range: ClosedRange<Int>) -> GenerationGuide<Value> {
|
|
624
|
+
.init(constraints: [.minimumCount(range.lowerBound), .maximumCount(range.upperBound)])
|
|
625
|
+
}
|
|
626
|
+
/// At least `count` elements.
|
|
627
|
+
public static func minimumCount(_ count: Int) -> GenerationGuide<Value> { .init(constraints: [.minimumCount(count)]) }
|
|
628
|
+
/// At most `count` elements.
|
|
629
|
+
public static func maximumCount(_ count: Int) -> GenerationGuide<Value> { .init(constraints: [.maximumCount(count)]) }
|
|
630
|
+
/// A number within the range.
|
|
631
|
+
public static func range(_ range: ClosedRange<Int>) -> GenerationGuide<Value> {
|
|
632
|
+
.init(constraints: [.minimum(Double(range.lowerBound)), .maximum(Double(range.upperBound))])
|
|
633
|
+
}
|
|
634
|
+
public static func range(_ range: ClosedRange<Double>) -> GenerationGuide<Value> {
|
|
635
|
+
.init(constraints: [.minimum(range.lowerBound), .maximum(range.upperBound)])
|
|
636
|
+
}
|
|
637
|
+
/// A number at least `value`.
|
|
638
|
+
public static func minimum(_ value: Int) -> GenerationGuide<Value> { .init(constraints: [.minimum(Double(value))]) }
|
|
639
|
+
public static func minimum(_ value: Double) -> GenerationGuide<Value> { .init(constraints: [.minimum(value)]) }
|
|
640
|
+
/// A number at most `value`.
|
|
641
|
+
public static func maximum(_ value: Int) -> GenerationGuide<Value> { .init(constraints: [.maximum(Double(value))]) }
|
|
642
|
+
public static func maximum(_ value: Double) -> GenerationGuide<Value> { .init(constraints: [.maximum(value)]) }
|
|
643
|
+
/// Applies `guide` to each element.
|
|
644
|
+
public static func element(_ guide: GenerationGuide<Value>) -> GenerationGuide<Value> {
|
|
645
|
+
.init(constraints: [.element(guide.constraints)])
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
/// One constraint of a guide, whatever its value type.
|
|
650
|
+
enum _GuideConstraint: Sendable, Equatable {
|
|
651
|
+
case anyOf([String]), constant(String), pattern(String)
|
|
652
|
+
case count(Int), minimumCount(Int), maximumCount(Int)
|
|
653
|
+
case minimum(Double), maximum(Double)
|
|
654
|
+
case element([_GuideConstraint])
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
/// The shape a generated value must have: a JSON schema (`debugDescription`).
|
|
658
|
+
public struct GenerationSchema: Sendable, CustomDebugStringConvertible {
|
|
659
|
+
indirect enum Node: Sendable {
|
|
660
|
+
case any, string, integer, number, boolean
|
|
661
|
+
case choices([String])
|
|
662
|
+
case array(Node, [_GuideConstraint])
|
|
663
|
+
case object(name: String, description: String?, properties: [Property])
|
|
664
|
+
case guided(Node, description: String?, [_GuideConstraint])
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
/// A property of a structure's schema.
|
|
668
|
+
public struct Property: Sendable {
|
|
669
|
+
let name: String
|
|
670
|
+
let description: String?
|
|
671
|
+
let node: Node
|
|
672
|
+
let isOptional: Bool
|
|
673
|
+
let constraints: [_GuideConstraint]
|
|
674
|
+
|
|
675
|
+
public init<Value: Generable>(name: String, description: String? = nil, type: Value.Type,
|
|
676
|
+
guides: [GenerationGuide<Value>] = []) {
|
|
677
|
+
self.name = name
|
|
678
|
+
self.description = description
|
|
679
|
+
node = Value.generationSchema.node
|
|
680
|
+
isOptional = false
|
|
681
|
+
constraints = guides.flatMap(\.constraints)
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
public init<Value: Generable>(name: String, description: String? = nil, type: Value?.Type,
|
|
685
|
+
guides: [GenerationGuide<Value>] = []) {
|
|
686
|
+
self.name = name
|
|
687
|
+
self.description = description
|
|
688
|
+
node = Value.generationSchema.node
|
|
689
|
+
isOptional = true
|
|
690
|
+
constraints = guides.flatMap(\.constraints)
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
/// `@Generable`'s form: the guides as `@Guide` wrote them.
|
|
694
|
+
public init<Value: Generable>(name: String, description: String? = nil, type: Value.Type,
|
|
695
|
+
_guides: [GenerationGuide<Any>]) {
|
|
696
|
+
self.name = name
|
|
697
|
+
self.description = description
|
|
698
|
+
node = Value.generationSchema.node
|
|
699
|
+
isOptional = false
|
|
700
|
+
constraints = _guides.flatMap(\.constraints)
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
public init<Value: Generable>(name: String, description: String? = nil, type: Value?.Type,
|
|
704
|
+
_guides: [GenerationGuide<Any>]) {
|
|
705
|
+
self.name = name
|
|
706
|
+
self.description = description
|
|
707
|
+
node = Value.generationSchema.node
|
|
708
|
+
isOptional = true
|
|
709
|
+
constraints = _guides.flatMap(\.constraints)
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
let node: Node
|
|
714
|
+
|
|
715
|
+
init(node: Node) { self.node = node }
|
|
716
|
+
|
|
717
|
+
/// A structure with these properties.
|
|
718
|
+
public init(type: any Generable.Type, description: String? = nil, properties: [Property]) {
|
|
719
|
+
node = .object(name: String(describing: type), description: description, properties: properties)
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
/// One of these strings (an enum's cases).
|
|
723
|
+
public init(type: any Generable.Type, description: String? = nil, anyOf choices: [String]) {
|
|
724
|
+
node = .guided(.choices(choices), description: description, [])
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
/// One of these types' values.
|
|
728
|
+
public init(type: any Generable.Type, description: String? = nil, anyOf types: [any Generable.Type]) {
|
|
729
|
+
node = .guided(.any, description: description, [])
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
public var debugDescription: String { Self.json(node).jsonString }
|
|
733
|
+
|
|
734
|
+
static func json(_ node: Node) -> GeneratedContent {
|
|
735
|
+
func object(_ pairs: [(String, GeneratedContent)]) -> GeneratedContent {
|
|
736
|
+
var properties: [String: GeneratedContent] = [:]
|
|
737
|
+
for (key, value) in pairs { properties[key] = value }
|
|
738
|
+
return GeneratedContent(kind: .structure(properties: properties, orderedKeys: pairs.map(\.0)))
|
|
739
|
+
}
|
|
740
|
+
func string(_ text: String) -> GeneratedContent { GeneratedContent(kind: .string(text)) }
|
|
741
|
+
func constrain(_ pairs: inout [(String, GeneratedContent)], _ constraints: [_GuideConstraint]) {
|
|
742
|
+
for constraint in constraints {
|
|
743
|
+
switch constraint {
|
|
744
|
+
case .anyOf(let values): pairs.append(("enum", GeneratedContent(kind: .array(values.map(string)))))
|
|
745
|
+
case .constant(let value): pairs.append(("const", string(value)))
|
|
746
|
+
case .pattern(let value): pairs.append(("pattern", string(value)))
|
|
747
|
+
case .count(let n):
|
|
748
|
+
pairs.append(("minItems", GeneratedContent(kind: .number(Double(n)))))
|
|
749
|
+
pairs.append(("maxItems", GeneratedContent(kind: .number(Double(n)))))
|
|
750
|
+
case .minimumCount(let n): pairs.append(("minItems", GeneratedContent(kind: .number(Double(n)))))
|
|
751
|
+
case .maximumCount(let n): pairs.append(("maxItems", GeneratedContent(kind: .number(Double(n)))))
|
|
752
|
+
case .minimum(let n): pairs.append(("minimum", GeneratedContent(kind: .number(n))))
|
|
753
|
+
case .maximum(let n): pairs.append(("maximum", GeneratedContent(kind: .number(n))))
|
|
754
|
+
case .element: break
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
switch node {
|
|
759
|
+
case .any: return object([])
|
|
760
|
+
case .string: return object([("type", string("string"))])
|
|
761
|
+
case .integer: return object([("type", string("integer"))])
|
|
762
|
+
case .number: return object([("type", string("number"))])
|
|
763
|
+
case .boolean: return object([("type", string("boolean"))])
|
|
764
|
+
case .choices(let values):
|
|
765
|
+
return object([("type", string("string")), ("enum", GeneratedContent(kind: .array(values.map(string))))])
|
|
766
|
+
case .array(let items, let constraints):
|
|
767
|
+
var pairs: [(String, GeneratedContent)] = [("type", string("array")), ("items", json(items))]
|
|
768
|
+
constrain(&pairs, constraints)
|
|
769
|
+
return object(pairs)
|
|
770
|
+
case .guided(let inner, let description, let constraints):
|
|
771
|
+
guard case .structure(let properties, let keys) = json(inner).kind else { return json(inner) }
|
|
772
|
+
var pairs = keys.map { ($0, properties[$0]!) }
|
|
773
|
+
if let description { pairs.append(("description", string(description))) }
|
|
774
|
+
constrain(&pairs, constraints)
|
|
775
|
+
return object(pairs)
|
|
776
|
+
case .object(let name, let description, let properties):
|
|
777
|
+
var pairs: [(String, GeneratedContent)] = [("type", string("object")), ("title", string(name))]
|
|
778
|
+
if let description { pairs.append(("description", string(description))) }
|
|
779
|
+
let fields = properties.map { property -> (String, GeneratedContent) in
|
|
780
|
+
var node = property.node
|
|
781
|
+
let elementConstraints = property.constraints.compactMap { constraint -> [_GuideConstraint]? in
|
|
782
|
+
if case .element(let inner) = constraint { return inner }
|
|
783
|
+
return nil
|
|
784
|
+
}.flatMap { $0 }
|
|
785
|
+
let own = property.constraints.filter { if case .element = $0 { return false } else { return true } }
|
|
786
|
+
if case .array(let items, let existing) = node {
|
|
787
|
+
node = .array(elementConstraints.isEmpty ? items : .guided(items, description: nil, elementConstraints), existing + own)
|
|
788
|
+
return (property.name, json(property.description.map { .guided(node, description: $0, []) } ?? node))
|
|
789
|
+
}
|
|
790
|
+
return (property.name, json(.guided(node, description: property.description, own)))
|
|
791
|
+
}
|
|
792
|
+
pairs.append(("properties", object(fields)))
|
|
793
|
+
pairs.append(("required", GeneratedContent(kind: .array(properties.filter { !$0.isOptional }.map { string($0.name) }))))
|
|
794
|
+
return object(pairs)
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
// MARK: - Tools
|
|
800
|
+
|
|
801
|
+
/// A function the model may call while responding (never, here: there is no model).
|
|
802
|
+
public protocol Tool<Arguments, Output>: Sendable {
|
|
803
|
+
associatedtype Arguments: ConvertibleFromGeneratedContent
|
|
804
|
+
associatedtype Output: PromptRepresentable
|
|
805
|
+
var name: String { get }
|
|
806
|
+
var description: String { get }
|
|
807
|
+
var parameters: GenerationSchema { get }
|
|
808
|
+
var includesSchemaInInstructions: Bool { get }
|
|
809
|
+
func call(arguments: Arguments) async throws -> Output
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
extension Tool {
|
|
813
|
+
public var name: String { String(describing: Self.self) }
|
|
814
|
+
public var includesSchemaInInstructions: Bool { true }
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
extension Tool where Arguments: Generable {
|
|
818
|
+
public var parameters: GenerationSchema { Arguments.generationSchema }
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
// MARK: - Transcripts
|
|
822
|
+
|
|
823
|
+
/// A session's history: its instructions, prompts and responses.
|
|
824
|
+
public struct Transcript: Sendable, Equatable, RandomAccessCollection {
|
|
825
|
+
public struct TextSegment: Sendable, Equatable, Identifiable {
|
|
826
|
+
public var id: String
|
|
827
|
+
public var content: String
|
|
828
|
+
public init(id: String = UUID().uuidString, content: String) {
|
|
829
|
+
self.id = id
|
|
830
|
+
self.content = content
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
public enum Segment: Sendable, Equatable, Identifiable {
|
|
835
|
+
case text(TextSegment)
|
|
836
|
+
public var id: String {
|
|
837
|
+
switch self { case .text(let segment): segment.id }
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
public struct Instructions: Sendable, Equatable, Identifiable {
|
|
842
|
+
public var id: String
|
|
843
|
+
public var segments: [Segment]
|
|
844
|
+
public init(id: String = UUID().uuidString, segments: [Segment]) {
|
|
845
|
+
self.id = id
|
|
846
|
+
self.segments = segments
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
public struct Prompt: Sendable, Equatable, Identifiable {
|
|
851
|
+
public var id: String
|
|
852
|
+
public var segments: [Segment]
|
|
853
|
+
public init(id: String = UUID().uuidString, segments: [Segment]) {
|
|
854
|
+
self.id = id
|
|
855
|
+
self.segments = segments
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
public struct Response: Sendable, Equatable, Identifiable {
|
|
860
|
+
public var id: String
|
|
861
|
+
public var segments: [Segment]
|
|
862
|
+
public init(id: String = UUID().uuidString, segments: [Segment]) {
|
|
863
|
+
self.id = id
|
|
864
|
+
self.segments = segments
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
public enum Entry: Sendable, Equatable, Identifiable {
|
|
869
|
+
case instructions(Instructions)
|
|
870
|
+
case prompt(Prompt)
|
|
871
|
+
case response(Response)
|
|
872
|
+
|
|
873
|
+
public var id: String {
|
|
874
|
+
switch self {
|
|
875
|
+
case .instructions(let entry): entry.id
|
|
876
|
+
case .prompt(let entry): entry.id
|
|
877
|
+
case .response(let entry): entry.id
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
var entries: [Entry]
|
|
883
|
+
|
|
884
|
+
public init() {
|
|
885
|
+
entries = []
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
public init(entries: some Sequence<Entry>) {
|
|
889
|
+
self.entries = Array(entries)
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
public var startIndex: Int { entries.startIndex }
|
|
893
|
+
public var endIndex: Int { entries.endIndex }
|
|
894
|
+
public subscript(position: Int) -> Entry { entries[position] }
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
// MARK: - Sessions
|
|
898
|
+
|
|
899
|
+
/// A conversation with the model. Every request fails with
|
|
900
|
+
/// `GenerationError.assetsUnavailable` in the browser (see the file comment).
|
|
901
|
+
public final class LanguageModelSession: @unchecked Sendable {
|
|
902
|
+
/// Why a request failed.
|
|
903
|
+
public enum GenerationError: Error, LocalizedError, Sendable {
|
|
904
|
+
public struct Context: Sendable {
|
|
905
|
+
public let debugDescription: String
|
|
906
|
+
public init(debugDescription: String) { self.debugDescription = debugDescription }
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
/// A refusal and its explanation.
|
|
910
|
+
public struct Refusal: Sendable {
|
|
911
|
+
public init(transcriptEntries: [Transcript.Entry] = []) {}
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
case exceededContextWindowSize(Context)
|
|
915
|
+
/// The model is not on the device: the browser's answer to every request.
|
|
916
|
+
case assetsUnavailable(Context)
|
|
917
|
+
case guardrailViolation(Context)
|
|
918
|
+
case unsupportedGuide(Context)
|
|
919
|
+
case unsupportedLanguageOrLocale(Context)
|
|
920
|
+
case decodingFailure(Context)
|
|
921
|
+
case rateLimited(Context)
|
|
922
|
+
case concurrentRequests(Context)
|
|
923
|
+
case refusal(Refusal, Context)
|
|
924
|
+
|
|
925
|
+
public var errorDescription: String? {
|
|
926
|
+
switch self {
|
|
927
|
+
case .exceededContextWindowSize(let context), .assetsUnavailable(let context), .guardrailViolation(let context),
|
|
928
|
+
.unsupportedGuide(let context), .unsupportedLanguageOrLocale(let context), .decodingFailure(let context),
|
|
929
|
+
.rateLimited(let context), .concurrentRequests(let context), .refusal(_, let context):
|
|
930
|
+
context.debugDescription
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
/// An error a tool threw while the model called it.
|
|
936
|
+
public struct ToolCallError: Error, LocalizedError {
|
|
937
|
+
public var tool: any Tool
|
|
938
|
+
public var underlyingError: any Error
|
|
939
|
+
public init(tool: any Tool, underlyingError: any Error) {
|
|
940
|
+
self.tool = tool
|
|
941
|
+
self.underlyingError = underlyingError
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
/// A complete response.
|
|
946
|
+
public struct Response<Content> {
|
|
947
|
+
public let content: Content
|
|
948
|
+
public let rawContent: GeneratedContent
|
|
949
|
+
public let transcriptEntries: ArraySlice<Transcript.Entry>
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
/// The snapshots of a response as it is generated. Iterating it fails
|
|
953
|
+
/// with the request's error (here, always `assetsUnavailable`).
|
|
954
|
+
public struct ResponseStream<Content: Generable>: AsyncSequence, Sendable {
|
|
955
|
+
public struct Snapshot {
|
|
956
|
+
public var content: Content.PartiallyGenerated
|
|
957
|
+
public var rawContent: GeneratedContent
|
|
958
|
+
|
|
959
|
+
public init(content: Content.PartiallyGenerated, rawContent: GeneratedContent) {
|
|
960
|
+
self.content = content
|
|
961
|
+
self.rawContent = rawContent
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
public typealias Element = Snapshot
|
|
965
|
+
|
|
966
|
+
let failure: GenerationError
|
|
967
|
+
|
|
968
|
+
public struct AsyncIterator: AsyncIteratorProtocol {
|
|
969
|
+
let failure: GenerationError
|
|
970
|
+
var finished = false
|
|
971
|
+
|
|
972
|
+
public mutating func next() async throws -> Snapshot? {
|
|
973
|
+
guard !finished else { return nil }
|
|
974
|
+
finished = true
|
|
975
|
+
throw failure
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
public func makeAsyncIterator() -> AsyncIterator { AsyncIterator(failure: failure) }
|
|
980
|
+
|
|
981
|
+
/// The whole response, once generated.
|
|
982
|
+
public func collect() async throws -> Response<Content> { throw failure }
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
let model: SystemLanguageModel
|
|
986
|
+
public let tools: [any Tool]
|
|
987
|
+
/// Whether a request is in progress (never: requests fail at once).
|
|
988
|
+
public private(set) var isResponding = false
|
|
989
|
+
/// The instructions; nothing is added, since nothing is generated.
|
|
990
|
+
public private(set) var transcript: Transcript
|
|
991
|
+
|
|
992
|
+
public init(model: SystemLanguageModel = .default, tools: [any Tool] = [], instructions: Instructions? = nil) {
|
|
993
|
+
self.model = model
|
|
994
|
+
self.tools = tools
|
|
995
|
+
var entries: [Transcript.Entry] = []
|
|
996
|
+
if let instructions {
|
|
997
|
+
entries.append(.instructions(Transcript.Instructions(segments: [.text(Transcript.TextSegment(content: instructions.text))])))
|
|
998
|
+
}
|
|
999
|
+
transcript = Transcript(entries: entries)
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
public convenience init(model: SystemLanguageModel = .default, tools: [any Tool] = [], instructions: String) {
|
|
1003
|
+
self.init(model: model, tools: tools, instructions: Instructions(text: instructions))
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
public convenience init(model: SystemLanguageModel = .default, tools: [any Tool] = [],
|
|
1007
|
+
@InstructionsBuilder instructions: () throws -> Instructions) rethrows {
|
|
1008
|
+
self.init(model: model, tools: tools, instructions: try instructions())
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
public init(model: SystemLanguageModel = .default, tools: [any Tool] = [], transcript: Transcript) {
|
|
1012
|
+
self.model = model
|
|
1013
|
+
self.tools = tools
|
|
1014
|
+
self.transcript = transcript
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
/// Loads the model ahead of a request: nothing to load.
|
|
1018
|
+
public func prewarm(promptPrefix: Prompt? = nil) {}
|
|
1019
|
+
|
|
1020
|
+
private var failure: GenerationError {
|
|
1021
|
+
.assetsUnavailable(.init(debugDescription: "The on-device language model is not available in the browser."))
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
// Text responses.
|
|
1025
|
+
|
|
1026
|
+
public func respond(to prompt: String, options: GenerationOptions = GenerationOptions()) async throws -> Response<String> {
|
|
1027
|
+
throw failure
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
public func respond(to prompt: Prompt, options: GenerationOptions = GenerationOptions()) async throws -> Response<String> {
|
|
1031
|
+
throw failure
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
public func respond(options: GenerationOptions = GenerationOptions(),
|
|
1035
|
+
@PromptBuilder prompt: () throws -> Prompt) async throws -> Response<String> {
|
|
1036
|
+
_ = try prompt()
|
|
1037
|
+
throw failure
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
// Generable responses.
|
|
1041
|
+
|
|
1042
|
+
public func respond<Content: Generable>(to prompt: String, generating type: Content.Type = Content.self,
|
|
1043
|
+
includeSchemaInPrompt: Bool = true,
|
|
1044
|
+
options: GenerationOptions = GenerationOptions()) async throws -> Response<Content> {
|
|
1045
|
+
throw failure
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
public func respond<Content: Generable>(to prompt: Prompt, generating type: Content.Type = Content.self,
|
|
1049
|
+
includeSchemaInPrompt: Bool = true,
|
|
1050
|
+
options: GenerationOptions = GenerationOptions()) async throws -> Response<Content> {
|
|
1051
|
+
throw failure
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
public func respond<Content: Generable>(generating type: Content.Type = Content.self, includeSchemaInPrompt: Bool = true,
|
|
1055
|
+
options: GenerationOptions = GenerationOptions(),
|
|
1056
|
+
@PromptBuilder prompt: () throws -> Prompt) async throws -> Response<Content> {
|
|
1057
|
+
_ = try prompt()
|
|
1058
|
+
throw failure
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
public func respond(to prompt: String, schema: GenerationSchema, includeSchemaInPrompt: Bool = true,
|
|
1062
|
+
options: GenerationOptions = GenerationOptions()) async throws -> Response<GeneratedContent> {
|
|
1063
|
+
throw failure
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
// Streams.
|
|
1067
|
+
|
|
1068
|
+
public func streamResponse(to prompt: String, options: GenerationOptions = GenerationOptions()) -> ResponseStream<String> {
|
|
1069
|
+
ResponseStream(failure: failure)
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
public func streamResponse(to prompt: Prompt, options: GenerationOptions = GenerationOptions()) -> ResponseStream<String> {
|
|
1073
|
+
ResponseStream(failure: failure)
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
public func streamResponse(options: GenerationOptions = GenerationOptions(),
|
|
1077
|
+
@PromptBuilder prompt: () throws -> Prompt) rethrows -> ResponseStream<String> {
|
|
1078
|
+
_ = try prompt()
|
|
1079
|
+
return ResponseStream(failure: failure)
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
public func streamResponse<Content: Generable>(to prompt: String, generating type: Content.Type = Content.self,
|
|
1083
|
+
includeSchemaInPrompt: Bool = true,
|
|
1084
|
+
options: GenerationOptions = GenerationOptions()) -> ResponseStream<Content> {
|
|
1085
|
+
ResponseStream(failure: failure)
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
public func streamResponse<Content: Generable>(to prompt: Prompt, generating type: Content.Type = Content.self,
|
|
1089
|
+
includeSchemaInPrompt: Bool = true,
|
|
1090
|
+
options: GenerationOptions = GenerationOptions()) -> ResponseStream<Content> {
|
|
1091
|
+
ResponseStream(failure: failure)
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
public func streamResponse(to prompt: String, schema: GenerationSchema, includeSchemaInPrompt: Bool = true,
|
|
1095
|
+
options: GenerationOptions = GenerationOptions()) -> ResponseStream<GeneratedContent> {
|
|
1096
|
+
ResponseStream(failure: failure)
|
|
1097
|
+
}
|
|
1098
|
+
}
|