@aituber-onair/chat 0.55.0 → 0.56.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/README.ja.md +28 -8
  2. package/README.md +30 -9
  3. package/dist/cjs/constants/claude.d.ts +1 -0
  4. package/dist/cjs/constants/claude.d.ts.map +1 -1
  5. package/dist/cjs/constants/claude.js +3 -1
  6. package/dist/cjs/constants/claude.js.map +1 -1
  7. package/dist/cjs/constants/openai.d.ts +5 -3
  8. package/dist/cjs/constants/openai.d.ts.map +1 -1
  9. package/dist/cjs/constants/openai.js +24 -7
  10. package/dist/cjs/constants/openai.js.map +1 -1
  11. package/dist/cjs/constants/xai.d.ts +1 -0
  12. package/dist/cjs/constants/xai.d.ts.map +1 -1
  13. package/dist/cjs/constants/xai.js +7 -2
  14. package/dist/cjs/constants/xai.js.map +1 -1
  15. package/dist/cjs/services/ChatService.d.ts +2 -0
  16. package/dist/cjs/services/ChatService.d.ts.map +1 -1
  17. package/dist/cjs/services/ChatServiceFactory.d.ts.map +1 -1
  18. package/dist/cjs/services/ChatServiceFactory.js +20 -15
  19. package/dist/cjs/services/ChatServiceFactory.js.map +1 -1
  20. package/dist/cjs/services/providers/ChatServiceProvider.d.ts +2 -0
  21. package/dist/cjs/services/providers/ChatServiceProvider.d.ts.map +1 -1
  22. package/dist/cjs/services/providers/claude/ClaudeChatServiceProvider.d.ts.map +1 -1
  23. package/dist/cjs/services/providers/claude/ClaudeChatServiceProvider.js +1 -0
  24. package/dist/cjs/services/providers/claude/ClaudeChatServiceProvider.js.map +1 -1
  25. package/dist/cjs/services/providers/geminiNano/GeminiNanoChatService.d.ts +24 -3
  26. package/dist/cjs/services/providers/geminiNano/GeminiNanoChatService.d.ts.map +1 -1
  27. package/dist/cjs/services/providers/geminiNano/GeminiNanoChatService.js +211 -15
  28. package/dist/cjs/services/providers/geminiNano/GeminiNanoChatService.js.map +1 -1
  29. package/dist/cjs/services/providers/geminiNano/GeminiNanoChatServiceProvider.d.ts.map +1 -1
  30. package/dist/cjs/services/providers/geminiNano/GeminiNanoChatServiceProvider.js +1 -0
  31. package/dist/cjs/services/providers/geminiNano/GeminiNanoChatServiceProvider.js.map +1 -1
  32. package/dist/cjs/services/providers/openai/OpenAIChatService.js +1 -1
  33. package/dist/cjs/services/providers/openai/OpenAIChatService.js.map +1 -1
  34. package/dist/cjs/services/providers/openai/OpenAIChatServiceProvider.d.ts.map +1 -1
  35. package/dist/cjs/services/providers/openai/OpenAIChatServiceProvider.js +10 -0
  36. package/dist/cjs/services/providers/openai/OpenAIChatServiceProvider.js.map +1 -1
  37. package/dist/cjs/services/providers/xai/XAIChatServiceProvider.d.ts.map +1 -1
  38. package/dist/cjs/services/providers/xai/XAIChatServiceProvider.js +1 -0
  39. package/dist/cjs/services/providers/xai/XAIChatServiceProvider.js.map +1 -1
  40. package/dist/esm/constants/claude.d.ts +1 -0
  41. package/dist/esm/constants/claude.d.ts.map +1 -1
  42. package/dist/esm/constants/claude.js +2 -0
  43. package/dist/esm/constants/claude.js.map +1 -1
  44. package/dist/esm/constants/openai.d.ts +5 -3
  45. package/dist/esm/constants/openai.d.ts.map +1 -1
  46. package/dist/esm/constants/openai.js +23 -6
  47. package/dist/esm/constants/openai.js.map +1 -1
  48. package/dist/esm/constants/xai.d.ts +1 -0
  49. package/dist/esm/constants/xai.d.ts.map +1 -1
  50. package/dist/esm/constants/xai.js +6 -1
  51. package/dist/esm/constants/xai.js.map +1 -1
  52. package/dist/esm/services/ChatService.d.ts +2 -0
  53. package/dist/esm/services/ChatService.d.ts.map +1 -1
  54. package/dist/esm/services/ChatServiceFactory.d.ts.map +1 -1
  55. package/dist/esm/services/ChatServiceFactory.js +21 -16
  56. package/dist/esm/services/ChatServiceFactory.js.map +1 -1
  57. package/dist/esm/services/providers/ChatServiceProvider.d.ts +2 -0
  58. package/dist/esm/services/providers/ChatServiceProvider.d.ts.map +1 -1
  59. package/dist/esm/services/providers/claude/ClaudeChatServiceProvider.d.ts.map +1 -1
  60. package/dist/esm/services/providers/claude/ClaudeChatServiceProvider.js +2 -1
  61. package/dist/esm/services/providers/claude/ClaudeChatServiceProvider.js.map +1 -1
  62. package/dist/esm/services/providers/geminiNano/GeminiNanoChatService.d.ts +24 -3
  63. package/dist/esm/services/providers/geminiNano/GeminiNanoChatService.d.ts.map +1 -1
  64. package/dist/esm/services/providers/geminiNano/GeminiNanoChatService.js +211 -15
  65. package/dist/esm/services/providers/geminiNano/GeminiNanoChatService.js.map +1 -1
  66. package/dist/esm/services/providers/geminiNano/GeminiNanoChatServiceProvider.d.ts.map +1 -1
  67. package/dist/esm/services/providers/geminiNano/GeminiNanoChatServiceProvider.js +1 -0
  68. package/dist/esm/services/providers/geminiNano/GeminiNanoChatServiceProvider.js.map +1 -1
  69. package/dist/esm/services/providers/openai/OpenAIChatService.js +1 -1
  70. package/dist/esm/services/providers/openai/OpenAIChatService.js.map +1 -1
  71. package/dist/esm/services/providers/openai/OpenAIChatServiceProvider.d.ts.map +1 -1
  72. package/dist/esm/services/providers/openai/OpenAIChatServiceProvider.js +11 -1
  73. package/dist/esm/services/providers/openai/OpenAIChatServiceProvider.js.map +1 -1
  74. package/dist/esm/services/providers/xai/XAIChatServiceProvider.d.ts.map +1 -1
  75. package/dist/esm/services/providers/xai/XAIChatServiceProvider.js +2 -1
  76. package/dist/esm/services/providers/xai/XAIChatServiceProvider.js.map +1 -1
  77. package/dist/umd/aituber-onair-chat.js +309 -25
  78. package/dist/umd/aituber-onair-chat.min.js +8 -8
  79. package/package.json +1 -1
@@ -99,6 +99,7 @@ var AITuberOnAirChat = (() => {
99
99
  MODEL_CLAUDE_4_OPUS: () => MODEL_CLAUDE_4_OPUS,
100
100
  MODEL_CLAUDE_4_SONNET: () => MODEL_CLAUDE_4_SONNET,
101
101
  MODEL_CLAUDE_5_1_FABLE: () => MODEL_CLAUDE_5_1_FABLE,
102
+ MODEL_CLAUDE_5_5_OPUS: () => MODEL_CLAUDE_5_5_OPUS,
102
103
  MODEL_CLAUDE_5_FABLE: () => MODEL_CLAUDE_5_FABLE,
103
104
  MODEL_CLAUDE_5_OPUS: () => MODEL_CLAUDE_5_OPUS,
104
105
  MODEL_CLAUDE_5_SONNET: () => MODEL_CLAUDE_5_SONNET,
@@ -171,6 +172,8 @@ var AITuberOnAirChat = (() => {
171
172
  MODEL_GPT_5_MINI: () => MODEL_GPT_5_MINI,
172
173
  MODEL_GPT_5_NANO: () => MODEL_GPT_5_NANO,
173
174
  MODEL_GPT_6_ASTRA: () => MODEL_GPT_6_ASTRA,
175
+ MODEL_GPT_6_LUNA: () => MODEL_GPT_6_LUNA,
176
+ MODEL_GPT_6_SOL: () => MODEL_GPT_6_SOL,
174
177
  MODEL_GPT_OSS_20B_FREE: () => MODEL_GPT_OSS_20B_FREE,
175
178
  MODEL_GROK_4_1_FAST_NON_REASONING: () => MODEL_GROK_4_1_FAST_NON_REASONING,
176
179
  MODEL_GROK_4_1_FAST_REASONING: () => MODEL_GROK_4_1_FAST_REASONING,
@@ -179,6 +182,7 @@ var AITuberOnAirChat = (() => {
179
182
  MODEL_GROK_4_3: () => MODEL_GROK_4_3,
180
183
  MODEL_GROK_4_5: () => MODEL_GROK_4_5,
181
184
  MODEL_GROK_4_6: () => MODEL_GROK_4_6,
185
+ MODEL_GROK_4_7: () => MODEL_GROK_4_7,
182
186
  MODEL_INCEPTION_MERCURY_2_5: () => MODEL_INCEPTION_MERCURY_2_5,
183
187
  MODEL_INCLUSIONAI_LING_3_0_FLASH_VL_FREE: () => MODEL_INCLUSIONAI_LING_3_0_FLASH_VL_FREE,
184
188
  MODEL_KIMI_K2_5: () => MODEL_KIMI_K2_5,
@@ -353,6 +357,8 @@ var AITuberOnAirChat = (() => {
353
357
  var ENDPOINT_OPENAI_CHAT_COMPLETIONS_API = "https://api.openai.com/v1/chat/completions";
354
358
  var ENDPOINT_OPENAI_RESPONSES_API = "https://api.openai.com/v1/responses";
355
359
  var MODEL_GPT_6_ASTRA = "gpt-6-astra";
360
+ var MODEL_GPT_6_SOL = "gpt-6-sol";
361
+ var MODEL_GPT_6_LUNA = "gpt-6-luna";
356
362
  var MODEL_GPT_5_NANO = "gpt-5-nano";
357
363
  var MODEL_GPT_5_MINI = "gpt-5-mini";
358
364
  var MODEL_GPT_5 = "gpt-5";
@@ -376,6 +382,8 @@ var AITuberOnAirChat = (() => {
376
382
  var MODEL_O1 = "o1";
377
383
  var VISION_SUPPORTED_MODELS = [
378
384
  MODEL_GPT_6_ASTRA,
385
+ MODEL_GPT_6_SOL,
386
+ MODEL_GPT_6_LUNA,
379
387
  MODEL_GPT_5_NANO,
380
388
  MODEL_GPT_5_MINI,
381
389
  MODEL_GPT_5,
@@ -416,19 +424,19 @@ var AITuberOnAirChat = (() => {
416
424
  return GPT_5_MODELS.includes(model);
417
425
  }
418
426
  function isOpenAIReasoningModel(model) {
419
- return model === MODEL_GPT_6_ASTRA || isGPT5Model(model);
427
+ return model === MODEL_GPT_6_ASTRA || model === MODEL_GPT_6_SOL || model === MODEL_GPT_6_LUNA || isGPT5Model(model);
420
428
  }
421
429
  function isResponsesOnlyGPT5Model(model) {
422
430
  return model === MODEL_GPT_5_4_PRO;
423
431
  }
424
432
  function allowsReasoningXHigh(model) {
425
- return model === MODEL_GPT_6_ASTRA || model === MODEL_GPT_5_6 || model === MODEL_GPT_5_6_SOL || model === MODEL_GPT_5_6_TERRA || model === MODEL_GPT_5_6_LUNA || model === MODEL_GPT_5_5 || model === MODEL_GPT_5_4 || model === MODEL_GPT_5_4_MINI || model === MODEL_GPT_5_4_NANO || model === MODEL_GPT_5_4_PRO;
433
+ return model === MODEL_GPT_6_ASTRA || model === MODEL_GPT_6_SOL || model === MODEL_GPT_6_LUNA || model === MODEL_GPT_5_6 || model === MODEL_GPT_5_6_SOL || model === MODEL_GPT_5_6_TERRA || model === MODEL_GPT_5_6_LUNA || model === MODEL_GPT_5_5 || model === MODEL_GPT_5_4 || model === MODEL_GPT_5_4_MINI || model === MODEL_GPT_5_4_NANO || model === MODEL_GPT_5_4_PRO;
426
434
  }
427
435
  function allowsReasoningMax(model) {
428
- return model === MODEL_GPT_6_ASTRA || model === MODEL_GPT_5_6 || model === MODEL_GPT_5_6_SOL || model === MODEL_GPT_5_6_TERRA || model === MODEL_GPT_5_6_LUNA;
436
+ return model === MODEL_GPT_6_ASTRA || model === MODEL_GPT_6_SOL || model === MODEL_GPT_6_LUNA || model === MODEL_GPT_5_6 || model === MODEL_GPT_5_6_SOL || model === MODEL_GPT_5_6_TERRA || model === MODEL_GPT_5_6_LUNA;
429
437
  }
430
438
  function allowsReasoningNone(model) {
431
- return model === MODEL_GPT_5_6 || model === MODEL_GPT_5_6_SOL || model === MODEL_GPT_5_6_TERRA || model === MODEL_GPT_5_6_LUNA || model === MODEL_GPT_5_1 || model === MODEL_GPT_5_4 || model === MODEL_GPT_5_5 || model === MODEL_GPT_5_4_MINI || model === MODEL_GPT_5_4_NANO;
439
+ return model === MODEL_GPT_6_SOL || model === MODEL_GPT_6_LUNA || model === MODEL_GPT_5_6 || model === MODEL_GPT_5_6_SOL || model === MODEL_GPT_5_6_TERRA || model === MODEL_GPT_5_6_LUNA || model === MODEL_GPT_5_1 || model === MODEL_GPT_5_4 || model === MODEL_GPT_5_5 || model === MODEL_GPT_5_4_MINI || model === MODEL_GPT_5_4_NANO;
432
440
  }
433
441
  function allowsReasoningMinimal(model) {
434
442
  return model === MODEL_GPT_5_NANO || model === MODEL_GPT_5_MINI || model === MODEL_GPT_5;
@@ -446,7 +454,7 @@ var AITuberOnAirChat = (() => {
446
454
  return "medium";
447
455
  }
448
456
  function getDefaultReasoningEffortForOpenAIModel(model) {
449
- return model === MODEL_GPT_6_ASTRA ? "low" : getDefaultReasoningEffortForGPT5Model(model);
457
+ return model === MODEL_GPT_6_ASTRA ? "low" : model === MODEL_GPT_6_SOL ? "medium" : model === MODEL_GPT_6_LUNA ? "low" : getDefaultReasoningEffortForGPT5Model(model);
450
458
  }
451
459
 
452
460
  // src/constants/gemini.ts
@@ -561,6 +569,7 @@ var AITuberOnAirChat = (() => {
561
569
  var MODEL_CLAUDE_5_FABLE = "claude-fable-5";
562
570
  var MODEL_CLAUDE_5_SONNET = "claude-sonnet-5";
563
571
  var MODEL_CLAUDE_5_OPUS = "claude-opus-5";
572
+ var MODEL_CLAUDE_5_5_OPUS = "claude-opus-5-5";
564
573
  var CLAUDE_DEPRECATED_MODELS = [
565
574
  MODEL_CLAUDE_3_HAIKU,
566
575
  MODEL_CLAUDE_3_5_HAIKU,
@@ -605,7 +614,8 @@ var AITuberOnAirChat = (() => {
605
614
  MODEL_CLAUDE_4_8_OPUS,
606
615
  MODEL_CLAUDE_5_FABLE,
607
616
  MODEL_CLAUDE_5_SONNET,
608
- MODEL_CLAUDE_5_OPUS
617
+ MODEL_CLAUDE_5_OPUS,
618
+ MODEL_CLAUDE_5_5_OPUS
609
619
  ];
610
620
  function getClaudeSupportedReasoningEfforts(model) {
611
621
  return CLAUDE_REASONING_EFFORTS_BY_MODEL[model] ?? [];
@@ -1054,6 +1064,7 @@ var AITuberOnAirChat = (() => {
1054
1064
  // src/constants/xai.ts
1055
1065
  var ENDPOINT_XAI_CHAT_COMPLETIONS_API = "https://api.x.ai/v1/chat/completions";
1056
1066
  var MODEL_GROK_4_6 = "grok-4.6";
1067
+ var MODEL_GROK_4_7 = "grok-4.7";
1057
1068
  var MODEL_GROK_4_5 = "grok-4.5";
1058
1069
  var MODEL_GROK_4_3 = "grok-4.3";
1059
1070
  var MODEL_GROK_4_20_REASONING = "grok-4.20-0309-reasoning";
@@ -1066,6 +1077,7 @@ var AITuberOnAirChat = (() => {
1066
1077
  ];
1067
1078
  var XAI_VISION_SUPPORTED_MODELS = [
1068
1079
  MODEL_GROK_4_6,
1080
+ MODEL_GROK_4_7,
1069
1081
  MODEL_GROK_4_5,
1070
1082
  MODEL_GROK_4_3,
1071
1083
  MODEL_GROK_4_20_REASONING,
@@ -1078,7 +1090,7 @@ var AITuberOnAirChat = (() => {
1078
1090
  return getXaiSupportedReasoningEfforts(model).length > 0;
1079
1091
  }
1080
1092
  function getXaiSupportedReasoningEfforts(model) {
1081
- if (model === MODEL_GROK_4_6) {
1093
+ if (model === MODEL_GROK_4_6 || model === MODEL_GROK_4_7) {
1082
1094
  return ["low", "medium", "high", "xhigh"];
1083
1095
  }
1084
1096
  if (model === MODEL_GROK_4_5) {
@@ -1093,6 +1105,9 @@ var AITuberOnAirChat = (() => {
1093
1105
  return getXaiSupportedReasoningEfforts(model).includes("none");
1094
1106
  }
1095
1107
  function getDefaultXaiReasoningEffort(model) {
1108
+ if (model === MODEL_GROK_4_7) {
1109
+ return "low";
1110
+ }
1096
1111
  if (model === MODEL_GROK_4_6 || model === MODEL_GROK_4_5) {
1097
1112
  return "low";
1098
1113
  }
@@ -2628,7 +2643,8 @@ If it's in another language, summarize in that language.
2628
2643
  MODEL_CLAUDE_5_1_FABLE,
2629
2644
  MODEL_CLAUDE_5_FABLE,
2630
2645
  MODEL_CLAUDE_5_SONNET,
2631
- MODEL_CLAUDE_5_OPUS
2646
+ MODEL_CLAUDE_5_OPUS,
2647
+ MODEL_CLAUDE_5_5_OPUS
2632
2648
  ];
2633
2649
  }
2634
2650
  /**
@@ -4335,6 +4351,7 @@ If it's in another language, summarize in that language.
4335
4351
  var GeminiNanoChatService = class {
4336
4352
  constructor(options = {}) {
4337
4353
  this.provider = "gemini-nano";
4354
+ this.consumedTranscript = [];
4338
4355
  this.expectedInputLanguages = options.expectedInputLanguages ?? [
4339
4356
  "ja",
4340
4357
  "en"
@@ -4344,6 +4361,7 @@ If it's in another language, summarize in that language.
4344
4361
  ...prompt
4345
4362
  }));
4346
4363
  this._responseLength = options.responseLength;
4364
+ this.sessionMode = options.sessionMode ?? "stateless";
4347
4365
  }
4348
4366
  getModel() {
4349
4367
  return MODEL_GEMINI_NANO;
@@ -4351,23 +4369,33 @@ If it's in another language, summarize in that language.
4351
4369
  getVisionModel() {
4352
4370
  return MODEL_GEMINI_NANO;
4353
4371
  }
4372
+ /** Destroy any persistent Prompt API sessions held by this service. */
4373
+ dispose() {
4374
+ this.destroyPersistentSessions();
4375
+ }
4354
4376
  /**
4355
4377
  * Process chat messages using Gemini Nano.
4356
- * Non-streaming: calls onPartialResponse once with the full response,
4357
- * then calls onCompleteResponse.
4378
+ * Streams response deltas when Chrome exposes promptStreaming(), then calls
4379
+ * onCompleteResponse with the complete response.
4358
4380
  */
4359
4381
  async processChat(messages, onPartialResponse, onCompleteResponse) {
4360
- const response = await this.generateResponse(messages);
4361
- onPartialResponse(response);
4382
+ const response = await this.generateResponse(
4383
+ messages,
4384
+ true,
4385
+ onPartialResponse
4386
+ );
4362
4387
  await onCompleteResponse(response);
4363
4388
  }
4364
4389
  async processVisionChat(_messages, _onPartialResponse, _onCompleteResponse) {
4365
4390
  throw new Error("Gemini Nano does not support vision capabilities.");
4366
4391
  }
4367
- async chatOnce(messages, _stream = false, onPartialResponse = () => {
4392
+ async chatOnce(messages, stream = false, onPartialResponse = () => {
4368
4393
  }, _maxTokens) {
4369
- const response = await this.generateResponse(messages);
4370
- onPartialResponse(response);
4394
+ const response = await this.generateResponse(
4395
+ messages,
4396
+ stream,
4397
+ onPartialResponse
4398
+ );
4371
4399
  return {
4372
4400
  blocks: [{ type: "text", text: response }],
4373
4401
  stop_reason: "end"
@@ -4380,7 +4408,7 @@ If it's in another language, summarize in that language.
4380
4408
  /**
4381
4409
  * Core logic: extract system prompt, manage session, call prompt().
4382
4410
  */
4383
- async generateResponse(messages) {
4411
+ async generateResponse(messages, stream, onPartialResponse) {
4384
4412
  const api = getLanguageModelAPI();
4385
4413
  if (!api) {
4386
4414
  throw new Error(
@@ -4388,11 +4416,8 @@ If it's in another language, summarize in that language.
4388
4416
  );
4389
4417
  }
4390
4418
  const modelOptions = this.getModelOptions();
4391
- const availability = await api.availability(modelOptions);
4392
- if (availability !== "available" && availability !== "downloadable") {
4393
- throw new Error(
4394
- `Gemini Nano Prompt API is not ready in this environment. LanguageModel.availability() returned "${availability}". Expected "available" or "downloadable".`
4395
- );
4419
+ if (this.sessionMode === "stateless") {
4420
+ await this.ensureAvailability(api, modelOptions);
4396
4421
  }
4397
4422
  const systemMessages = messages.filter((m) => m.role === "system");
4398
4423
  const systemPrompt = systemMessages.map((m) => m.content).join("\n");
@@ -4402,14 +4427,31 @@ If it's in another language, summarize in that language.
4402
4427
  throw new Error("No user message found in the provided messages.");
4403
4428
  }
4404
4429
  const lastUserMessage = conversationMessages[lastUserMessageIndex];
4430
+ const contextHistory = conversationMessages.slice(0, lastUserMessageIndex);
4431
+ if (this.sessionMode === "persistent") {
4432
+ return this.generatePersistentResponse(
4433
+ api,
4434
+ systemPrompt,
4435
+ contextHistory,
4436
+ lastUserMessage.content,
4437
+ modelOptions,
4438
+ stream,
4439
+ onPartialResponse
4440
+ );
4441
+ }
4405
4442
  const session = await this.createSession(
4406
4443
  api,
4407
4444
  systemPrompt,
4408
- conversationMessages.slice(0, lastUserMessageIndex),
4445
+ contextHistory,
4409
4446
  modelOptions
4410
4447
  );
4411
4448
  try {
4412
- return await session.prompt(lastUserMessage.content);
4449
+ return await this.promptSession(
4450
+ session,
4451
+ lastUserMessage.content,
4452
+ stream,
4453
+ onPartialResponse
4454
+ );
4413
4455
  } finally {
4414
4456
  try {
4415
4457
  session.destroy();
@@ -4417,6 +4459,241 @@ If it's in another language, summarize in that language.
4417
4459
  }
4418
4460
  }
4419
4461
  }
4462
+ async generatePersistentResponse(api, systemPrompt, contextHistory, userPrompt, modelOptions, stream, onPartialResponse) {
4463
+ const sessionKey = this.getPersistentSessionKey(systemPrompt, modelOptions);
4464
+ if (this.persistentSessionKey !== sessionKey) {
4465
+ this.destroyPersistentSessions();
4466
+ }
4467
+ if (!this.baseSession && !this.liveSession) {
4468
+ await this.ensureAvailability(api, modelOptions);
4469
+ await this.createPersistentBaseSession(
4470
+ api,
4471
+ systemPrompt,
4472
+ contextHistory,
4473
+ modelOptions
4474
+ );
4475
+ this.persistentSessionKey = sessionKey;
4476
+ }
4477
+ let session = await this.getPersistentLiveSession(
4478
+ api,
4479
+ systemPrompt,
4480
+ contextHistory,
4481
+ modelOptions
4482
+ );
4483
+ const reusedLiveSession = session === this.liveSession && this.isHistoryCompatible(contextHistory, this.consumedTranscript);
4484
+ this.persistentSessionKey = sessionKey;
4485
+ try {
4486
+ const response = await this.promptSession(
4487
+ session,
4488
+ userPrompt,
4489
+ stream,
4490
+ onPartialResponse
4491
+ );
4492
+ this.recordConsumedTranscript(
4493
+ contextHistory,
4494
+ userPrompt,
4495
+ response,
4496
+ reusedLiveSession
4497
+ );
4498
+ return response;
4499
+ } catch (error) {
4500
+ if (!this.isQuotaExceededError(error)) {
4501
+ this.destroyPersistentLiveSession();
4502
+ throw error;
4503
+ }
4504
+ this.destroyPersistentLiveSession();
4505
+ session = await this.getPersistentLiveSession(
4506
+ api,
4507
+ systemPrompt,
4508
+ [],
4509
+ modelOptions
4510
+ );
4511
+ this.persistentSessionKey = sessionKey;
4512
+ try {
4513
+ const response = await this.promptSession(
4514
+ session,
4515
+ userPrompt,
4516
+ stream,
4517
+ onPartialResponse
4518
+ );
4519
+ this.recordConsumedTranscript([], userPrompt, response, false);
4520
+ return response;
4521
+ } catch (retryError) {
4522
+ this.destroyPersistentLiveSession();
4523
+ throw retryError;
4524
+ }
4525
+ }
4526
+ }
4527
+ async ensureAvailability(api, modelOptions) {
4528
+ const availability = await api.availability(modelOptions);
4529
+ if (availability !== "available" && availability !== "downloadable") {
4530
+ throw new Error(
4531
+ `Gemini Nano Prompt API is not ready in this environment. LanguageModel.availability() returned "${availability}". Expected "available" or "downloadable".`
4532
+ );
4533
+ }
4534
+ }
4535
+ async createPersistentBaseSession(api, systemPrompt, contextHistory, modelOptions) {
4536
+ this.baseSession = await this.createSession(
4537
+ api,
4538
+ systemPrompt,
4539
+ [],
4540
+ modelOptions
4541
+ );
4542
+ if (contextHistory.length > 0) {
4543
+ this.liveSession = await this.createSession(
4544
+ api,
4545
+ systemPrompt,
4546
+ contextHistory,
4547
+ modelOptions
4548
+ );
4549
+ this.consumedTranscript = contextHistory.map((message) => ({
4550
+ ...message
4551
+ }));
4552
+ } else if (typeof this.baseSession.clone === "function") {
4553
+ this.liveSession = await this.baseSession.clone();
4554
+ } else {
4555
+ this.liveSession = this.baseSession;
4556
+ }
4557
+ }
4558
+ async getPersistentLiveSession(api, systemPrompt, contextHistory, modelOptions) {
4559
+ if (this.liveSession && this.isHistoryCompatible(contextHistory, this.consumedTranscript)) {
4560
+ return this.liveSession;
4561
+ }
4562
+ if (this.liveSession && this.liveSession !== this.baseSession) {
4563
+ this.destroyPersistentLiveSession();
4564
+ }
4565
+ if (contextHistory.length === 0 && this.baseSession) {
4566
+ if (typeof this.baseSession.clone === "function") {
4567
+ this.liveSession = await this.baseSession.clone();
4568
+ } else {
4569
+ if (this.consumedTranscript.length > 0) {
4570
+ this.destroyPersistentSessions();
4571
+ await this.createPersistentBaseSession(
4572
+ api,
4573
+ systemPrompt,
4574
+ [],
4575
+ modelOptions
4576
+ );
4577
+ return this.liveSession;
4578
+ }
4579
+ this.liveSession = this.baseSession;
4580
+ }
4581
+ return this.liveSession;
4582
+ }
4583
+ if (this.baseSession && typeof this.baseSession.clone === "function") {
4584
+ this.liveSession = await this.createSession(
4585
+ api,
4586
+ systemPrompt,
4587
+ contextHistory,
4588
+ modelOptions
4589
+ );
4590
+ return this.liveSession;
4591
+ }
4592
+ this.destroyPersistentSessions();
4593
+ await this.ensureAvailability(api, modelOptions);
4594
+ await this.createPersistentBaseSessionWithHistory(
4595
+ api,
4596
+ systemPrompt,
4597
+ contextHistory,
4598
+ modelOptions
4599
+ );
4600
+ return this.liveSession;
4601
+ }
4602
+ async createPersistentBaseSessionWithHistory(api, systemPrompt, contextHistory, modelOptions) {
4603
+ this.baseSession = await this.createSession(
4604
+ api,
4605
+ systemPrompt,
4606
+ contextHistory,
4607
+ modelOptions
4608
+ );
4609
+ this.liveSession = this.baseSession;
4610
+ this.consumedTranscript = contextHistory.map((message) => ({
4611
+ ...message
4612
+ }));
4613
+ }
4614
+ recordConsumedTranscript(contextHistory, userPrompt, response, reusedLiveSession) {
4615
+ const priorTranscript = reusedLiveSession ? this.consumedTranscript : contextHistory;
4616
+ this.consumedTranscript = [
4617
+ ...priorTranscript,
4618
+ { role: "user", content: userPrompt },
4619
+ { role: "assistant", content: response }
4620
+ ];
4621
+ }
4622
+ getPersistentSessionKey(systemPrompt, modelOptions) {
4623
+ return JSON.stringify({
4624
+ systemPrompt,
4625
+ modelOptions,
4626
+ initialPrompts: this.initialPrompts,
4627
+ responseLength: this._responseLength
4628
+ });
4629
+ }
4630
+ isHistoryCompatible(left, right) {
4631
+ if (left.length === 0 || right.length === 0) {
4632
+ return left.length === 0 && right.length === 0;
4633
+ }
4634
+ return this.isSuffix(left, right) || this.isSuffix(right, left);
4635
+ }
4636
+ isSuffix(candidate, full) {
4637
+ if (candidate.length > full.length) return false;
4638
+ const offset = full.length - candidate.length;
4639
+ return candidate.every(
4640
+ (message, index) => message.role === full[offset + index].role && message.content === full[offset + index].content
4641
+ );
4642
+ }
4643
+ isQuotaExceededError(error) {
4644
+ return typeof error === "object" && error !== null && "name" in error && error.name === "QuotaExceededError";
4645
+ }
4646
+ destroyPersistentLiveSession() {
4647
+ if (this.liveSession) {
4648
+ this.destroySession(this.liveSession);
4649
+ if (this.liveSession === this.baseSession) {
4650
+ this.baseSession = void 0;
4651
+ }
4652
+ }
4653
+ this.liveSession = void 0;
4654
+ this.consumedTranscript = [];
4655
+ }
4656
+ destroyPersistentSessions() {
4657
+ if (this.liveSession && this.liveSession !== this.baseSession) {
4658
+ this.destroySession(this.liveSession);
4659
+ }
4660
+ if (this.baseSession) {
4661
+ this.destroySession(this.baseSession);
4662
+ }
4663
+ this.baseSession = void 0;
4664
+ this.liveSession = void 0;
4665
+ this.persistentSessionKey = void 0;
4666
+ this.consumedTranscript = [];
4667
+ }
4668
+ destroySession(session) {
4669
+ try {
4670
+ session.destroy();
4671
+ } catch {
4672
+ }
4673
+ }
4674
+ async promptSession(session, prompt, stream, onPartialResponse) {
4675
+ if (stream && typeof session.promptStreaming === "function") {
4676
+ const reader = session.promptStreaming(prompt).getReader();
4677
+ let response2 = "";
4678
+ let streamMode = "unknown";
4679
+ while (true) {
4680
+ const { done, value } = await reader.read();
4681
+ if (done) break;
4682
+ const chunk = String(value ?? "");
4683
+ if (streamMode === "unknown" && response2 !== "") {
4684
+ streamMode = chunk.startsWith(response2) ? "cumulative" : "delta";
4685
+ }
4686
+ const isCumulative = streamMode === "cumulative";
4687
+ const delta = isCumulative ? chunk.slice(response2.length) : chunk;
4688
+ response2 = isCumulative ? chunk : response2 + chunk;
4689
+ if (delta) onPartialResponse(delta);
4690
+ }
4691
+ return response2;
4692
+ }
4693
+ const response = await session.prompt(prompt);
4694
+ onPartialResponse(response);
4695
+ return response;
4696
+ }
4420
4697
  /**
4421
4698
  * Create a new LanguageModel session with structured initial prompts.
4422
4699
  * System instructions, few-shot examples, and conversation history retain
@@ -4511,7 +4788,8 @@ If it's in another language, summarize in that language.
4511
4788
  expectedInputLanguages: options.expectedInputLanguages,
4512
4789
  expectedOutputLanguages: options.expectedOutputLanguages,
4513
4790
  initialPrompts: options.initialPrompts,
4514
- responseLength: options.responseLength
4791
+ responseLength: options.responseLength,
4792
+ sessionMode: options.sessionMode
4515
4793
  });
4516
4794
  }
4517
4795
  getProviderName() {
@@ -5061,6 +5339,9 @@ If it's in another language, summarize in that language.
5061
5339
  let shouldUseResponsesAPI = false;
5062
5340
  if (mcpServers.length > 0 || modelName === MODEL_GPT_6_ASTRA || visionModel === MODEL_GPT_6_ASTRA) {
5063
5341
  shouldUseResponsesAPI = true;
5342
+ } else if (modelName === MODEL_GPT_6_SOL || visionModel === MODEL_GPT_6_SOL || modelName === MODEL_GPT_6_LUNA || visionModel === MODEL_GPT_6_LUNA) {
5343
+ const preference = optimizedOptions.gpt5EndpointPreference || "responses";
5344
+ shouldUseResponsesAPI = preference !== "chat" || optimizedOptions.reasoning_effort !== "none";
5064
5345
  } else if (isResponsesOnlyGPT5Model(modelName)) {
5065
5346
  shouldUseResponsesAPI = true;
5066
5347
  } else if (isOpenAIReasoningModel(modelName)) {
@@ -5107,6 +5388,8 @@ If it's in another language, summarize in that language.
5107
5388
  MODEL_GPT_5_5,
5108
5389
  MODEL_GPT_5_6,
5109
5390
  MODEL_GPT_6_ASTRA,
5391
+ MODEL_GPT_6_SOL,
5392
+ MODEL_GPT_6_LUNA,
5110
5393
  MODEL_GPT_5_6_SOL,
5111
5394
  MODEL_GPT_5_6_TERRA,
5112
5395
  MODEL_GPT_5_6_LUNA,
@@ -6035,6 +6318,7 @@ If it's in another language, summarize in that language.
6035
6318
  getSupportedModels() {
6036
6319
  return [
6037
6320
  MODEL_GROK_4_6,
6321
+ MODEL_GROK_4_7,
6038
6322
  MODEL_GROK_4_5,
6039
6323
  MODEL_GROK_4_3,
6040
6324
  MODEL_GROK_4_20_REASONING,
@@ -6553,7 +6837,7 @@ If it's in another language, summarize in that language.
6553
6837
  mcp: MCP_SUPPORTED_PROVIDERS.has(providerName),
6554
6838
  jsonMode: JSON_MODE_SUPPORTED_PROVIDERS.has(providerName),
6555
6839
  responseLength: true,
6556
- reasoningEffort: providerName === "openai" && model === MODEL_GPT_6_ASTRA ? ["low", "medium", "high", "xhigh", "max"] : providerName === "claude" && model ? [...getClaudeSupportedReasoningEfforts(model)] : providerName === "gemini" && model ? [...getGeminiSupportedReasoningEfforts(model)] : providerName === "kimi" && model ? [...getKimiSupportedReasoningEfforts(model)] : providerName === "deepseek" && model ? [...getDeepSeekSupportedReasoningEfforts(model)] : providerName === "openrouter" && model ? [...getOpenRouterSupportedReasoningEfforts(model)] : providerName === "xai" && model ? [...getXaiSupportedReasoningEfforts(model)] : providerName === "zai" && model ? [...getZaiSupportedReasoningEfforts(model)] : REASONING_EFFORT_BY_PROVIDER[providerName] ?? []
6840
+ reasoningEffort: providerName === "openai" && model === MODEL_GPT_6_ASTRA ? ["low", "medium", "high", "xhigh", "max"] : providerName === "openai" && model === MODEL_GPT_6_SOL ? ["none", "low", "medium", "high", "xhigh", "max"] : providerName === "openai" && model === MODEL_GPT_6_LUNA ? ["none", "low", "medium", "high", "xhigh", "max"] : providerName === "claude" && model ? [...getClaudeSupportedReasoningEfforts(model)] : providerName === "gemini" && model ? [...getGeminiSupportedReasoningEfforts(model)] : providerName === "kimi" && model ? [...getKimiSupportedReasoningEfforts(model)] : providerName === "deepseek" && model ? [...getDeepSeekSupportedReasoningEfforts(model)] : providerName === "openrouter" && model ? [...getOpenRouterSupportedReasoningEfforts(model)] : providerName === "xai" && model ? [...getXaiSupportedReasoningEfforts(model)] : providerName === "zai" && model ? [...getZaiSupportedReasoningEfforts(model)] : REASONING_EFFORT_BY_PROVIDER[providerName] ?? []
6557
6841
  };
6558
6842
  }
6559
6843
  /**