chrome-ai-bridge 2.5.2 → 2.5.3

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.
@@ -1037,7 +1037,7 @@ async function askChatGPTFastInternal(question, debug, budgetMs) {
1037
1037
  // 60秒 caller deadline を超えないよう、残り予算内で待機する。
1038
1038
  const maxWaitMs = getResponseWaitBudgetMs(t0, RESPONSE_WAIT_MAX_MS, 'chatgpt-response', budgetMs);
1039
1039
  const pollIntervalMs = 1000;
1040
- const IDLE_TIMEOUT_MS = 30000; // ストップボタン消失後、30秒間無活動でタイムアウト
1040
+ const IDLE_TIMEOUT_MS = 60000; // ストップボタン消失後、60秒間無活動でタイムアウト
1041
1041
  const startWait = Date.now();
1042
1042
  let lastActivityAt = Date.now(); // 最後にストップボタンorテキスト成長を検出した時刻
1043
1043
  let lastLoggedState = '';
@@ -1047,8 +1047,10 @@ async function askChatGPTFastInternal(question, debug, budgetMs) {
1047
1047
  let lastTextLength = -1; // 前回のテキスト長
1048
1048
  let stopButtonGoneCount = 0; // ストップボタンが連続不在のポール数(Thinkingフェーズ切替誤判定防止)
1049
1049
  let textGrowingCount = 0; // テキストが成長中のポール数(成長中はフォールバック抑止)
1050
- // ストップボタンが見えている間は無制限に待つ(maxWaitMs は絶対安全上限)
1051
- while (Date.now() - startWait < maxWaitMs && Date.now() - lastActivityAt < IDLE_TIMEOUT_MS) {
1050
+ // ストップボタンが見えている間は maxWaitMs を無視し、IDLE_TIMEOUT のみで判定する。
1051
+ // sawStopButton=false の初期フェーズでは maxWaitMs も併用。
1052
+ while (Date.now() - lastActivityAt < IDLE_TIMEOUT_MS &&
1053
+ (sawStopButton || Date.now() - startWait < maxWaitMs)) {
1052
1054
  const state = await client.evaluate(`
1053
1055
  (() => {
1054
1056
  ${DOM_UTILS_CODE}
@@ -1407,8 +1409,10 @@ async function askChatGPTFastInternal(question, debug, budgetMs) {
1407
1409
  }
1408
1410
  await new Promise(r => setTimeout(r, pollIntervalMs));
1409
1411
  }
1410
- // タイムアウトチェック
1411
- if (Date.now() - startWait >= maxWaitMs) {
1412
+ // タイムアウトチェック(IDLE_TIMEOUT で抜けた場合も含む)
1413
+ const loopElapsed = Date.now() - startWait;
1414
+ const loopIdle = Date.now() - lastActivityAt;
1415
+ if (loopIdle >= IDLE_TIMEOUT_MS || (!sawStopButton && loopElapsed >= maxWaitMs)) {
1412
1416
  const finalState = await client.evaluate(`
1413
1417
  (() => {
1414
1418
  // フォールバックセレクター付きの検出
@@ -2747,12 +2751,16 @@ async function askGeminiFastInternal(question, debug, budgetMs) {
2747
2751
  // ChatGPT側と同様のポーリングループで応答完了を検出
2748
2752
  const maxWaitMs = getResponseWaitBudgetMs(t0, RESPONSE_WAIT_MAX_MS, 'gemini-response', budgetMs);
2749
2753
  const pollIntervalMs = 1000;
2754
+ const IDLE_TIMEOUT_MS = 60000; // ストップボタン消失後、60秒間無活動でタイムアウト
2750
2755
  const startWait = Date.now();
2756
+ let lastActivityAt = Date.now(); // 最後にストップボタンorテキスト成長を検出した時刻
2751
2757
  let lastLoggedState = '';
2752
2758
  let sawStopButton = false; // 停止ボタンを見たかどうか(生成が始まった証拠)
2753
2759
  let lastTextLength = 0;
2754
2760
  let textStableCount = 0; // テキスト長が変わらなかった回数
2755
- while (Date.now() - startWait < maxWaitMs) {
2761
+ // ストップボタンが見えている間は maxWaitMs を無視し、IDLE_TIMEOUT のみで判定する。
2762
+ while (Date.now() - lastActivityAt < IDLE_TIMEOUT_MS &&
2763
+ (sawStopButton || Date.now() - startWait < maxWaitMs)) {
2756
2764
  const state = await client.evaluate(`
2757
2765
  (() => {
2758
2766
  ${DOM_UTILS_CODE}
@@ -2854,14 +2862,20 @@ async function askGeminiFastInternal(question, debug, budgetMs) {
2854
2862
  };
2855
2863
  })()
2856
2864
  `);
2857
- // 停止ボタンを検出したらフラグを立てる(生成が始まった証拠)
2865
+ // 停止ボタンを検出したらフラグを立て、アクティビティを更新
2858
2866
  if (state.hasStopButton) {
2859
2867
  sawStopButton = true;
2868
+ lastActivityAt = Date.now();
2860
2869
  }
2861
2870
  // テキスト長安定化検出
2862
2871
  if (state.lastResponseTextLength === lastTextLength && state.lastResponseTextLength > 0) {
2863
2872
  textStableCount++;
2864
2873
  }
2874
+ else if (state.lastResponseTextLength > lastTextLength) {
2875
+ textStableCount = 0;
2876
+ lastTextLength = state.lastResponseTextLength;
2877
+ lastActivityAt = Date.now(); // テキスト成長もアクティビティとみなす
2878
+ }
2865
2879
  else {
2866
2880
  textStableCount = 0;
2867
2881
  lastTextLength = state.lastResponseTextLength;
@@ -2911,8 +2925,13 @@ async function askGeminiFastInternal(question, debug, budgetMs) {
2911
2925
  }
2912
2926
  await new Promise(r => setTimeout(r, pollIntervalMs));
2913
2927
  }
2914
- // タイムアウトチェック
2915
- if (Date.now() - startWait >= maxWaitMs) {
2928
+ // タイムアウトチェック(IDLE_TIMEOUT で抜けた場合も含む)
2929
+ const geminiLoopElapsed = Date.now() - startWait;
2930
+ const geminiLoopIdle = Date.now() - lastActivityAt;
2931
+ if (geminiLoopIdle >= IDLE_TIMEOUT_MS || (!sawStopButton && geminiLoopElapsed >= maxWaitMs)) {
2932
+ const reason = geminiLoopIdle >= IDLE_TIMEOUT_MS
2933
+ ? `idle for ${Math.round(geminiLoopIdle / 1000)}s (no stop button or text growth)`
2934
+ : `absolute ceiling ${maxWaitMs}ms reached (stop button never seen)`;
2916
2935
  const finalState = await client.evaluate(`
2917
2936
  (() => {
2918
2937
  const textIncludes = (needle) => document.body && document.body.innerText && document.body.innerText.includes(needle);
@@ -2941,9 +2960,9 @@ async function askGeminiFastInternal(question, debug, budgetMs) {
2941
2960
  };
2942
2961
  })()
2943
2962
  `);
2944
- console.error(`[Gemini] Timeout - final state: ${JSON.stringify(finalState)}`);
2963
+ console.error(`[Gemini] Timeout - ${reason}, elapsed=${Math.round(geminiLoopElapsed / 1000)}s, final state: ${JSON.stringify(finalState)}`);
2945
2964
  await resetConnection('gemini');
2946
- throw new Error(`Timed out waiting for Gemini response (${maxWaitMs}ms). sawStopButton=${sawStopButton}, textStableCount=${textStableCount}. Final state: ${JSON.stringify(finalState)}`);
2965
+ throw new Error(`Timed out waiting for Gemini response (${Math.round(geminiLoopElapsed / 1000)}s, ${reason}). sawStopButton=${sawStopButton}, textStableCount=${textStableCount}. Final state: ${JSON.stringify(finalState)}`);
2947
2966
  }
2948
2967
  // 重要: タブをフォアグラウンドに持ってくる(バックグラウンドタブ対策)
2949
2968
  // GeminiもChatGPTと同様、バックグラウンドタブではDOMの状態が正しく取得できない
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chrome-ai-bridge",
3
- "version": "2.5.2",
3
+ "version": "2.5.3",
4
4
  "description": "CLI tool for querying ChatGPT and Gemini via Chrome extension. No Puppeteer required.",
5
5
  "type": "module",
6
6
  "bin": {