จัดการเซสชันสำหรับ Live API

Gemini Live API จะประมวลผลสตรีมเสียงหรือข้อความอย่างต่อเนื่อง ซึ่งเรียกว่าเซสชัน คุณสามารถจัดการวงจรของเซสชันได้ตั้งแต่การแฮนด์เชคเริ่มต้นไปจนถึงการสิ้นสุดอย่างราบรื่น

ขีดจำกัดสำหรับเซสชัน

สำหรับ Live API เซสชันหมายถึงการเชื่อมต่อแบบถาวรที่มีการสตรีมอินพุตและเอาต์พุตอย่างต่อเนื่องผ่านการเชื่อมต่อ

หากเซสชันเกินขีดจำกัดข้อใดข้อหนึ่งต่อไปนี้ ระบบจะสิ้นสุดการเชื่อมต่อ อย่างไรก็ตาม โปรดทราบว่า Live API มีตัวเลือกบางอย่าง (ดูด้านล่าง) เพื่อจัดการขีดจำกัดที่เกี่ยวข้องกับเซสชันเหล่านี้

  • หน้าต่างบริบทของเซสชันจำกัดไว้ที่ 128,000 โทเค็น

    เนื่องจากขีดจำกัดของหน้าต่างบริบทนี้ ระยะเวลาเซสชันสูงสุดโดยประมาณตามรูปแบบอินพุตมีดังนี้

    • เซสชันอินพุตแบบเสียงเท่านั้นจำกัดไว้ที่ 15 นาที
    • วิดีโอ + อินพุตเสียงจำกัดไว้ที่ 2 นาที
  • ระยะเวลาการเชื่อมต่อจำกัดอยู่ที่ประมาณ 10 นาที

    คุณจะได้รับการแจ้งเตือนว่ากำลังจะออกประมาณ 60 วินาทีก่อนที่การเชื่อมต่อจะสิ้นสุดลง

ตัวเลือกบางส่วนในการจัดการขีดจำกัดที่เกี่ยวข้องกับเซสชันมีดังนี้

  • บีบอัดหน้าต่างบริบทของเซสชันเพื่อให้เซิร์ฟเวอร์รักษาขนาดบริบทให้อยู่ภายในขีดจำกัดโดยอัตโนมัติ

  • กลับมาทำเซสชันต่อเพื่อป้องกันไม่ให้บริบทการสนทนาหายไประหว่างที่เครือข่ายขาดการเชื่อมต่อเป็นเวลาสั้นๆ หรือหลังจากได้รับการแจ้งเตือนกำลังจะออก

เริ่มเซสชัน

ไปที่คู่มือเริ่มต้นใช้งานสำหรับ Live API เพื่อดูข้อมูลโค้ดแบบเต็มที่แสดงวิธีเริ่มเซสชัน

อัปเดตระหว่างเซสชัน

โมเดล Live API รองรับความสามารถขั้นสูงต่อไปนี้สำหรับการอัปเดตระหว่างเซสชัน

เพิ่มการอัปเดตเนื้อหาที่เพิ่มขึ้น

คุณสามารถเพิ่มการอัปเดตที่เพิ่มขึ้นในระหว่างเซสชันที่ใช้งานอยู่ได้ ใช้เพื่อส่งอินพุตข้อความ สร้างบริบทเซสชัน หรือกู้คืนบริบทเซสชัน

  • สำหรับบริบทที่ยาวขึ้น เราขอแนะนำให้ระบุสรุปข้อความเดียวเพื่อเพิ่มพื้นที่ว่างในหน้าต่างบริบทสำหรับการโต้ตอบที่ตามมา

  • สำหรับบริบทสั้นๆ คุณสามารถส่งการโต้ตอบแบบเลี้ยวต่อเลี้ยวเพื่อแสดงลำดับเหตุการณ์ที่แน่นอนได้ เช่น ข้อมูลโค้ดด้านล่าง

Swift

// Define initial turns (history/context).
let turns: [ModelContent] = [
  ModelContent(role: "user", parts: [TextPart("What is the capital of France?")]),
  ModelContent(role: "model", parts: [TextPart("Paris")]),
]

// Send history, keeping the conversational turn OPEN (false).
await session.sendContent(turns, turnComplete: false)

// Define the new user query.
let newTurn: [ModelContent] = [
  ModelContent(role: "user", parts: [TextPart("What is the capital of Germany?")]),
]

// Send the final query, CLOSING the turn (true) to trigger the model response.
await session.sendContent(newTurn, turnComplete: true)

Kotlin

// Define initial turns (history/context).
val turns = listOf(
  content("user") {
    text("What is the capital of France?")
  },
  content("model") {
    text("Paris")
  }
)

// Send history, keeping the conversational turn OPEN (false).
turns.forEach {
  session.send(
    content = it,
    turnComplete = false
  )
}

// Define the new user query.
val newTurn = content("user") {
  text("What is the capital of Germany?")
}

// Send the final query, CLOSING the turn (true) to trigger the model response.
session.send(
  content = newTurn,
  turnComplete = true
)

Java

// Define initial turns (history/context).
List turns =
    Arrays.asList(
        new Content.Builder().setRole("user").addText("What is the capital of France?").build(),
        new Content.Builder().setRole("model").addText("Paris").build());

for (Content turn : turns) {
  session.send(
    turn,
    false // turnComplete: false
  );
}

// Define the new user query.
Content newTurn = new Content.Builder().addText("What is the capital of Germany?").build();

// Send the final query, CLOSING the turn (true) to trigger the model response.
session.send(
  newTurn,
  true // isTurnComplete: true
);

Web

const turns = [{ type: "text", text: "Hello from the user!" }];

await session.send(
  turns,
  false // turnComplete: false
);

console.log("Sent history. Waiting for next input...");

// Define the new user query.
const newTurn = [{ type: "text", text: "And what is the capital of Germany?" }];

// Send the final query, CLOSING the turn (true) to trigger the model response.
await session.send(
    newTurn,
    true // turnComplete: true
);
console.log("Sent final query. Model response expected now.");

Dart

// Define initial turns (history/context).
final List turns = [
  Content(
    "user",
    [TextPart("What is the capital of France?")],
  ),
  Content(
    "model",
    [TextPart("Paris")],
  ),
];

// Send history, keeping the conversational turn OPEN (false).
await session.send(
  input: turns,
  turnComplete: false,
);

// Define the new user query.
final List newTurn = [
  Content(
    "user",
    [TextPart("What is the capital of Germany?")],
  ),
];

// Send the final query, CLOSING the turn (true) to trigger the model response.
await session.send(
  input: newTurn,
  turnComplete: true,
);

Unity

// Define initial turns (history/context).
List turns = new List {
    new ModelContent("user", new ModelContent.TextPart("What is the capital of France?") ),
    new ModelContent("model", new ModelContent.TextPart("Paris") ),
};

// Send history, keeping the conversational turn OPEN (false).
foreach (ModelContent turn in turns)
{
    await session.SendAsync(
        content: turn,
        turnComplete: false
    );
}

// Define the new user query.
ModelContent newTurn = ModelContent.Text("What is the capital of Germany?");

// Send the final query, CLOSING the turn (true) to trigger the model response.
await session.SendAsync(
    content: newTurn,
    turnComplete: true
);

อัปเดตคำสั่งของระบบระหว่างเซสชัน

ใช้ได้เฉพาะเมื่อใช้ Agent Platform Gemini API (formerly Vertex AI) เป็นผู้ให้บริการ API

คุณสามารถอัปเดตคำสั่งของระบบในระหว่างเซสชันที่ใช้งานอยู่ได้ ใช้ตัวเลือกนี้เพื่อปรับคำตอบของโมเดล เช่น เปลี่ยนภาษาของคำตอบหรือปรับเปลี่ยนโทน

หากต้องการอัปเดตคำสั่งของระบบระหว่างเซสชัน คุณสามารถส่งเนื้อหาข้อความที่มีบทบาท system ได้ คำสั่งของระบบที่อัปเดตจะมีผลตลอดช่วงเวลาที่เหลือของเซสชัน

Swift

await session.sendContent(
  [ModelContent(
    role: "system",
    parts: [TextPart("new system instruction")]
  )],
  turnComplete: false
)

Kotlin

// In a coroutine scope
session.send(
    content = content("system") {
        text("new system instruction")
    },
    turnComplete = false
)

Java

session.send(
    new Content.Builder()
        .setRole("system")
        .addText("new system instruction")
        .build(),
    /* turnComplete: */ false
);

Web

Not yet supported for Web apps - check back soon!

Dart

try {
  await _session.send(
    input: Content(
      'system',
      [TextPart('new system instruction')],
    ),
    turnComplete: false,
  );
} catch (e) {
  print('Failed to update system instructions: $e');
}

Unity

try
{
    await session.SendAsync(
        content: new ModelContent(
            "system",
            new ModelContent.TextPart("new system instruction")
        ),
        turnComplete: false
    );
}
catch (Exception e)
{
    Debug.LogError($"Failed to update system instructions: {e.Message}");
}

ส่งสัญญาณกิจกรรมของผู้ใช้ด้วยตนเอง

โดยค่าเริ่มต้น Live API จะตรวจจับจุดเริ่มต้นและจุดสิ้นสุดของคำพูดของผู้ใช้โดยอัตโนมัติโดยใช้การตรวจจับกิจกรรมเสียงพูด (VAD) ซึ่งช่วยให้คุณขัดจังหวะโมเดลได้ทุกเมื่อ (ดูวิธีจัดการการขัดจังหวะ)

อย่างไรก็ตาม คุณสามารถควบคุมการสนทนาด้วยตนเองได้อย่างสมบูรณ์ (เช่น สำหรับอินเทอร์เฟซแบบกดเพื่อพูด) โดยปิดใช้การตรวจจับกิจกรรมเสียงพูด (VAD) อัตโนมัติ

หากปิดใช้ VAD เซิร์ฟเวอร์จะไม่ตรวจจับคำพูดของผู้ใช้หรือทริกเกอร์การตอบกลับโดยอัตโนมัติเมื่อไม่มีเสียงพูด ในสถานการณ์นี้ คุณต้องกำหนดขอบเขตของกิจกรรมของผู้ใช้แต่ละรอบด้วยตนเอง

ดูวิธีปิดใช้การตรวจจับกิจกรรมเสียงพูด (VAD) อัตโนมัติและส่งสัญญาณกิจกรรมของผู้ใช้ด้วยตนเอง

บีบอัดหน้าต่างบริบท

คลิกผู้ให้บริการ Gemini API เพื่อดูเนื้อหาและโค้ดเฉพาะของผู้ให้บริการในหน้านี้

Live API หน้าต่างบริบทของเซสชันจะจัดเก็บข้อมูลที่สตรีมแบบเรียลไทม์ (25 โทเค็นต่อวินาที (TPS) สำหรับเสียงและ 258 TPS สำหรับวิดีโอ) รวมถึงเนื้อหาอื่นๆ เช่น อินพุตข้อความและเอาต์พุตโมเดล โมเดล Live API ทั้งหมดมีขีดจำกัดหน้าต่างบริบทของเซสชันอยู่ที่ 128,000 โทเค็น

โดยค่าเริ่มต้น เนื่องจากขีดจำกัดของหน้าต่างบริบทนี้ ระยะเวลาเซสชันสูงสุดโดยประมาณตามรูปแบบอินพุตมีดังนี้

  • เซสชันอินพุตแบบเสียงเท่านั้นจำกัดไว้ที่ 15 นาที
  • วิดีโอ + อินพุตเสียงจำกัดไว้ที่ 2 นาที

ในเซสชันที่ใช้เวลานาน เมื่อการสนทนาดำเนินไป ประวัติของโทเค็นเสียงและ/หรือวิดีโอจะสะสมมากขึ้น หากประวัตินี้เกินขีดจำกัดของโมเดล โมเดลอาจเกิดอาการหลอน ทำงานช้าลง หรือเซสชันอาจถูกบังคับให้สิ้นสุด

หากต้องการเปิดใช้เซสชันที่ยาวนานขึ้น คุณสามารถเปิดใช้การบีบอัดหน้าต่างบริบทโดยตั้งค่าช่อง contextWindowCompression เป็นส่วนหนึ่งของ LiveGenerationConfig เมื่อเปิดใช้ เซิร์ฟเวอร์จะใช้กลไก Sliding Window เพื่อทิ้งเทิร์นที่เก่าที่สุดโดยอัตโนมัติหรือสรุปเทิร์นเหล่านั้นเพื่อรักษาขนาดบริบทให้อยู่ภายในขีดจำกัดเริ่มต้นหรือขีดจำกัดที่ระบุ ระบบจะไม่ทิ้งคำสั่งของระบบและจะเก็บไว้ที่จุดเริ่มต้นของหน้าต่างบริบทเสมอ

จากมุมมองของผู้ใช้ วิธีนี้ช่วยให้ระยะเวลาเซสชันไม่มีที่สิ้นสุดในทางทฤษฎี เนื่องจาก "หน่วยความจำ" ได้รับการจัดการอย่างต่อเนื่อง

คุณสามารถกำหนดค่ากลไกกรอบเวลาแบบเลื่อนได้ รวมถึงจำนวนโทเค็นที่ทริกเกอร์การบีบอัดได้ด้วย (ดูการตั้งค่าและค่าที่ใช้ได้ด้านล่าง) ข้อควรพิจารณาระดับสูงเกี่ยวกับการใช้การตั้งค่าเหล่านี้มีดังนี้

  • การตั้งค่า targetTokens ให้ต่ำมากจะเพิ่มพื้นที่บริบทสำหรับสตรีมต่อเนื่อง แต่โมเดลจะ "ลืม" การสนทนาที่เก่ากว่าอย่างรวดเร็ว

  • การตั้งค่า targetTokens ให้ใกล้เคียงกับ triggerTokens จะช่วยประหยัดหน่วยความจำได้มากขึ้น แต่จะทริกเกอร์รูทีนการบีบอัดบ่อยขึ้นมาก

การตั้งค่า ค่าเริ่มต้นสำหรับกรอบเวลาแบบเลื่อนหากไม่ได้ตั้งค่าไว้ในการกำหนดค่า ค่าต่ำสุด ค่าสูงสุด
triggerTokens
ความยาวบริบทก่อนที่จะทริกเกอร์การบีบอัด
80% ของขีดจำกัดหน้าต่างบริบทของโมเดล 5,000 128,000
targetTokens
จำนวนโทเค็นเป้าหมายที่จะเก็บไว้
50% ของค่า triggerTokens
  • หากไม่ได้ตั้งค่า triggerTokens อย่างชัดเจน targetTokens จะมีค่าเริ่มต้นเป็น 50% ของค่า triggerTokens เริ่มต้น
  • ค่า targetTokens ต้องน้อยกว่าค่า triggerTokens
0 128,000

Swift


// ...

let liveModel = FirebaseAI.firebaseAI(backend: .googleAI()).liveModel(
  modelName: "GEMINI_LIVE_API_MODEL_NAME",
  // Enable context window compression.
  // (Optional) Configure the number of tokens in the context window that triggers the compression.
  generationConfig: LiveGenerationConfig(
    responseModalities: [.audio],
    contextWindowCompression: ContextWindowCompressionConfig(
      triggerTokens: 10000,
      slidingWindow: SlidingWindow(
        targetTokens: 2000,
      )
    )
  )
)

Kotlin


// ...

val liveModel = Firebase.ai(backend = GenerativeBackend.googleAI()).liveModel(
    modelName = "GEMINI_LIVE_API_MODEL_NAME",
    // Enable context window compression.
    // (Optional) Configure the number of tokens in the context window that triggers the compression.
    generationConfig = liveGenerationConfig {
        responseModality = ResponseModality.AUDIO,
        contextWindowCompression = ContextWindowCompressionConfig(
            triggerTokens = 10000,
            slidingWindow = SlidingWindow(targetTokens = 2000)
        )
    }
)

Java


// ...

LiveGenerativeModel lm = FirebaseAI.getInstance(GenerativeBackend.googleAI()).liveModel(
        "GEMINI_LIVE_API_MODEL_NAME",
        // Enable context window compression.
        // (Optional) Configure the number of tokens in the context window that triggers the compression.
        new LiveGenerationConfig.Builder()
                .setResponseModality(ResponseModality.AUDIO)
                .setContextWindowCompression(
                        new ContextWindowCompressionConfig(10000, new SlidingWindow(2000))
                )
                .build()
);

Web


// ...

const ai = getAI(firebaseApp, { backend: new GoogleAIBackend() });

const liveModel = getLiveGenerativeModel(ai, {
  model: "GEMINI_LIVE_API_MODEL_NAME",
  // Enable context window compression.
  // (Optional) Configure the number of tokens in the context window that triggers the compression.
  generationConfig: {
    responseModalities: [ResponseModality.AUDIO],
    contextWindowCompression: {
      triggerTokens: 10000,
      slidingWindow: {
        targetTokens: 2000,
      },
    },
  },
});

Dart


// ...

final _liveModel = FirebaseAI.googleAI().liveGenerativeModel(
  model: 'GEMINI_LIVE_API_MODEL_NAME',
  // Enable context window compression.
  // (Optional) Configure the number of tokens in the context window that triggers the compression.
  liveGenerationConfig: LiveGenerationConfig(
    responseModalities: [ResponseModalities.audio],
    contextWindowCompression: ContextWindowCompressionConfig(
      triggerTokens: 10000,
      slidingWindow: SlidingWindow(targetTokens: 2000),
    ),
  ),
);

Unity


// ...

var liveModel = FirebaseAI.GetInstance(FirebaseAI.Backend.GoogleAI()).GetLiveModel(
    modelName: "GEMINI_LIVE_API_MODEL_NAME",
    // Enable context window compression.
    // (Optional) Configure the number of tokens in the context window that triggers the compression.
    liveGenerationConfig: new LiveGenerationConfig(
        responseModalities: new[] { ResponseModality.Audio },
        contextWindowCompression: new ContextWindowCompressionConfig(
            triggerTokens: 10000,
            slidingWindow: new SlidingWindow(targetTokens: 2000)
        )
    )
);

ตรวจจับเมื่อเซสชันกำลังจะสิ้นสุด

ระยะเวลาสูงสุดของการเชื่อมต่อ WebSocket แบบต่อเนื่องครั้งเดียวคือประมาณ 10 นาที ระบบจะส่งการแจ้งเตือนการออกจากระบบไปยังไคลเอ็นต์ 60 วินาทีก่อนที่การเชื่อมต่อจะสิ้นสุดลง ซึ่งจะช่วยให้คุณดำเนินการเพิ่มเติมได้ (เช่น การกลับมาทำงานต่อในเซสชัน)

ตัวอย่างต่อไปนี้แสดงวิธีตรวจหาการสิ้นสุดการเชื่อมต่อที่ใกล้จะเกิดขึ้นโดยการฟังการแจ้งเตือนกำลังจะออก

Swift

for try await response in session.responses {
  switch response.payload {

  case .goingAwayNotice(let goingAwayNotice):
    // Prepare for the session to close soon
    if let timeLeft = goingAwayNotice.timeLeft {
        print("Server going away in \(timeLeft) seconds")
    }
  }
}

Kotlin

for (response in session.responses) {
    when (val message = response.payload) {
        is LiveServerGoAway -> {
            // Prepare for the session to close soon
            val remaining = message.timeLeft
            logger.info("Server going away in $remaining")
        }
    }
}

Java

session.getResponses().forEach(response -> {
    if (response.getPayload() instanceof LiveServerResponse.GoingAwayNotice) {
        LiveServerResponse.GoingAwayNotice notice = (LiveServerResponse.GoingAwayNotice) response.getPayload();
        // Prepare for the session to close soon
        Duration timeLeft = notice.getTimeLeft();
    }
});

Web

for await (const message of session.receive()) {
  switch (message.type) {

  ...
  case "goingAwayNotice":
    console.log("Server going away. Time left:", message.timeLeft);
    break;
  }
}

Dart

Future _handleLiveServerMessage(LiveServerResponse response) async {
  final message = response.message;
  if (message is GoingAwayNotice) {
     // Prepare for the session to close soon
     developer.log('Server going away. Time left: ${message.timeLeft}');
  }
}

Unity

foreach (var response in session.Responses) {
    if (response.Payload is LiveSessionGoingAway notice) {
        // Prepare for the session to close soon
        TimeSpan timeLeft = notice.TimeLeft;
        Debug.Log($"Server going away notice received. Remaining: {timeLeft}");
    }
}

กลับมาใช้เซสชันต่อ

Live API รองรับการกลับมาทำงานของเซสชันเพื่อป้องกันไม่ให้บริบทการสนทนาหายไป ทุกเซสชันจะมีแฮนเดิล และสามารถใช้ได้ในลักษณะต่อไปนี้

  • การคงเซสชันไว้ก่อนถึงขีดจำกัดเวลาการเชื่อมต่อ

    ระยะเวลาสูงสุดของการเชื่อมต่อ WebSocket แบบต่อเนื่องครั้งเดียวคือประมาณ 10 นาที คุณสามารถตรวจจับได้เมื่อการเชื่อมต่อกำลังจะสิ้นสุดลงโดยฟังการแจ้งเตือนการออกจากระบบ แล้วขยายเซสชันโดยสร้างการเชื่อมต่อใหม่โดยใช้แฮนเดิลเซสชัน

  • การกลับมาทำงานต่อในเซสชันทันทีหลังจากการเชื่อมต่อขาดหาย

    หากการเชื่อมต่อสิ้นสุดลงหรือหลุดก่อนถึงขีดจำกัดเวลาการเชื่อมต่อสูงสุด (เช่น การเปลี่ยนจาก Wi-Fi เป็น 5G) เซิร์ฟเวอร์จะเก็บสถานะเซสชันไว้ประมาณ 10 นาที ในระหว่างกรอบเวลานี้ คุณสามารถกลับมาทำเซสชันต่อได้โดยสร้างการเชื่อมต่อใหม่โดยใช้แฮนเดิลเซสชัน

  • การกลับมาใช้งานเซสชันอีกครั้งหลังจากผ่านไประยะเวลานาน

    หลังจากสิ้นสุดการเชื่อมต่อ เซิร์ฟเวอร์จะเก็บสถานะเซสชันไว้ 2-3 ชั่วโมง ในระหว่างช่วงเวลานี้ คุณสามารถกลับมาทำเซสชันต่อได้โดยสร้างการเชื่อมต่อใหม่โดยใช้แฮนเดิลเซสชัน โปรดทราบว่ากรอบเวลานี้จะแตกต่างกันสำหรับผู้ให้บริการ Gemini API 2 ราย โดย Gemini Developer API คือ 2 ชั่วโมง ส่วน Agent Platform Gemini API (formerly Vertex AI) คือ 24 ชั่วโมง

โดยค่าเริ่มต้น ระบบจะปิดใช้การกลับมาทำงานของเซสชัน หากต้องการเปิดใช้การกลับมาทำงานของเซสชัน ให้ส่งการกำหนดค่าการกลับมาทำงานที่ว่างเปล่าเมื่อสร้างการเชื่อมต่อใหม่ เมื่อเปิดใช้ เซิร์ฟเวอร์จะส่งการอัปเดตที่มีแฮนเดิลการกลับมาทำงานของเซสชันเป็นระยะๆ หากเซสชันถูกตัดการเชื่อมต่อ คุณสามารถเชื่อมต่อใหม่และส่งแฮนเดิลนี้เพื่อกลับมาทำเซสชันต่อโดยที่บริบทไม่เปลี่ยนแปลง

ตัวอย่างต่อไปนี้แสดง 2 ตัวเลือกในการกลับมาทำงานต่อในเซสชัน

Swift

// Local variable to save the active session handle
var activeSessionHandle: String?

// Initialize the session. Passing an empty config requests the server to send SessionResumptionUpdate
var session = try await liveModel.connect(
  sessionResumption: SessionResumptionConfig()
)

// Start receiving responses
for try await message in session.responses {
  // Check for new session handles inside your message handling loop
  switch message.payload {
  case let .sessionResumptionUpdate(updateMessage):
    guard let newHandle = updateMessage.newHandle, updateMessage.resumable else {
      continue
    }
    activeSessionHandle = newHandle
    print("SessionResumptionUpdate: handle \(newHandle)")
  // ... handle other LiveServerMessage types ...
  default:
    break
  }
}

// The following are alternative options to resume a session. Choose only one.

// Option 1: Create and connect a session to resume with the saved handle
if let handle = activeSessionHandle {
  session = try await liveModel.connect(
    sessionResumption: SessionResumptionConfig(handle: handle)
  )
}

// Option 2: Resume the session directly on an existing session object
if let handle = activeSessionHandle {
  try await session.resumeSession(
    sessionResumption: SessionResumptionConfig(handle: handle)
  )
}

Kotlin

// Local variable to save the active session handle
var activeSessionHandle: String? = null

// Initialize the session. Passing an empty config requests the server to send SessionResumptionUpdate
var session = liveModel.connect(
    sessionResumption = SessionResumptionConfig()
)

// Start receiving responses
session.receive().collect { message ->
    // Process other received response types...

    // Check for new session handles inside your message handling loop
    if (message is LiveSessionResumptionUpdate) {
        if (message.resumable == true && message.newHandle != null) {
            activeSessionHandle = message.newHandle
            Log.d("TAG", "SessionResumptionUpdate: handle ${message.newHandle}")
        }
    }
}

// The following are alternative options to resume a session. Choose only one.

// Option 1: Create and connect a session to resume with the saved handle
activeSessionHandle?.let { handle ->
    session = liveModel.connect(
        sessionResumption = SessionResumptionConfig(handle = handle)
    )
}

// Option 2: Resume the session directly on an existing session object
activeSessionHandle?.let { handle ->
    session.resumeSession(
        sessionResumption = SessionResumptionConfig(handle = handle)
    )
}

Java

For Java, session resumption is not yet supported. Check back soon!

Web

// Local variable to save the active session handle
let activeSessionHandle = null;

// Initialize the session. Passing an empty object requests the server to send SessionResumptionUpdate
let session = await liveModel.connect({});

// Start receiving responses
for await (const message of session.receive()) {
  // Process other received response types...

  // Check for new session handles inside your message handling loop
  if (message.type === 'sessionResumptionUpdate') {
    if (message.resumable && message.newHandle) {
      activeSessionHandle = message.newHandle;
      console.log(`SessionResumptionUpdate: handle ${activeSessionHandle}`);
    }
  }
}

// The following are alternative options to resume a session. Choose only one.

// Option 1: Create and connect a session to resume with the saved handle
if (activeSessionHandle) {
  session = await liveModel.connect({
    handle: activeSessionHandle
  });
}

// Option 2: Resume the session directly on an existing session object
if (activeSessionHandle) {
  await session.resumeSession({
    handle: activeSessionHandle
  });
}

Dart

// Local variable to save the active session handle
String? _activeSessionHandle;

// Initialize the session. Passing an empty config requests the server to send SessionResumptionUpdate
var _session = await _liveModel.connect(
  sessionResumption: SessionResumptionConfig(),
);

// Start receiving responses
await for (final response in _session.receive()) {
  // Process other received response types...

  // Check for new session handles inside your message handling loop
  final message = response.message;
  if (message is SessionResumptionUpdate &&
      message.resumable != null &&
      message.resumable!) {
    _activeSessionHandle = message.newHandle;
    log('SessionResumptionUpdate: handle ${message.newHandle}');
  }
}

// The following are alternative options to resume a session. Choose only one.

// Option 1: Create and connect a session to resume with the saved handle
if (_activeSessionHandle != null) {
  _session = await _liveModel.connect(
    sessionResumption: SessionResumptionConfig.resume(_activeSessionHandle!),
  );
}

// Option 2: Alternatively, resume the session directly on an existing session object
if (_activeSessionHandle != null) {
  await _session.resumeSession(
    sessionResumption: SessionResumptionConfig.resume(_activeSessionHandle!),
  );
}

Unity

// Local variable to save the active session handle
string activeSessionHandle = null;

// Initialize the session. Passing an empty config requests the server to send SessionResumptionUpdate
var session = await liveModel.ConnectAsync(
    sessionResumption: new SessionResumptionConfig()
);

// Start receiving responses
await foreach (var response in session.ReceiveAsync())
{
  // Process other received response types...

  // Check for new session handles inside your message handling loop
  if (response.Message is LiveSessionResumptionUpdate updateMessage)
  {
    if (updateMessage.Resumable == true && !string.IsNullOrEmpty(updateMessage.NewHandle))
    {
      activeSessionHandle = updateMessage.NewHandle;
      Debug.Log($"SessionResumptionUpdate: handle {activeSessionHandle}");
    }
  }
}

// The following are alternative options to resume a session. Choose only one.

// Option 1: Create and connect a session to resume with the saved handle
if (!string.IsNullOrEmpty(activeSessionHandle)) {
  session = await liveModel.ConnectAsync(
      sessionResumption: new SessionResumptionConfig(activeSessionHandle)
  );
}

// Option 2: Resume the session directly on an existing session object
if (!string.IsNullOrEmpty(activeSessionHandle)) {
  await session.ResumeSessionAsync(
      sessionResumption: new SessionResumptionConfig(activeSessionHandle)
  );
}