Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ import FoundationModelsCDeclarations
import Synchronization

enum ComposedPromptError: Error {
case unsupported
// Error thrown when the SDK, at build time, does not support attachments
case unsupportedSDK
// Error thrown when the runtime OS does not support attachments
case unsupportedOS
}

/// Builder class for a `Prompt`.
Expand All @@ -36,10 +39,12 @@ public class ComposedPrompt: NSObject, PromptRepresentable {
}
self.components.append(attachment)
return
} else {
throw ComposedPromptError.unsupportedOS
}
#else
throw ComposedPromptError.unsupportedSDK
#endif

throw ComposedPromptError.unsupported
}

public var promptRepresentation: Prompt {
Expand Down Expand Up @@ -74,8 +79,11 @@ public func FMComposedPromptAddAttachment(
do {
try composedPrompt.add(attachmentFromPath: imageURLToAddToPrompt, label: labelString)
return true
} catch ComposedPromptError.unsupported {
error?.pointee = FMComposedPromptAddImageErrorUnsupported
} catch ComposedPromptError.unsupportedOS {
error?.pointee = FMComposedPromptAddImageErrorUnsupportedOS
return false
} catch ComposedPromptError.unsupportedSDK {
error?.pointee = FMComposedPromptAddImageErrorUnsupportedSDK
Comment on lines +82 to +86

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this really be within the responsibilities of the C bindings? This is not really bridging anything from the Swift framework. Is it at all possible to detect OS/SDK mismatches from the Python side?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wish we didn't have to maintain this piping code in the Swift package, but I couldn't quite find any viable alternatives that include the image input functionality for macOS 27 users, without breaking builds of the package for users still using the macOS 26 SDK. Looked into accessing the symbols dynamically using dlsym, but it doesn't seem to work well with Swift structs like Attachment. We could also maintain two versions of our package (one using the macOS 27 symbols, one without), but it might then just mean more friction when installing the package. Have any other ideas?

Ultimately, we can always remove this code if we don't feel good about adding this in our bindings, but it'll just mean that it might be harder for a user to understand why image attachments are unsupported, especially in edge cases such as when they're using a macOS 26 SDK on a macOS 27 machine. We could consider other mitigations like logging on pip install.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good

return false
} catch _ {
error?.pointee = FMComposedPromptAddImageErrorUnknown
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ FMComposedPrompt _Nonnull FMComposedPromptInitialize();

typedef enum {
FMComposedPromptAddImageErrorNone,
FMComposedPromptAddImageErrorUnsupported,
FMComposedPromptAddImageErrorUnsupportedOS,
FMComposedPromptAddImageErrorUnsupportedSDK,
FMComposedPromptAddImageErrorUnknown
} FMComposedPromptAddImageError;

Expand Down
27 changes: 16 additions & 11 deletions src/apple_fm_sdk/prompt.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@

from abc import ABC, abstractmethod
import logging
from .c_helpers import (
_get_error_string,
)
from typing import Optional, Union
from pathlib import Path

Expand All @@ -15,6 +12,10 @@

try:
from . import _ctypes_bindings as lib
from ._ctypes_bindings import (
FMComposedPromptAddImageErrorUnsupportedOS,
FMComposedPromptAddImageErrorUnsupportedSDK,
)
except ImportError:
raise ImportError(
"Foundation Models C bindings not found. Please ensure _foundationmodels_ctypes.py is available."
Expand Down Expand Up @@ -158,7 +159,8 @@ def add_to_composed_prompt(self, composed_prompt):
:param composed_prompt: The native composed prompt object to add this attachment to
:type composed_prompt: ctypes pointer
:raises ImagePromptError: If the attachment cannot be added, either because
the image format is not supported or another error occurs
the runtime OS or the build-time SDK doesn't support attachments, or
another error occurs.
"""
label_bytes = self._label.encode("utf-8") if self._label else None
error_reason = ctypes.c_int()
Expand All @@ -168,11 +170,13 @@ def add_to_composed_prompt(self, composed_prompt):
label_bytes,
ctypes.byref(error_reason),
):
error = _get_error_string(error_reason, None)
error_message = error[1] if error[1] else "Attachment prompts not supported"
raise ImagePromptError(
f"Failed to add attachment to prompt: {error_message}"
)
if error_reason.value == FMComposedPromptAddImageErrorUnsupportedOS:
detail = "the current OS does not support attachment prompts"
elif error_reason.value == FMComposedPromptAddImageErrorUnsupportedSDK:
detail = "the Xcode version used to build this package doesn't include macOS 27 SDKs"
else:
detail = "an unknown error occurred while adding the attachment"
raise ImagePromptError(f"Failed to add attachment to prompt: {detail}")


PromptComponent = Union[str, Attachment]
Expand Down Expand Up @@ -251,8 +255,9 @@ class ImagePromptError(PromptError):
This exception is raised when there are issues with image attachments, such as:

- Image file not found at the specified path
- Unsupported image format
- Failure to add the image to the prompt
- The current OS does not support attachment prompts
- The Xcode version used to build this package doesn't include the right SDKs for
image input support

Examples:
Handling image prompt errors::
Expand Down