Source code for apple_fm_sdk.transcript

# For licensing see accompanying LICENSE file.
# Copyright (C) 2026 Apple Inc. All Rights Reserved.

import json
import ctypes

from apple_fm_sdk.errors import _status_code_to_exception
from apple_fm_sdk.c_helpers import _get_error_string


try:
    from . import _ctypes_bindings as lib
except ImportError:
    raise ImportError(
        "Foundation Models C bindings not found. Please ensure _foundationmodels_ctypes.py is available."
    )


[docs] class Transcript: """Represents a foundation model session's transcript. A ``Transcript`` provides access to the complete session history of a LanguageModelSession, including all user prompts, model responses, and tool invocations. The transcript is automatically updated after each interaction with the model. **Transcript Format:** The transcript follows the Foundation Models Swift framework structure and is organized as a dictionary containing: - **version**: Integer version number (currently 1) - **type**: String identifier "FoundationModels.Transcript" - **transcript**: Object containing: - **entries**: List of session entries, each with: - ``id``: Unique UUID for the entry - ``role``: One of "instructions", "user", "response", or "tool" - ``contents``: Array of content objects with ``type``, ``id``, and type-specific fields **Entry Types by Role:** - **instructions**: System instructions and tool definitions - ``tools``: Array of available tool definitions - ``contents``: Array with text instructions - **user**: User messages and requests - ``contents``: Array of content objects (text and more) - ``options``: Optional configuration for the request - ``responseFormat``: Optional structured output schema - **response**: Model-generated responses - ``toolCalls``: Array of tool invocations (if tools were called) - ``contents``: Array of response content (text or structured data) - ``assets``: Array of model asset identifiers used - **tool**: Tool execution results - ``toolName``: Name of the executed tool - ``toolCallID``: UUID linking to the tool call - ``contents``: Array with tool execution results **When Transcripts Are Updated:** - After each ``respond()`` call completes successfully - After each ``stream_response()`` completes - After tool invocations are processed - NOT during streaming (only after completion) - NOT if a request fails or is cancelled Examples: Accessing transcript after session:: import apple_fm_sdk as fm session = fm.LanguageModelSession() await session.respond("Hello!") await session.respond("What is Python?") # Get the full session history transcript = await session.transcript.to_dict() # Access the entries entries = transcript["transcript"]["entries"] for entry in entries: role = entry["role"] print(f"Entry role: {role}") if "contents" in entry: for content in entry["contents"]: if content["type"] == "text": print(f" Text: {content['text']}") Monitoring session length:: import apple_fm_sdk as fm session = fm.LanguageModelSession() for i in range(5): await session.respond(f"Question {i}") transcript = await session.transcript.to_dict() entry_count = len(transcript["transcript"]["entries"]) print(f"Session has {entry_count} entries") Examining tool calls in transcript:: import apple_fm_sdk as fm from my_tools import CalculatorTool session = fm.LanguageModelSession( tools=[CalculatorTool()] ) await session.respond("What is 15 * 24?") transcript = await session.transcript.to_dict() # Find entries with tool calls for entry in transcript["transcript"]["entries"]: if entry["role"] == "response" and "toolCalls" in entry: print(f"Tool calls: {entry['toolCalls']}") elif entry["role"] == "tool": print(f"Tool result for {entry['toolName']}") Saving session history:: import apple_fm_sdk as fm import json session = fm.LanguageModelSession() # Have a session await session.respond("Hello") await session.respond("Tell me about Python") # Save transcript to file transcript = await session.transcript.to_dict() with open("session.json", "w") as f: json.dump(transcript, f, indent=2) Note: - The transcript object shares the session's internal pointer - Transcripts are read-only; you cannot modify session history - Large sessions may result in large transcript dictionaries - The transcript format follows the Foundation Models Swift framework structure - Accessing the transcript does not affect the session state See Also: - :class:`~apple_fm_sdk.session.LanguageModelSession`: For creating sessions - :meth:`~apple_fm_sdk.session.LanguageModelSession.respond`: For making requests """
[docs] def __init__( self, _ptr, ): """Initialize a Transcript instance. Note: Transcript instances are automatically created by LanguageModelSession. Do not create Transcript instances directly. """ # A transcript doesn't get it's own pointer, it uses the session's pointer self.session_ptr = _ptr
[docs] async def to_dict(self) -> dict: """Get the current transcript of the session as a dictionary. This function retrieves the complete session history, including all user messages, model responses, and tool interactions. The transcript is returned as a structured dictionary following the Foundation Models Swift framework format. :return: The transcript data as a dictionary with the following structure: - ``version`` (int): Version number (currently 1) - ``type`` (str): Type identifier "FoundationModels.Transcript" - ``transcript`` (dict): Object containing: - ``entries`` (list): List of session entries, each with: - ``id`` (str): Unique UUID for the entry - ``role`` (str): One of "instructions", "user", "response", or "tool" - ``contents`` (list): Array of content objects - Additional role-specific fields (tools, toolCalls, options, and more) :rtype: dict :raises GenerationError: If fetching the transcript fails due to an internal error Example: :: import apple_fm_sdk as fm session = fm.LanguageModelSession() await session.respond("Hello!") transcript = await session.transcript.to_dict() # Access entries entries = transcript["transcript"]["entries"] for entry in entries: print(f"{entry['role']}: {entry.get('id')}") Note: - This is an async function and must be awaited - The returned dictionary is a snapshot; it won't update automatically - Call this function again to get an updated transcript after new interactions """ error_code = ctypes.c_int32() # C error status code error_description = ctypes.POINTER( ctypes.c_char )() # C error description pointer jsn_string = lib.FMLanguageModelSessionGetTranscriptJSONString( self.session_ptr, ctypes.byref(error_code), ctypes.byref(error_description) ) # Check if we got a valid result or an error if jsn_string is None or ( hasattr(jsn_string, "data") and jsn_string.data is None ): # An error occurred, raise appropriate exception err_code, err_desc = _get_error_string(error_code, error_description) error_msg = "Failed to fetch session transcript" if err_desc: error_msg = error_msg + ": " + err_desc raise _status_code_to_exception(err_code or error_code.value, error_msg) # Successfully got the JSON string, parse it and free the C string # The return value is wrapped in a String object by ctypes # The String wrapper handles memory, so we don't need to manually free json_str = str(jsn_string) result = json.loads(json_str) return result