TranscriptRendering.swift 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. //===----------------------------------------------------------------------===//
  2. //
  3. // This source file is part of the Foundation Models open source project.
  4. //
  5. // Copyright © 2024-2027 Apple Inc. and the Foundation Models project authors.
  6. //
  7. // Licensed under the Apache License v2.0
  8. //
  9. // See LICENSE.txt for license information
  10. //
  11. //===----------------------------------------------------------------------===//
  12. import FoundationModels
  13. extension Transcript.Entry {
  14. /// Plain-text role-tagged rendering of this entry, suitable for embedding
  15. /// in an LLM prompt. Returns `nil` for entries without conversational
  16. /// text (for example, `.instructions`).
  17. var chatText: String? {
  18. switch self {
  19. case .prompt(let prompt):
  20. return "User: \(prompt.segments.textContent)"
  21. case .response(let response):
  22. return "Assistant: \(response.segments.textContent)"
  23. case .reasoning(let reasoning):
  24. return "Assistant (reasoning): \(reasoning.segments.textContent)"
  25. case .toolCalls(let calls):
  26. let rendered =
  27. calls
  28. .map { "\($0.toolName)(\($0.arguments))" }
  29. .joined(separator: ", ")
  30. return "Tool call: \(rendered)"
  31. case .toolOutput(let output):
  32. return "Tool output (\(output.toolName)): \(output.segments.textContent)"
  33. case .instructions:
  34. return nil
  35. @unknown default:
  36. return nil
  37. }
  38. }
  39. }
  40. extension Sequence where Element == Transcript.Entry {
  41. /// Renders the entries as role-tagged lines joined by `separator`,
  42. /// omitting non-conversational entries.
  43. func chatLog(separator: String = "\n") -> String {
  44. compactMap(\.chatText).joined(separator: separator)
  45. }
  46. }
  47. extension Sequence where Element == Transcript.Segment {
  48. /// Concatenates the textual content of any text segments, ignoring
  49. /// structured content and attachments.
  50. var textContent: String {
  51. compactMap { segment in
  52. if case .text(let textSegment) = segment {
  53. return textSegment.content
  54. }
  55. return nil
  56. }
  57. .joined(separator: " ")
  58. }
  59. }