happy-imou-cloud 2.0.22 → 2.1.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 (35) hide show
  1. package/bin/happy-cloud.mjs +1 -1
  2. package/dist/{BaseReasoningProcessor-CJVv1aNR.cjs → BaseReasoningProcessor-C9mH8EVn.cjs} +3 -3
  3. package/dist/{BaseReasoningProcessor-mIqqngd3.mjs → BaseReasoningProcessor-DQkzwRuf.mjs} +3 -3
  4. package/dist/ProviderSelectionHandler-5Dedbm8j.cjs +265 -0
  5. package/dist/ProviderSelectionHandler-BlrrLPlo.mjs +261 -0
  6. package/dist/{api-DP-RQUao.cjs → api-Bd-MnOS4.cjs} +24 -2
  7. package/dist/{api-DrijKeDb.mjs → api-w_CUxb9Q.mjs} +25 -3
  8. package/dist/{command-BZphfJrt.cjs → command-DoDmHNxR.cjs} +3 -3
  9. package/dist/{command--vV6BSsL.mjs → command-mTWwCqTY.mjs} +3 -3
  10. package/dist/{index-CqCEZDFi.cjs → index-BQmJ4NAa.cjs} +199 -79
  11. package/dist/{index-BIki80pQ.mjs → index-GuXV-pxB.mjs} +196 -76
  12. package/dist/index.cjs +3 -3
  13. package/dist/index.mjs +3 -3
  14. package/dist/lib.cjs +1 -1
  15. package/dist/lib.d.cts +95 -92
  16. package/dist/lib.d.mts +95 -92
  17. package/dist/lib.mjs +1 -1
  18. package/dist/{persistence-yVTbf_Ng.cjs → persistence-BL06LLVz.cjs} +1 -1
  19. package/dist/{persistence-C3NBdZdz.mjs → persistence-MSy70is3.mjs} +1 -1
  20. package/dist/{registerKillSessionHandler-CHEj7UjN.mjs → registerKillSessionHandler-CjWfUfc3.mjs} +428 -13
  21. package/dist/{registerKillSessionHandler-QmBN446A.cjs → registerKillSessionHandler-D9kwxy6B.cjs} +430 -12
  22. package/dist/{runClaude-BuI6OOEv.cjs → runClaude-D2ZEXue8.cjs} +11 -9
  23. package/dist/{runClaude-D0DD_Ya5.mjs → runClaude-DpZ95Twb.mjs} +8 -6
  24. package/dist/{runCodex-BzZ0jODI.mjs → runCodex-CJwaep2R.mjs} +9 -7
  25. package/dist/{runCodex-1jTTmCvq.cjs → runCodex-Dz_1ho8d.cjs} +12 -10
  26. package/dist/{runGemini-Bx2SYAyG.mjs → runGemini-BehqjM73.mjs} +192 -71
  27. package/dist/{runGemini-1gJRE8oT.cjs → runGemini-Dfu6LltX.cjs} +192 -71
  28. package/package.json +1 -1
  29. package/scripts/build.mjs +66 -66
  30. package/scripts/devtools/README.md +9 -9
  31. package/scripts/e2e/fake-codex-acp-agent.mjs +139 -139
  32. package/scripts/e2e/local-server-session-roundtrip.mjs +1063 -1063
  33. package/scripts/release-smoke.mjs +3 -0
  34. package/dist/ProviderSelectionHandler-BjLyIfSR.mjs +0 -673
  35. package/dist/ProviderSelectionHandler-e4zL4Y5_.cjs +0 -680
@@ -1,9 +1,9 @@
1
1
  'use strict';
2
2
 
3
3
  var node_crypto = require('node:crypto');
4
- var api = require('./api-DP-RQUao.cjs');
5
- var registerKillSessionHandler = require('./registerKillSessionHandler-QmBN446A.cjs');
6
- var index = require('./index-CqCEZDFi.cjs');
4
+ var api = require('./api-Bd-MnOS4.cjs');
5
+ var registerKillSessionHandler = require('./registerKillSessionHandler-D9kwxy6B.cjs');
6
+ var index = require('./index-BQmJ4NAa.cjs');
7
7
  require('cross-spawn');
8
8
  require('@agentclientprotocol/sdk');
9
9
  require('ps-list');
@@ -16,7 +16,7 @@ require('node:path');
16
16
  require('node:os');
17
17
  require('node:child_process');
18
18
  require('node:readline');
19
- require('./persistence-yVTbf_Ng.cjs');
19
+ require('./persistence-BL06LLVz.cjs');
20
20
  require('node:fs/promises');
21
21
  require('fs/promises');
22
22
  require('crypto');
@@ -27,8 +27,8 @@ require('tweetnacl');
27
27
  require('open');
28
28
  var React = require('react');
29
29
  var ink = require('ink');
30
- var ProviderSelectionHandler = require('./ProviderSelectionHandler-e4zL4Y5_.cjs');
31
- var BaseReasoningProcessor = require('./BaseReasoningProcessor-CJVv1aNR.cjs');
30
+ var ProviderSelectionHandler = require('./ProviderSelectionHandler-5Dedbm8j.cjs');
31
+ var BaseReasoningProcessor = require('./BaseReasoningProcessor-C9mH8EVn.cjs');
32
32
  require('zod');
33
33
  require('socket.io-client');
34
34
  require('expo-server-sdk');
@@ -1021,7 +1021,7 @@ async function codexRemoteLauncher(session) {
1021
1021
  api.logger.debug(`[Codex] Injected conversation history context (${historyContext.length} chars)`);
1022
1022
  }
1023
1023
  if (message.mode.happyOrg) {
1024
- promptToSend = ProviderSelectionHandler.buildHappyOrgTurnPrompt(promptToSend, message.mode.happyOrg);
1024
+ promptToSend = registerKillSessionHandler.buildHappyOrgTurnPrompt(promptToSend, message.mode.happyOrg);
1025
1025
  }
1026
1026
  conversationHistory.addUserMessage(message.message);
1027
1027
  await activeRuntimeHandle.sendPrompt(promptToSend);
@@ -1051,7 +1051,7 @@ async function codexRemoteLauncher(session) {
1051
1051
  }
1052
1052
  } finally {
1053
1053
  turnInFlight = false;
1054
- const finalizedTurn = ProviderSelectionHandler.finalizeHappyOrgTurn({
1054
+ const finalizedTurn = registerKillSessionHandler.finalizeHappyOrgTurn({
1055
1055
  metadata: session.runtimeSession.getMetadataSnapshot?.() ?? null,
1056
1056
  queuedTurn: message.mode.happyOrg,
1057
1057
  responseText: accumulatedResponse,
@@ -1233,7 +1233,7 @@ async function runCodex(opts) {
1233
1233
  let currentPermissionMode = initialPermissionMode;
1234
1234
  let currentModel;
1235
1235
  sessionClient.onUserMessage((message) => {
1236
- const happyOrgResult = ProviderSelectionHandler.resolveHappyOrgQueuedTurn({
1236
+ const happyOrgResult = registerKillSessionHandler.resolveHappyOrgQueuedTurn({
1237
1237
  metadata: sessionClient.getMetadataSnapshot?.() ?? metadata,
1238
1238
  message
1239
1239
  });
@@ -1299,7 +1299,9 @@ async function runCodex(opts) {
1299
1299
  loopError = error;
1300
1300
  } finally {
1301
1301
  try {
1302
- await registerKillSessionHandler.closeProviderSession(sessionClient);
1302
+ await registerKillSessionHandler.closeProviderSession(sessionClient, {
1303
+ archiveOnClose: true
1304
+ });
1303
1305
  } catch (error) {
1304
1306
  closeError = error;
1305
1307
  }
@@ -1,10 +1,10 @@
1
1
  import { useStdout, useInput, Box, Text, render } from 'ink';
2
2
  import React, { useState, useRef, useEffect, useCallback } from 'react';
3
3
  import { randomUUID } from 'node:crypto';
4
- import { l as logger, f as connectionState, A as ApiClient } from './api-DrijKeDb.mjs';
5
- import { B as BasePermissionHandler, C as ConversationHistory$1, e as ensureManagedProviderMachine, M as MissingMachineIdError, s as syncControlledByUserState, b as MessageQueue2, h as hashObject, d as MessageBuffer, r as registerKillSessionHandler, w as waitForResponseCompleteWithAbort, f as closeProviderSession, l as launchRuntimeHandleWithFactoryResult, i as inferToolResultError, j as forwardAgentMessageToProviderSession } from './registerKillSessionHandler-CHEj7UjN.mjs';
6
- import { g as getInitialGeminiModel, r as readGeminiLocalConfig, G as GEMINI_MODEL_ENV, s as saveGeminiModelToConfig, a as createGeminiBackend, b as stopCaffeinate } from './index-BIki80pQ.mjs';
7
- import { B as BaseReasoningProcessor, b as bootstrapManagedProviderSession } from './BaseReasoningProcessor-mIqqngd3.mjs';
4
+ import { l as logger, b as connectionState, A as ApiClient } from './api-w_CUxb9Q.mjs';
5
+ import { B as BasePermissionHandler, C as ConversationHistory$1, r as resolveHappyOrgQueuedTurn, e as ensureManagedProviderMachine, M as MissingMachineIdError, s as syncControlledByUserState, b as MessageQueue2, h as hashObject, d as registerKillSessionHandler, f as MessageBuffer, i as buildHappyOrgTurnPrompt, w as waitForResponseCompleteWithAbort, j as finalizeHappyOrgTurn, k as closeProviderSession, l as launchRuntimeHandleWithFactoryResult, m as inferToolResultError, n as forwardAgentMessageToProviderSession } from './registerKillSessionHandler-CjWfUfc3.mjs';
6
+ import { g as getInitialGeminiModel, r as readGeminiLocalConfig, G as GEMINI_MODEL_ENV, s as saveGeminiModelToConfig, a as createGeminiBackend, b as stopCaffeinate } from './index-GuXV-pxB.mjs';
7
+ import { B as BaseReasoningProcessor, b as bootstrapManagedProviderSession } from './BaseReasoningProcessor-DQkzwRuf.mjs';
8
8
  import 'cross-spawn';
9
9
  import '@agentclientprotocol/sdk';
10
10
  import 'ps-list';
@@ -15,7 +15,7 @@ import 'node:child_process';
15
15
  import 'node:readline';
16
16
  import 'tweetnacl';
17
17
  import 'axios';
18
- import './persistence-C3NBdZdz.mjs';
18
+ import './persistence-MSy70is3.mjs';
19
19
  import 'open';
20
20
  import 'chalk';
21
21
  import 'fs';
@@ -430,6 +430,93 @@ class ConversationHistory extends ConversationHistory$1 {
430
430
  }
431
431
  }
432
432
 
433
+ const GEMINI_PERMISSION_MODES = [
434
+ "default",
435
+ "read-only",
436
+ "safe-yolo",
437
+ "yolo"
438
+ ];
439
+ function isGeminiPermissionMode(value) {
440
+ return typeof value === "string" && GEMINI_PERMISSION_MODES.includes(value);
441
+ }
442
+ function hasMetaOverride(message, key) {
443
+ return Object.prototype.hasOwnProperty.call(message.meta ?? {}, key);
444
+ }
445
+ function resolveGeminiQueuedMessage(message, currentState) {
446
+ const previousState = { ...currentState };
447
+ const currentPermissionMode = isGeminiPermissionMode(currentState.permissionMode) ? currentState.permissionMode : void 0;
448
+ let permissionMode = currentPermissionMode;
449
+ let invalidPermissionMode = null;
450
+ if (hasMetaOverride(message, "permissionMode")) {
451
+ if (isGeminiPermissionMode(message.meta?.permissionMode)) {
452
+ permissionMode = message.meta.permissionMode;
453
+ } else if (message.meta?.permissionMode) {
454
+ invalidPermissionMode = String(message.meta.permissionMode);
455
+ }
456
+ }
457
+ const hasModelOverride = hasMetaOverride(message, "model");
458
+ const model = hasModelOverride ? message.meta?.model || void 0 : currentState.model;
459
+ const originalUserMessage = message.content.text;
460
+ let queuedText = originalUserMessage;
461
+ const isFirstMessage = currentState.isFirstMessage ?? true;
462
+ let nextIsFirstMessage = isFirstMessage;
463
+ if (isFirstMessage && message.meta?.appendSystemPrompt) {
464
+ queuedText = `${message.meta.appendSystemPrompt}
465
+
466
+ ${originalUserMessage}`;
467
+ nextIsFirstMessage = false;
468
+ }
469
+ const nextState = {
470
+ permissionMode: permissionMode ?? "default",
471
+ model,
472
+ isFirstMessage: nextIsFirstMessage
473
+ };
474
+ return {
475
+ previousState,
476
+ nextState,
477
+ invalidPermissionMode,
478
+ hasModelOverride,
479
+ queuedMessage: {
480
+ text: queuedText,
481
+ mode: {
482
+ permissionMode: nextState.permissionMode ?? "default",
483
+ model,
484
+ originalUserMessage
485
+ }
486
+ }
487
+ };
488
+ }
489
+ function bindGeminiUserMessageQueue(opts) {
490
+ let currentState = { ...opts.initialState };
491
+ opts.session.onUserMessage((message) => {
492
+ const happyOrgResult = opts.happyOrg ? resolveHappyOrgQueuedTurn({
493
+ metadata: opts.happyOrg.getMetadata(),
494
+ message
495
+ }) : {
496
+ nextMetadata: null,
497
+ queuedTurn: null,
498
+ blocked: false,
499
+ statusMessage: void 0
500
+ };
501
+ if (opts.happyOrg && happyOrgResult.nextMetadata) {
502
+ opts.happyOrg.updateMetadata(() => happyOrgResult.nextMetadata);
503
+ }
504
+ if (happyOrgResult.blocked) {
505
+ if (happyOrgResult.statusMessage) {
506
+ opts.happyOrg?.emitStatusMessage(happyOrgResult.statusMessage);
507
+ }
508
+ logger.debugLargeJson("[gemini] User message blocked by Happy Org runtime:", message);
509
+ return;
510
+ }
511
+ const resolution = resolveGeminiQueuedMessage(message, currentState);
512
+ currentState = resolution.nextState;
513
+ resolution.queuedMessage.mode.happyOrg = happyOrgResult.queuedTurn;
514
+ opts.onResolvedMessage?.(resolution);
515
+ opts.messageQueue.push(resolution.queuedMessage.text, resolution.queuedMessage.mode);
516
+ logger.debugLargeJson("[gemini] User message queued:", message);
517
+ });
518
+ }
519
+
433
520
  async function runGemini(opts) {
434
521
  const sessionTag = randomUUID();
435
522
  connectionState.setBackend("Gemini");
@@ -511,67 +598,21 @@ async function runGemini(opts) {
511
598
  await syncControlledByUserState(session, false);
512
599
  const messageQueue = new MessageQueue2((mode) => hashObject({
513
600
  permissionMode: mode.permissionMode,
514
- model: mode.model
601
+ model: mode.model,
602
+ happyOrg: mode.happyOrg ? {
603
+ taskId: mode.happyOrg.context.taskId,
604
+ organizationId: mode.happyOrg.context.organizationId,
605
+ memberAgentId: mode.happyOrg.context.memberAgentId,
606
+ supervisorAgentId: mode.happyOrg.context.supervisorAgentId,
607
+ reopenContext: mode.happyOrg.reopenContext ?? null
608
+ } : null
515
609
  }));
516
610
  const conversationHistory = new ConversationHistory({ maxMessages: 20, maxCharacters: 5e4 });
517
- let currentPermissionMode = void 0;
518
- let currentModel = void 0;
519
- session.onUserMessage((message) => {
520
- let messagePermissionMode = currentPermissionMode;
521
- if (message.meta?.permissionMode) {
522
- const validModes = ["default", "read-only", "safe-yolo", "yolo"];
523
- if (validModes.includes(message.meta.permissionMode)) {
524
- messagePermissionMode = message.meta.permissionMode;
525
- currentPermissionMode = messagePermissionMode;
526
- updatePermissionMode(messagePermissionMode);
527
- logger.debug(`[Gemini] Permission mode updated from user message to: ${currentPermissionMode}`);
528
- } else {
529
- logger.debug(`[Gemini] Invalid permission mode received: ${message.meta.permissionMode}`);
530
- }
531
- } else {
532
- logger.debug(`[Gemini] User message received with no permission mode override, using current: ${currentPermissionMode ?? "default (effective)"}`);
533
- }
534
- if (currentPermissionMode === void 0) {
535
- currentPermissionMode = "default";
536
- updatePermissionMode("default");
537
- }
538
- let messageModel = currentModel;
539
- if (message.meta?.hasOwnProperty("model")) {
540
- if (message.meta.model === null) {
541
- messageModel = void 0;
542
- currentModel = void 0;
543
- } else if (message.meta.model) {
544
- const previousModel = currentModel;
545
- messageModel = message.meta.model;
546
- currentModel = messageModel;
547
- if (previousModel !== messageModel) {
548
- updateDisplayedModel(messageModel, true);
549
- messageBuffer.addMessage(`Model changed to: ${messageModel}`, "system");
550
- logger.debug(`[Gemini] Model changed from ${previousModel} to ${messageModel}`);
551
- }
552
- }
553
- }
554
- const originalUserMessage = message.content.text;
555
- let fullPrompt = originalUserMessage;
556
- if (isFirstMessage && message.meta?.appendSystemPrompt) {
557
- fullPrompt = message.meta.appendSystemPrompt + "\n\n" + originalUserMessage;
558
- isFirstMessage = false;
559
- }
560
- const mode = {
561
- permissionMode: messagePermissionMode || "default",
562
- model: messageModel,
563
- originalUserMessage
564
- // Store original message separately
565
- };
566
- messageQueue.push(fullPrompt, mode);
567
- conversationHistory.addUserMessage(originalUserMessage);
568
- });
569
611
  let thinking = false;
570
612
  session.keepAlive(thinking, "remote");
571
613
  const keepAliveInterval = setInterval(() => {
572
614
  session.keepAlive(thinking, "remote");
573
615
  }, 2e3);
574
- let isFirstMessage = true;
575
616
  const sendReady = () => {
576
617
  session.sendSessionEvent({ type: "ready" });
577
618
  try {
@@ -604,12 +645,18 @@ async function runGemini(opts) {
604
645
  let shouldExit = false;
605
646
  let runtimeHandle = null;
606
647
  let unsubscribeRuntimeMessages = null;
648
+ let handleQueuedUserMessage = null;
649
+ let emitGeminiStatusMessage = null;
650
+ let turnAbortedSent = false;
607
651
  async function handleAbort() {
608
652
  logger.debug("[Gemini] Abort requested - stopping current task");
609
- session.sendAgentMessage("gemini", {
610
- type: "turn_aborted",
611
- id: randomUUID()
612
- });
653
+ if (!turnAbortedSent) {
654
+ session.sendAgentMessage("gemini", {
655
+ type: "turn_aborted",
656
+ id: randomUUID()
657
+ });
658
+ turnAbortedSent = true;
659
+ }
613
660
  reasoningProcessor.abort();
614
661
  diffProcessor.reset();
615
662
  try {
@@ -670,6 +717,10 @@ async function runGemini(opts) {
670
717
  logger.debug(`[gemini] Model unchanged, skipping update message`);
671
718
  }
672
719
  };
720
+ emitGeminiStatusMessage = (message) => {
721
+ messageBuffer.addMessage(message, "status");
722
+ session.sendSessionEvent({ type: "message", message });
723
+ };
673
724
  if (hasTTY) {
674
725
  console.clear();
675
726
  const DisplayComponent = () => {
@@ -710,6 +761,41 @@ async function runGemini(opts) {
710
761
  const updatePermissionMode = (mode) => {
711
762
  permissionHandler.setPermissionMode(mode);
712
763
  };
764
+ handleQueuedUserMessage = ({ previousState, nextState, invalidPermissionMode, hasModelOverride }) => {
765
+ if (invalidPermissionMode) {
766
+ logger.debug(`[Gemini] Invalid permission mode received: ${invalidPermissionMode}`);
767
+ } else if (nextState.permissionMode) {
768
+ logger.debug(`[Gemini] Permission mode resolved to: ${nextState.permissionMode}`);
769
+ }
770
+ updatePermissionMode(nextState.permissionMode ?? "default");
771
+ if (hasModelOverride && nextState.model && previousState.model !== nextState.model) {
772
+ updateDisplayedModel(nextState.model, true);
773
+ messageBuffer.addMessage(`Model changed to: ${nextState.model}`, "system");
774
+ logger.debug(`[Gemini] Model changed from ${previousState.model} to ${nextState.model}`);
775
+ }
776
+ };
777
+ bindGeminiUserMessageQueue({
778
+ session,
779
+ messageQueue,
780
+ initialState: {},
781
+ happyOrg: {
782
+ getMetadata: () => session.getMetadataSnapshot?.() ?? metadata,
783
+ updateMetadata: (handler) => session.updateMetadata(handler),
784
+ emitStatusMessage: (message) => {
785
+ emitGeminiStatusMessage?.(message);
786
+ }
787
+ },
788
+ onResolvedMessage: (resolution) => {
789
+ handleQueuedUserMessage?.(resolution);
790
+ }
791
+ });
792
+ const emitTurnReport = (report) => {
793
+ session.sendAgentMessage("gemini", {
794
+ type: "turn-report",
795
+ id: randomUUID(),
796
+ report
797
+ });
798
+ };
713
799
  let accumulatedResponse = "";
714
800
  let isResponseInProgress = false;
715
801
  let hadToolCallInTurn = false;
@@ -757,10 +843,13 @@ async function runGemini(opts) {
757
843
  logger.debug(`[gemini] Status changed: ${msg.status}${statusDetail ? ` - ${statusDetail}` : ""}`);
758
844
  if (msg.status === "error") {
759
845
  logger.debug(`[gemini] \u26A0\uFE0F Error status received: ${statusDetail || "Unknown error"}`);
760
- session.sendAgentMessage("gemini", {
761
- type: "turn_aborted",
762
- id: randomUUID()
763
- });
846
+ if (!turnAbortedSent) {
847
+ session.sendAgentMessage("gemini", {
848
+ type: "turn_aborted",
849
+ id: randomUUID()
850
+ });
851
+ turnAbortedSent = true;
852
+ }
764
853
  }
765
854
  if (msg.status === "running") {
766
855
  thinking = true;
@@ -985,6 +1074,7 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
985
1074
  const userMessageToShow = message.mode?.originalUserMessage || message.message;
986
1075
  messageBuffer.addMessage(userMessageToShow, "user");
987
1076
  isProcessingMessage = true;
1077
+ let turnStatus = "task_complete";
988
1078
  try {
989
1079
  let activeHandle = runtimeHandle;
990
1080
  if (!activeHandle) {
@@ -1005,12 +1095,17 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
1005
1095
  isResponseInProgress = false;
1006
1096
  hadToolCallInTurn = false;
1007
1097
  taskStartedSent = false;
1098
+ turnAbortedSent = false;
1008
1099
  let promptToSend = message.message;
1009
1100
  if (injectHistoryContext && conversationHistory.hasHistory()) {
1010
1101
  const historyContext = conversationHistory.getContextForNewSession();
1011
1102
  promptToSend = historyContext + promptToSend;
1012
1103
  logger.debug(`[gemini] Injected conversation history context (${historyContext.length} chars)`);
1013
1104
  }
1105
+ if (message.mode.happyOrg) {
1106
+ promptToSend = buildHappyOrgTurnPrompt(promptToSend, message.mode.happyOrg);
1107
+ }
1108
+ conversationHistory.addUserMessage(userMessageToShow);
1014
1109
  logger.debug(`[gemini] Sending prompt to Gemini (length: ${promptToSend.length}): ${promptToSend.substring(0, 100)}...`);
1015
1110
  logger.debug(`[gemini] Full prompt: ${promptToSend}`);
1016
1111
  const MAX_RETRIES = 3;
@@ -1020,7 +1115,7 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
1020
1115
  try {
1021
1116
  await activeHandle.sendPrompt(promptToSend);
1022
1117
  logger.debug("[gemini] Prompt sent successfully");
1023
- await waitForResponseCompleteWithAbort(activeHandle.backend, abortController.signal, 12e4);
1118
+ await waitForResponseCompleteWithAbort(activeHandle.backend, abortController.signal, 10 * 6e4);
1024
1119
  logger.debug("[gemini] Response complete");
1025
1120
  break;
1026
1121
  } catch (promptError) {
@@ -1059,6 +1154,14 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
1059
1154
  } catch (error) {
1060
1155
  logger.debug("[gemini] Error in gemini session:", error);
1061
1156
  const isAbortError = error instanceof Error && error.name === "AbortError";
1157
+ turnStatus = "turn_aborted";
1158
+ if (!turnAbortedSent) {
1159
+ session.sendAgentMessage("gemini", {
1160
+ type: "turn_aborted",
1161
+ id: randomUUID()
1162
+ });
1163
+ turnAbortedSent = true;
1164
+ }
1062
1165
  if (isAbortError) {
1063
1166
  messageBuffer.addMessage("Aborted by user", "status");
1064
1167
  session.sendSessionEvent({ type: "message", message: "Aborted by user" });
@@ -1071,8 +1174,8 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
1071
1174
  const errorMessage = errObj.message || errObj.error?.message || "";
1072
1175
  const errorString = String(error);
1073
1176
  if (errorCode === 404 || errorDetails.includes("notFound") || errorDetails.includes("404") || errorMessage.includes("not found") || errorMessage.includes("404")) {
1074
- const currentModel2 = displayedModel || "gemini-2.5-pro";
1075
- errorMsg = `Model "${currentModel2}" not found. Available models: gemini-2.5-pro, gemini-2.5-flash, gemini-2.5-flash-lite`;
1177
+ const currentModel = displayedModel || "gemini-2.5-pro";
1178
+ errorMsg = `Model "${currentModel}" not found. Available models: gemini-2.5-pro, gemini-2.5-flash, gemini-2.5-flash-lite`;
1076
1179
  } else if (errorCode === -32603 || errorDetails.includes("empty response") || errorDetails.includes("Model stream ended")) {
1077
1180
  errorMsg = "Gemini API returned empty response after retries. This is a temporary issue - please try again.";
1078
1181
  } else if (errorCode === 429 || errorDetails.includes("429") || errorMessage.includes("429") || errorString.includes("429") || errorDetails.includes("rateLimitExceeded") || errorDetails.includes("RESOURCE_EXHAUSTED") || errorMessage.includes("Rate limit exceeded") || errorMessage.includes("Resource exhausted") || errorString.includes("rateLimitExceeded") || errorString.includes("RESOURCE_EXHAUSTED")) {
@@ -1108,6 +1211,22 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
1108
1211
  permissionHandler.reset();
1109
1212
  reasoningProcessor.abort();
1110
1213
  diffProcessor.reset();
1214
+ const finalizedTurn = finalizeHappyOrgTurn({
1215
+ metadata: session.getMetadataSnapshot?.() ?? null,
1216
+ queuedTurn: message.mode.happyOrg,
1217
+ responseText: accumulatedResponse,
1218
+ turnStatus
1219
+ });
1220
+ if (finalizedTurn.nextMetadata && typeof session.updateMetadata === "function") {
1221
+ session.updateMetadata(() => finalizedTurn.nextMetadata);
1222
+ }
1223
+ if (finalizedTurn.report) {
1224
+ emitTurnReport(finalizedTurn.report);
1225
+ }
1226
+ if (finalizedTurn.terminateMessage) {
1227
+ emitGeminiStatusMessage?.(finalizedTurn.terminateMessage);
1228
+ }
1229
+ accumulatedResponse = finalizedTurn.cleanedText;
1111
1230
  if (accumulatedResponse.trim()) {
1112
1231
  const { text: messageText, options } = parseOptionsFromText(accumulatedResponse);
1113
1232
  conversationHistory.addAssistantMessage(messageText);
@@ -1151,7 +1270,9 @@ Guide: https://goo.gle/gemini-cli-auth-docs#workspace-gca`;
1151
1270
  reconnectionHandle.cancel();
1152
1271
  }
1153
1272
  try {
1154
- await closeProviderSession(session);
1273
+ await closeProviderSession(session, {
1274
+ archiveOnClose: true
1275
+ });
1155
1276
  } catch (e) {
1156
1277
  logger.debug("[gemini]: Error while closing session", e);
1157
1278
  }