Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
e150802
[Firebase AI] Add `Generable` scaffolding
andrewheard Nov 24, 2025
4f7b30a
Add `asOpenAPISchema()` to `GenerationSchema`
andrewheard Nov 24, 2025
97cee24
Rename `GenerationSchema` to `JSONSchema`
andrewheard Nov 24, 2025
d8d983f
Rename `GeneratedContent` to `ModelOutput`
andrewheard Nov 24, 2025
d1b07f1
Merge remote-tracking branch 'origin/main' into ah/ai-generable-macro
andrewheard Nov 24, 2025
7184df4
Add `available(iOS 15.0, macOS 12.0, ..., *)` annotations
andrewheard Nov 24, 2025
d555f0c
Add example output for the `Generable` macro
andrewheard Nov 24, 2025
c435c92
Implement `ModelOutput.value(_:forProperty:)` and add tests
andrewheard Nov 24, 2025
6144992
Add `GenerativeModel.GenerationError` and throw `decodingFailure`
andrewheard Nov 25, 2025
5541a00
Fix Xcode 16 build errors
andrewheard Nov 25, 2025
bb0e9e5
Merge remote-tracking branch 'origin/main' into ah/ai-generable-macro
andrewheard Nov 25, 2025
4cec2b3
More build fixes
andrewheard Nov 25, 2025
a1aa0b0
Add `SendableMetatype` typealias for older Xcode versions
andrewheard Nov 25, 2025
c01d338
Merge remote-tracking branch 'origin/main' into ah/ai-generable-macro
andrewheard Nov 25, 2025
f687ab1
Another Xcode 16 workaround
andrewheard Nov 25, 2025
a6e8e4e
Merge remote-tracking branch 'origin/main' into ah/ai-generable-macro
andrewheard Nov 25, 2025
a219b40
Coalesce type conversion failures
andrewheard Nov 25, 2025
5cafb19
Implement TODOs and add tests (#15535)
paulb777 Nov 26, 2025
e0febca
Decode `Float` and `Double` more leniently
andrewheard Nov 26, 2025
52b4e17
Update error messages in `ModelOutput.value(...)` methods
andrewheard Nov 26, 2025
aebc24e
Merge remote-tracking branch 'origin/main' into ah/ai-generable-macro
andrewheard Nov 26, 2025
4c113d0
Replace `ModelOutput.DecodingError` with `GenerativeModel.GenerationE…
andrewheard Nov 26, 2025
65d7860
Fix `GenerableTests` on Xcode 16.2
andrewheard Nov 27, 2025
33c2a1e
Add `available(iOS 15.0, macOS 12.0, ..., *)` to `GenerableTests`
andrewheard Nov 27, 2025
ad396d5
Try forcing Swift 6 mode on macOS 14 / Xcode 16.2
andrewheard Nov 27, 2025
46ab2c7
Merge remote-tracking branch 'origin/main' into ah/ai-generable-macro
andrewheard Nov 27, 2025
9922957
Rewrite `GenerableTests` from Swift Testing to XCTest
andrewheard Nov 27, 2025
bfb5bf4
Add `available(iOS 15.0, macOS 12.0, ..., *)` annotation
andrewheard Nov 27, 2025
b81c154
Add `FirebaseAILogicMacros` SPM target with placeholder macro
andrewheard Nov 27, 2025
551cfd7
Workaround transient SPM build issues due to prebuilt swift-syntax
andrewheard Nov 27, 2025
94f989f
Revert "Try forcing Swift 6 mode on macOS 14 / Xcode 16.2"
andrewheard Nov 27, 2025
21816b0
Try removing `spm-package-resolved` job
andrewheard Nov 28, 2025
fb5f2e2
Revert "Try removing `spm-package-resolved` job"
andrewheard Nov 28, 2025
fdb4dbf
Set `IDEPackageEnablePrebuilts NO`
andrewheard Nov 28, 2025
2395e13
Revert "Set `IDEPackageEnablePrebuilts NO`"
andrewheard Nov 28, 2025
33bda28
Refactor to more closely match starter project from Xcode 16.2
andrewheard Nov 28, 2025
45c4300
Switch `swift-syntax` dependency version based on Swift version
andrewheard Nov 28, 2025
e817d78
Try disabling Swift prebuilts again
andrewheard Nov 28, 2025
53373e8
Try building without `-sdk`
andrewheard Dec 1, 2025
88b411e
Revert `.github/workflows/common.yml` changes
andrewheard Dec 1, 2025
69afe2c
Fix podspec macro file exclusions
andrewheard Dec 1, 2025
8f39570
Simplify `swift-syntax` declaration in `Package.swift`
andrewheard Dec 1, 2025
a91d14f
Set arch based on platform
andrewheard Dec 1, 2025
1888510
Stop restoring SPM cache
andrewheard Dec 2, 2025
6d09c52
Merge remote-tracking branch 'origin/main' into ah/ai-generable-macro
andrewheard Dec 2, 2025
a86c616
Update `swift-syntax` dependency range
andrewheard Dec 2, 2025
d929a23
Remove `spm-package-resolved` from `common` workflow
andrewheard Dec 2, 2025
fdb1ea0
Try Xcode 26.0
andrewheard Dec 2, 2025
197f3ba
Revert "Try Xcode 26.0"
andrewheard Dec 2, 2025
6c7745a
Set `-IDEPackageEnablePrebuilts=NO`
andrewheard Dec 2, 2025
b100dc0
Update macOS `-destination` flag
andrewheard Dec 2, 2025
b35a5f6
Set `IDEPackageEnablePrebuilts NO` in quickstart build
andrewheard Dec 2, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 0 additions & 34 deletions .github/workflows/common.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,40 +52,10 @@ on:
required: false
default: ""

outputs:
cache_key:
description: "The cache key for the Swift package resolution."
value: ${{ jobs.spm-package-resolved.outputs.cache_key }}

jobs:
spm-package-resolved:
env:
FIREBASECI_USE_LATEST_GOOGLEAPPMEASUREMENT: 1
runs-on: macos-15
outputs:
cache_key: ${{ steps.generate_cache_key.outputs.cache_key }}
steps:
- uses: actions/checkout@v4
- name: Xcode
run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer
- name: Generate Swift Package.resolved
id: swift_package_resolve
run: swift package resolve
- name: Generate cache key
id: generate_cache_key
run: |
cache_key="${{ runner.os }}-spm-${{ hashFiles('**/Package.resolved') }}"
echo "cache_key=${cache_key}" >> "$GITHUB_OUTPUT"
- uses: actions/cache/save@v4
id: cache
with:
path: .build
key: ${{ steps.generate_cache_key.outputs.cache_key }}

spm:
# Run on the main repo's scheduled jobs or pull requests and manual workflow invocations.
if: (github.repository == 'firebase/firebase-ios-sdk' && github.event_name == 'schedule') || contains(fromJSON('["pull_request", "workflow_dispatch"]'), github.event_name)
needs: [spm-package-resolved]
strategy:
matrix:
os: [macos-15]
Expand All @@ -101,10 +71,6 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/cache/restore@v4
with:
path: .build
key: ${{needs.spm-package-resolved.outputs.cache_key}}
- name: Xcode
run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer
- name: Run setup command, if needed.
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/firebaseai.yml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Xcode
run: sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer
run: |
sudo xcode-select -s /Applications/${{ matrix.xcode }}.app/Contents/Developer
defaults write com.apple.dt.Xcode IDEPackageEnablePrebuilts NO
- name: Build Quickstart
run: scripts/quickstart_build_spm.sh FirebaseAI
23 changes: 23 additions & 0 deletions FirebaseAI/Sources/Macros/FirebaseAILogicPlugin.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import SwiftCompilerPlugin
import SwiftSyntaxMacros

@main
struct FirebaseAILogicPlugin: CompilerPlugin {
let providingMacros: [Macro.Type] = [
StringifyMacro.self,
]
}
37 changes: 37 additions & 0 deletions FirebaseAI/Sources/Macros/StringifyMacro.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import SwiftSyntax
import SwiftSyntaxBuilder
import SwiftSyntaxMacros

/// Implementation of the `stringify` macro, which takes an expression
/// of any type and produces a tuple containing the value of that expression
/// and the source code that produced the value. For example
///
/// #stringify(x + y)
///
/// will expand to
///
/// (x + y, "x + y")
public struct StringifyMacro: ExpressionMacro {
public static func expansion(of node: some FreestandingMacroExpansionSyntax,
in context: some MacroExpansionContext) -> ExprSyntax {
guard let argument = node.arguments.first?.expression else {
fatalError("compiler bug: the macro does not have any arguments")
}

return "(\(argument), \(literal: argument.description))"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import Foundation

/// A type that can be initialized from model output.
@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *)
public protocol ConvertibleFromModelOutput: SendableMetatype {
/// Creates an instance from content generated by a model.
///
/// Conformance to this protocol is provided by the `@Generable` macro. A manual implementation
/// may be used to map values onto properties using different names. To manually initialize your
/// type from model output, decode the values as shown below:
///
/// ```swift
/// struct Person: ConvertibleFromModelOutput {
/// var name: String
/// var age: Int
///
/// init(_ content: ModelOutput) {
/// self.name = try content.value(forProperty: "firstName")
/// self.age = try content.value(forProperty: "ageInYears")
/// }
/// }
/// ```
///
/// - Important: If your type also conforms to ``ConvertibleToModelOutput``, it is critical
/// that this implementation be symmetrical with
/// ``ConvertibleToModelOutput/modelOutput``.
///
/// - SeeAlso: `@Generable` macro ``Generable(description:)``
init(_ content: ModelOutput) throws
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/// A type that can be converted to model output.
@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *)
public protocol ConvertibleToModelOutput {
/// This instance represented as model output.
///
/// Conformance to this protocol is provided by the `@Generable` macro. A manual implementation
/// may be used to map values onto properties using different names. Use the `modelOutput`
/// property as shown below, to manually return a new ``ModelOutput`` with the properties
/// you specify.
///
/// ```swift
/// struct Person: ConvertibleToModelOutput {
/// var name: String
/// var age: Int
///
/// var modelOutput: ModelOutput {
/// ModelOutput(properties: [
/// "firstName": name,
/// "ageInYears": age
/// ])
/// }
/// }
/// ```
///
/// - Important: If your type also conforms to ``ConvertibleFromModelOutput``, it is
/// critical that this implementation be symmetrical with
/// ``ConvertibleFromModelOutput/init(_:)``.
var modelOutput: ModelOutput { get }
}
Loading
Loading