|
78 | 78 | let fmSession = FoundationModels.LanguageModelSession( |
79 | 79 | model: systemModel, |
80 | 80 | tools: session.tools.toFoundationModels(), |
81 | | - instructions: session.instructions?.toFoundationModels() |
| 81 | + transcript: session.transcript.toFoundationModels(instructions: session.instructions) |
82 | 82 | ) |
83 | 83 |
|
84 | 84 | let fmResponse = try await fmSession.respond(to: fmPrompt, options: fmOptions) |
|
115 | 115 | let fmSession = FoundationModels.LanguageModelSession( |
116 | 116 | model: systemModel, |
117 | 117 | tools: session.tools.toFoundationModels(), |
118 | | - instructions: session.instructions?.toFoundationModels() |
| 118 | + transcript: session.transcript.toFoundationModels(instructions: session.instructions) |
119 | 119 | ) |
120 | 120 |
|
121 | 121 | let stream = AsyncThrowingStream<LanguageModelSession.ResponseStream<Content>.Snapshot, any Error> { |
|
475 | 475 | nil |
476 | 476 | } |
477 | 477 | } |
| 478 | + |
| 479 | + @available(macOS 26.0, iOS 26.0, watchOS 26.0, tvOS 26.0, visionOS 26.0, *) |
| 480 | + extension Transcript { |
| 481 | + fileprivate func toFoundationModels(instructions: AnyLanguageModel.Instructions?) -> FoundationModels.Transcript |
| 482 | + { |
| 483 | + var fmEntries: [FoundationModels.Transcript.Entry] = [] |
| 484 | + |
| 485 | + // Add instructions entry if provided and not already in transcript |
| 486 | + if let instructions = instructions { |
| 487 | + let hasInstructions = |
| 488 | + self.first.map { entry in |
| 489 | + if case .instructions = entry { return true } else { return false } |
| 490 | + } ?? false |
| 491 | + |
| 492 | + if !hasInstructions { |
| 493 | + let fmInstructions = FoundationModels.Transcript.Instructions( |
| 494 | + segments: [.text(.init(content: instructions.description))], |
| 495 | + toolDefinitions: [] |
| 496 | + ) |
| 497 | + fmEntries.append(.instructions(fmInstructions)) |
| 498 | + } |
| 499 | + } |
| 500 | + |
| 501 | + // Convert each entry |
| 502 | + for entry in self { |
| 503 | + switch entry { |
| 504 | + case .instructions(let instr): |
| 505 | + let fmSegments = instr.segments.toFoundationModels() |
| 506 | + let fmToolDefinitions = instr.toolDefinitions.toFoundationModels() |
| 507 | + let fmInstructions = FoundationModels.Transcript.Instructions( |
| 508 | + segments: fmSegments, |
| 509 | + toolDefinitions: fmToolDefinitions |
| 510 | + ) |
| 511 | + fmEntries.append(.instructions(fmInstructions)) |
| 512 | + |
| 513 | + case .prompt(let prompt): |
| 514 | + let fmSegments = prompt.segments.toFoundationModels() |
| 515 | + let fmPrompt = FoundationModels.Transcript.Prompt( |
| 516 | + segments: fmSegments |
| 517 | + ) |
| 518 | + fmEntries.append(.prompt(fmPrompt)) |
| 519 | + |
| 520 | + case .response(let response): |
| 521 | + let fmSegments = response.segments.toFoundationModels() |
| 522 | + let fmResponse = FoundationModels.Transcript.Response( |
| 523 | + assetIDs: response.assetIDs, |
| 524 | + segments: fmSegments |
| 525 | + ) |
| 526 | + fmEntries.append(.response(fmResponse)) |
| 527 | + |
| 528 | + case .toolCalls(let toolCalls): |
| 529 | + let fmCalls = toolCalls.compactMap { call -> FoundationModels.Transcript.ToolCall? in |
| 530 | + guard let fmArguments = try? FoundationModels.GeneratedContent(call.arguments) else { |
| 531 | + return nil |
| 532 | + } |
| 533 | + return FoundationModels.Transcript.ToolCall( |
| 534 | + id: call.id, |
| 535 | + toolName: call.toolName, |
| 536 | + arguments: fmArguments |
| 537 | + ) |
| 538 | + } |
| 539 | + let fmToolCalls = FoundationModels.Transcript.ToolCalls(id: toolCalls.id, fmCalls) |
| 540 | + fmEntries.append(.toolCalls(fmToolCalls)) |
| 541 | + |
| 542 | + case .toolOutput(let toolOutput): |
| 543 | + let fmSegments = toolOutput.segments.toFoundationModels() |
| 544 | + let fmToolOutput = FoundationModels.Transcript.ToolOutput( |
| 545 | + id: toolOutput.id, |
| 546 | + toolName: toolOutput.toolName, |
| 547 | + segments: fmSegments |
| 548 | + ) |
| 549 | + fmEntries.append(.toolOutput(fmToolOutput)) |
| 550 | + } |
| 551 | + } |
| 552 | + |
| 553 | + return FoundationModels.Transcript(entries: fmEntries) |
| 554 | + } |
| 555 | + } |
| 556 | + |
| 557 | + @available(macOS 26.0, iOS 26.0, watchOS 26.0, tvOS 26.0, visionOS 26.0, *) |
| 558 | + extension Array where Element == Transcript.Segment { |
| 559 | + fileprivate func toFoundationModels() -> [FoundationModels.Transcript.Segment] { |
| 560 | + compactMap { segment -> FoundationModels.Transcript.Segment? in |
| 561 | + switch segment { |
| 562 | + case .text(let textSegment): |
| 563 | + return .text(.init(id: textSegment.id, content: textSegment.content)) |
| 564 | + case .structure(let structuredSegment): |
| 565 | + guard let fmContent = try? FoundationModels.GeneratedContent(structuredSegment.content) else { |
| 566 | + return nil |
| 567 | + } |
| 568 | + return .structure( |
| 569 | + .init( |
| 570 | + id: structuredSegment.id, |
| 571 | + source: structuredSegment.source, |
| 572 | + content: fmContent |
| 573 | + ) |
| 574 | + ) |
| 575 | + case .image: |
| 576 | + // FoundationModels Transcript does not support image segments |
| 577 | + return nil |
| 578 | + } |
| 579 | + } |
| 580 | + } |
| 581 | + } |
| 582 | + |
| 583 | + @available(macOS 26.0, iOS 26.0, watchOS 26.0, tvOS 26.0, visionOS 26.0, *) |
| 584 | + extension Array where Element == Transcript.ToolDefinition { |
| 585 | + fileprivate func toFoundationModels() -> [FoundationModels.Transcript.ToolDefinition] { |
| 586 | + map { toolDef in |
| 587 | + FoundationModels.Transcript.ToolDefinition( |
| 588 | + name: toolDef.name, |
| 589 | + description: toolDef.description, |
| 590 | + parameters: FoundationModels.GenerationSchema(toolDef.parameters) |
| 591 | + ) |
| 592 | + } |
| 593 | + } |
| 594 | + } |
478 | 595 | #endif |
0 commit comments