chrome-ai-bridge 2.4.0 → 2.5.1
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.
- package/README.md +28 -40
- package/build/extension/README.md +10 -10
- package/build/extension/background.mjs +94 -26
- package/build/extension/manifest.json +2 -2
- package/build/extension/relay-server.ts +16 -2
- package/build/extension/ui/connect.html +1 -1
- package/build/extension/ui/connect.js +46 -10
- package/build/src/cli.js +6 -1
- package/build/src/config.js +2 -4
- package/build/src/extension/relay-server.js +20 -2
- package/build/src/fast-cdp/agent-context.js +2 -2
- package/build/src/fast-cdp/{mcp-logger.js → debug-logger.js} +11 -11
- package/build/src/fast-cdp/extension-raw.js +51 -5
- package/build/src/fast-cdp/fast-chat.js +124 -92
- package/build/src/logger.js +3 -3
- package/build/src/main.js +104 -568
- package/build/src/plugin-api.js +1 -1
- package/build/src/runtime-scope.js +1 -1
- package/build/src/tools/ai-helpers.js +72 -17
- package/build/src/tools/chatgpt-gemini-web.js +1 -1
- package/build/src/tools/chatgpt-web.js +7 -7
- package/build/src/tools/gemini-web.js +10 -22
- package/build/src/tools/optional-tools.js +8 -5
- package/package.json +17 -18
- package/scripts/cab +200 -0
- package/scripts/cli.mjs +1 -1
- package/build/src/McpResponse.js +0 -60
- package/build/src/stdio-http-proxy.js +0 -157
|
@@ -2,7 +2,7 @@ import fs from 'node:fs/promises';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { connectViaExtensionRaw } from './extension-raw.js';
|
|
4
4
|
import { CdpClient } from './cdp-client.js';
|
|
5
|
-
import { logConnectionState, logInfo, logError, logWarn } from './
|
|
5
|
+
import { logConnectionState, logInfo, logError, logWarn } from './debug-logger.js';
|
|
6
6
|
import { DOM_UTILS_CODE } from './utils/index.js';
|
|
7
7
|
import { getDriver } from './drivers/index.js';
|
|
8
8
|
import { NetworkInterceptor } from './network-interceptor.js';
|
|
@@ -49,18 +49,29 @@ function setClientForAgent(kind, client, relay) {
|
|
|
49
49
|
conn.geminiRelay = relay;
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
// Env var deprecation helpers
|
|
53
|
+
function envWithFallback(newName, oldName, defaultVal) {
|
|
54
|
+
if (process.env[newName])
|
|
55
|
+
return process.env[newName];
|
|
56
|
+
if (process.env[oldName]) {
|
|
57
|
+
console.error(`[deprecation] ${oldName} is deprecated, use ${newName} instead`);
|
|
58
|
+
return process.env[oldName];
|
|
59
|
+
}
|
|
60
|
+
return defaultVal;
|
|
61
|
+
}
|
|
62
|
+
const CONNECT_REUSE_TIMEOUT_MS = Number(envWithFallback('CAI_CONNECT_REUSE_TIMEOUT_MS', 'MCP_CONNECT_REUSE_TIMEOUT_MS', '12000'));
|
|
63
|
+
const CONNECT_NEWTAB_TIMEOUT_MS = Number(envWithFallback('CAI_CONNECT_NEWTAB_TIMEOUT_MS', 'MCP_CONNECT_NEWTAB_TIMEOUT_MS', '20000'));
|
|
64
|
+
const TOOL_BUDGET_MS = Number(envWithFallback('CAI_TOOL_BUDGET_MS', 'CAI_MCP_TOOL_BUDGET_MS', '50000'));
|
|
55
65
|
const RESPONSE_WAIT_MAX_MS = Number(process.env.CAI_RESPONSE_WAIT_MAX_MS || '40000');
|
|
56
|
-
const BUDGET_RESERVE_MS = Number(
|
|
57
|
-
function getRemainingBudgetMs(startMs) {
|
|
58
|
-
return
|
|
66
|
+
const BUDGET_RESERVE_MS = Number(envWithFallback('CAI_BUDGET_RESERVE_MS', 'CAI_MCP_BUDGET_RESERVE_MS', '3000'));
|
|
67
|
+
function getRemainingBudgetMs(startMs, overrideBudgetMs) {
|
|
68
|
+
return (overrideBudgetMs ?? TOOL_BUDGET_MS) - (nowMs() - startMs) - BUDGET_RESERVE_MS;
|
|
59
69
|
}
|
|
60
|
-
function getResponseWaitBudgetMs(startMs, ceilingMs, stage) {
|
|
61
|
-
const
|
|
70
|
+
function getResponseWaitBudgetMs(startMs, ceilingMs, stage, overrideBudgetMs) {
|
|
71
|
+
const effectiveBudget = overrideBudgetMs ?? TOOL_BUDGET_MS;
|
|
72
|
+
const remaining = getRemainingBudgetMs(startMs, overrideBudgetMs);
|
|
62
73
|
if (remaining <= 1000) {
|
|
63
|
-
throw new Error(`
|
|
74
|
+
throw new Error(`TOOL_BUDGET_EXCEEDED: stage=${stage} budgetMs=${effectiveBudget} reserveMs=${BUDGET_RESERVE_MS}`);
|
|
64
75
|
}
|
|
65
76
|
return Math.max(1000, Math.min(ceilingMs, remaining));
|
|
66
77
|
}
|
|
@@ -72,6 +83,14 @@ function nowMs() {
|
|
|
72
83
|
* 軽量なevaluateコマンドで接続が生きているかチェック
|
|
73
84
|
*/
|
|
74
85
|
async function isConnectionHealthy(client, kind) {
|
|
86
|
+
// Fast-path: if relay is already disconnected, skip the expensive evaluate call
|
|
87
|
+
if (kind) {
|
|
88
|
+
const relay = getRelayFromAgent(kind);
|
|
89
|
+
if (relay && !relay.isReady()) {
|
|
90
|
+
logConnectionState(kind, 'unhealthy', { elapsed: 0, error: 'relay not ready (fast-path)' });
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
75
94
|
const startTime = Date.now();
|
|
76
95
|
try {
|
|
77
96
|
// 4秒タイムアウトで簡単なコマンドを実行(2秒では不十分な場合があった)
|
|
@@ -228,7 +247,7 @@ export async function resetConnection(kind) {
|
|
|
228
247
|
}
|
|
229
248
|
/**
|
|
230
249
|
* 全接続をクリーンアップ(プロセス終了時用)
|
|
231
|
-
*
|
|
250
|
+
* サーバー終了時にゾンビプロセスを防ぐために使用
|
|
232
251
|
*/
|
|
233
252
|
export async function cleanupAllConnections() {
|
|
234
253
|
// Snapshot entries before clearing to avoid mutation during iteration
|
|
@@ -505,7 +524,17 @@ async function navigate(client, url) {
|
|
|
505
524
|
await client.send('Page.navigate', { url });
|
|
506
525
|
await client.waitForFunction(`document.readyState === 'complete'`, 30000);
|
|
507
526
|
}
|
|
508
|
-
|
|
527
|
+
/** Strip conversation-specific paths (/c/<id>, /app/<id>) to prevent chat pollution on reuse */
|
|
528
|
+
function getBaseUrl(kind, url) {
|
|
529
|
+
if (kind === 'chatgpt') {
|
|
530
|
+
return url.replace(/\/c\/[a-zA-Z0-9_-]+.*$/, '/');
|
|
531
|
+
}
|
|
532
|
+
if (kind === 'gemini') {
|
|
533
|
+
return url.replace(/\/app\/[a-zA-Z0-9_-]+.*$/, '/');
|
|
534
|
+
}
|
|
535
|
+
return url;
|
|
536
|
+
}
|
|
537
|
+
async function askChatGPTFastInternal(question, debug, budgetMs) {
|
|
509
538
|
const t0 = nowMs();
|
|
510
539
|
const timings = {};
|
|
511
540
|
logInfo('chatgpt', 'askChatGPTFast started', { questionLength: question.length });
|
|
@@ -523,16 +552,14 @@ async function askChatGPTFastInternal(question, debug) {
|
|
|
523
552
|
// SPA描画安定化のため追加待機
|
|
524
553
|
await new Promise(r => setTimeout(r, 500));
|
|
525
554
|
console.error('[ChatGPT] Waited 500ms for SPA rendering');
|
|
526
|
-
// 既存チャット(/c/を含むURL
|
|
555
|
+
// 既存チャット(/c/を含むURL)の場合、新規チャットへ遷移
|
|
556
|
+
// 同じ会話に質問を投入すると前回のコンテキストが応答に影響するため
|
|
527
557
|
const currentUrl = await client.evaluate('location.href');
|
|
528
558
|
if (currentUrl.includes('/c/')) {
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
catch {
|
|
534
|
-
console.error('[ChatGPT] No existing messages found, continuing as new chat');
|
|
535
|
-
}
|
|
559
|
+
console.error('[ChatGPT] Existing conversation detected, navigating to new chat...');
|
|
560
|
+
await navigate(client, 'https://chatgpt.com/');
|
|
561
|
+
await new Promise(r => setTimeout(r, 500));
|
|
562
|
+
console.error('[ChatGPT] New chat page loaded');
|
|
536
563
|
}
|
|
537
564
|
// 入力欄が表示されるまで待機してから取得
|
|
538
565
|
const tWaitInput = nowMs();
|
|
@@ -1008,12 +1035,14 @@ async function askChatGPTFastInternal(question, debug) {
|
|
|
1008
1035
|
const tWaitResp = nowMs();
|
|
1009
1036
|
console.error('[ChatGPT] Waiting for response (using stop button detection)...');
|
|
1010
1037
|
// 60秒 caller deadline を超えないよう、残り予算内で待機する。
|
|
1011
|
-
const maxWaitMs = getResponseWaitBudgetMs(t0, RESPONSE_WAIT_MAX_MS, 'chatgpt-response');
|
|
1038
|
+
const maxWaitMs = getResponseWaitBudgetMs(t0, RESPONSE_WAIT_MAX_MS, 'chatgpt-response', budgetMs);
|
|
1012
1039
|
const pollIntervalMs = 1000;
|
|
1013
1040
|
const startWait = Date.now();
|
|
1014
1041
|
let lastLoggedState = '';
|
|
1015
1042
|
let sawStopButton = false; // 生成中状態を検出したかどうか
|
|
1016
1043
|
let streamingText = ''; // ストリーミング中に取得したテキスト(完了後に折りたたまれる対策)
|
|
1044
|
+
let textStableCount = 0; // テキスト長が安定した回数(2-poll confirmation)
|
|
1045
|
+
let lastTextLength = -1; // 前回のテキスト長
|
|
1017
1046
|
while (Date.now() - startWait < maxWaitMs) {
|
|
1018
1047
|
const state = await client.evaluate(`
|
|
1019
1048
|
(() => {
|
|
@@ -1288,46 +1317,65 @@ async function askChatGPTFastInternal(question, debug) {
|
|
|
1288
1317
|
// 2. AND 入力欄が空
|
|
1289
1318
|
// 3. AND 新しいアシスタントメッセージが増えた
|
|
1290
1319
|
// 注: hasResponseText は CDP でテキスト取得できない場合があるため必須条件から外す
|
|
1320
|
+
// テキスト安定性チェック(全完了条件で共通使用)
|
|
1321
|
+
const currentTextLen = state.debug_lastAssistantInnerTextLen;
|
|
1322
|
+
if (currentTextLen === lastTextLength && currentTextLen > 0) {
|
|
1323
|
+
textStableCount++;
|
|
1324
|
+
}
|
|
1325
|
+
else {
|
|
1326
|
+
textStableCount = 0;
|
|
1327
|
+
lastTextLength = currentTextLen;
|
|
1328
|
+
}
|
|
1291
1329
|
if (sawStopButton && !state.hasStopButton && !state.inputBoxHasText &&
|
|
1292
1330
|
state.assistantMsgCount > initialAssistantCount) {
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1331
|
+
// 2-poll confirmation: テキスト長が2回連続安定してから完了とする
|
|
1332
|
+
if (textStableCount >= 2) {
|
|
1333
|
+
console.error(`[ChatGPT] Response complete - stop gone, text stable for ${textStableCount} polls (len=${currentTextLen})`);
|
|
1334
|
+
streamingText = await client.evaluate(`
|
|
1335
|
+
(() => {
|
|
1336
|
+
const msgs = document.querySelectorAll('[data-message-author-role="assistant"]');
|
|
1337
|
+
if (msgs.length === 0) return '';
|
|
1338
|
+
const last = msgs[msgs.length - 1];
|
|
1339
|
+
const md = last.querySelector('.markdown');
|
|
1340
|
+
if (md) {
|
|
1341
|
+
const t = (md.innerText || md.textContent || '').trim();
|
|
1342
|
+
if (t.length > 0) return t;
|
|
1343
|
+
}
|
|
1344
|
+
const rt = last.querySelector('.result-thinking');
|
|
1345
|
+
if (rt) {
|
|
1346
|
+
const t = (rt.innerText || rt.textContent || '').trim();
|
|
1347
|
+
if (t.length > 0) return t;
|
|
1348
|
+
}
|
|
1349
|
+
return (last.innerText || last.textContent || '').trim();
|
|
1350
|
+
})()
|
|
1351
|
+
`);
|
|
1352
|
+
break;
|
|
1311
1353
|
}
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1354
|
+
// まだ安定していない — 次のポールまで待機
|
|
1355
|
+
console.error(`[ChatGPT] Stop button gone but text not stable yet (len=${currentTextLen}, stableCount=${textStableCount})`);
|
|
1356
|
+
await new Promise(r => setTimeout(r, pollIntervalMs));
|
|
1357
|
+
continue;
|
|
1316
1358
|
}
|
|
1317
1359
|
// フォールバック: 5秒以上待って、stopボタンなし、入力欄空、新しいアシスタントメッセージが増えた
|
|
1318
1360
|
// (stopボタンを見逃した場合の救済)
|
|
1319
1361
|
const elapsed = Date.now() - startWait;
|
|
1320
1362
|
if (elapsed > 5000 && !state.hasStopButton && !state.inputBoxHasText &&
|
|
1321
1363
|
state.assistantMsgCount > initialAssistantCount && !state.isStillGenerating) {
|
|
1322
|
-
|
|
1323
|
-
|
|
1364
|
+
if (textStableCount >= 2) {
|
|
1365
|
+
console.error(`[ChatGPT] Response complete - fallback after 5s, text stable (len=${currentTextLen}, stableCount=${textStableCount})`);
|
|
1366
|
+
break;
|
|
1367
|
+
}
|
|
1368
|
+
console.error(`[ChatGPT] Fallback conditions met but text not stable yet (len=${currentTextLen}, stableCount=${textStableCount})`);
|
|
1324
1369
|
}
|
|
1325
1370
|
// Thinkingモード専用フォールバック: stopボタンなしでも、生成完了していれば完了
|
|
1326
1371
|
// 重要: 「今すぐ回答」ボタンがある間は、まだThinking中なので待機を継続
|
|
1327
1372
|
if (elapsed > 10000 && !state.isStillGenerating && !state.hasSkipThinkingButton &&
|
|
1328
1373
|
state.assistantMsgCount > initialAssistantCount && !state.inputBoxHasText) {
|
|
1329
|
-
|
|
1330
|
-
|
|
1374
|
+
if (textStableCount >= 2) {
|
|
1375
|
+
console.error(`[ChatGPT] Response complete - Thinking mode fallback after 10s, text stable (len=${currentTextLen}, stableCount=${textStableCount})`);
|
|
1376
|
+
break;
|
|
1377
|
+
}
|
|
1378
|
+
console.error(`[ChatGPT] Thinking fallback conditions met but text not stable yet (len=${currentTextLen}, stableCount=${textStableCount})`);
|
|
1331
1379
|
}
|
|
1332
1380
|
await new Promise(r => setTimeout(r, pollIntervalMs));
|
|
1333
1381
|
}
|
|
@@ -1401,7 +1449,7 @@ async function askChatGPTFastInternal(question, debug) {
|
|
|
1401
1449
|
// 回答完了後、DOM安定化のための追加待機
|
|
1402
1450
|
// ChatGPT Thinkingモードでは、停止ボタン消失後も最終回答がレンダリングされるまで遅延がある
|
|
1403
1451
|
// 回答テキストが存在するまでポーリングで待機
|
|
1404
|
-
const maxWaitForText = getResponseWaitBudgetMs(t0, 15000, 'chatgpt-finalize');
|
|
1452
|
+
const maxWaitForText = getResponseWaitBudgetMs(t0, 15000, 'chatgpt-finalize', budgetMs);
|
|
1405
1453
|
const pollInterval = 200;
|
|
1406
1454
|
const waitStart = Date.now();
|
|
1407
1455
|
let hasResponseText = false;
|
|
@@ -1941,7 +1989,7 @@ async function askChatGPTFastInternal(question, debug) {
|
|
|
1941
1989
|
console.error(`[ChatGPT] Response extracted: ${finalAnswer.slice(0, 100)}...`);
|
|
1942
1990
|
const finalUrl = await client.evaluate('location.href');
|
|
1943
1991
|
if (finalUrl && finalUrl.includes('chatgpt.com')) {
|
|
1944
|
-
await saveAgentSession('chatgpt', finalUrl);
|
|
1992
|
+
await saveAgentSession('chatgpt', getBaseUrl('chatgpt', finalUrl));
|
|
1945
1993
|
}
|
|
1946
1994
|
timings.waitResponseMs = nowMs() - tWaitResp;
|
|
1947
1995
|
timings.totalMs = nowMs() - t0;
|
|
@@ -2053,7 +2101,7 @@ async function askChatGPTFastInternal(question, debug) {
|
|
|
2053
2101
|
* Driver経由でChatGPTに質問(実験的)
|
|
2054
2102
|
* 環境変数 CAI_USE_DRIVERS=1 で有効化
|
|
2055
2103
|
*/
|
|
2056
|
-
async function askChatGPTViaDriver(question, debug) {
|
|
2104
|
+
async function askChatGPTViaDriver(question, debug, budgetMs) {
|
|
2057
2105
|
const t0 = nowMs();
|
|
2058
2106
|
const timings = {};
|
|
2059
2107
|
// 接続
|
|
@@ -2082,7 +2130,7 @@ async function askChatGPTViaDriver(question, debug) {
|
|
|
2082
2130
|
timings.sendMs = nowMs() - tSend;
|
|
2083
2131
|
// 応答待機
|
|
2084
2132
|
const tWaitResp = nowMs();
|
|
2085
|
-
const driverWaitBudgetMs = getResponseWaitBudgetMs(t0, RESPONSE_WAIT_MAX_MS, 'chatgpt-driver-response');
|
|
2133
|
+
const driverWaitBudgetMs = getResponseWaitBudgetMs(t0, RESPONSE_WAIT_MAX_MS, 'chatgpt-driver-response', budgetMs);
|
|
2086
2134
|
await driver.waitForResponse({ maxWaitMs: driverWaitBudgetMs });
|
|
2087
2135
|
timings.waitResponseMs = nowMs() - tWaitResp;
|
|
2088
2136
|
// 応答抽出
|
|
@@ -2096,7 +2144,7 @@ async function askChatGPTViaDriver(question, debug) {
|
|
|
2096
2144
|
// セッション保存
|
|
2097
2145
|
const finalUrl = await driver.getCurrentUrl();
|
|
2098
2146
|
if (finalUrl.includes('chatgpt.com')) {
|
|
2099
|
-
await saveAgentSession('chatgpt', finalUrl);
|
|
2147
|
+
await saveAgentSession('chatgpt', getBaseUrl('chatgpt', finalUrl));
|
|
2100
2148
|
}
|
|
2101
2149
|
timings.totalMs = nowMs() - t0;
|
|
2102
2150
|
// 履歴保存
|
|
@@ -2120,7 +2168,7 @@ async function askChatGPTViaDriver(question, debug) {
|
|
|
2120
2168
|
/**
|
|
2121
2169
|
* Driver経由でGeminiに質問(実験的)
|
|
2122
2170
|
*/
|
|
2123
|
-
async function askGeminiViaDriver(question, debug) {
|
|
2171
|
+
async function askGeminiViaDriver(question, debug, budgetMs) {
|
|
2124
2172
|
const t0 = nowMs();
|
|
2125
2173
|
const timings = {};
|
|
2126
2174
|
// 接続
|
|
@@ -2150,7 +2198,7 @@ async function askGeminiViaDriver(question, debug) {
|
|
|
2150
2198
|
timings.sendMs = nowMs() - tSend;
|
|
2151
2199
|
// 応答待機
|
|
2152
2200
|
const tWaitResp = nowMs();
|
|
2153
|
-
const driverWaitBudgetMs = getResponseWaitBudgetMs(t0, RESPONSE_WAIT_MAX_MS, 'gemini-driver-response');
|
|
2201
|
+
const driverWaitBudgetMs = getResponseWaitBudgetMs(t0, RESPONSE_WAIT_MAX_MS, 'gemini-driver-response', budgetMs);
|
|
2154
2202
|
await driver.waitForResponse({ maxWaitMs: driverWaitBudgetMs });
|
|
2155
2203
|
timings.waitResponseMs = nowMs() - tWaitResp;
|
|
2156
2204
|
// 応答抽出
|
|
@@ -2164,7 +2212,7 @@ async function askGeminiViaDriver(question, debug) {
|
|
|
2164
2212
|
// セッション保存
|
|
2165
2213
|
const finalUrl = await driver.getCurrentUrl();
|
|
2166
2214
|
if (finalUrl.includes('gemini.google.com')) {
|
|
2167
|
-
await saveAgentSession('gemini', finalUrl);
|
|
2215
|
+
await saveAgentSession('gemini', getBaseUrl('gemini', finalUrl));
|
|
2168
2216
|
}
|
|
2169
2217
|
timings.totalMs = nowMs() - t0;
|
|
2170
2218
|
// 履歴保存
|
|
@@ -2190,24 +2238,24 @@ const USE_DRIVERS = process.env.CAI_USE_DRIVERS === '1';
|
|
|
2190
2238
|
/**
|
|
2191
2239
|
* ChatGPTに質問して回答を取得(後方互換用)
|
|
2192
2240
|
*/
|
|
2193
|
-
export async function askChatGPTFast(question, debug) {
|
|
2241
|
+
export async function askChatGPTFast(question, debug, budgetMs) {
|
|
2194
2242
|
if (USE_DRIVERS) {
|
|
2195
|
-
const result = await askChatGPTViaDriver(question, debug);
|
|
2243
|
+
const result = await askChatGPTViaDriver(question, debug, budgetMs);
|
|
2196
2244
|
return result.answer;
|
|
2197
2245
|
}
|
|
2198
|
-
const result = await askChatGPTFastInternal(question, debug);
|
|
2246
|
+
const result = await askChatGPTFastInternal(question, debug, budgetMs);
|
|
2199
2247
|
return result.answer;
|
|
2200
2248
|
}
|
|
2201
2249
|
/**
|
|
2202
2250
|
* ChatGPTに質問して回答とタイミング情報を取得
|
|
2203
2251
|
*/
|
|
2204
|
-
export async function askChatGPTFastWithTimings(question, debug) {
|
|
2252
|
+
export async function askChatGPTFastWithTimings(question, debug, budgetMs) {
|
|
2205
2253
|
if (USE_DRIVERS) {
|
|
2206
|
-
return askChatGPTViaDriver(question, debug);
|
|
2254
|
+
return askChatGPTViaDriver(question, debug, budgetMs);
|
|
2207
2255
|
}
|
|
2208
|
-
return askChatGPTFastInternal(question, debug);
|
|
2256
|
+
return askChatGPTFastInternal(question, debug, budgetMs);
|
|
2209
2257
|
}
|
|
2210
|
-
async function askGeminiFastInternal(question, debug) {
|
|
2258
|
+
async function askGeminiFastInternal(question, debug, budgetMs) {
|
|
2211
2259
|
const t0 = nowMs();
|
|
2212
2260
|
const timings = {};
|
|
2213
2261
|
const client = await getClient('gemini');
|
|
@@ -2234,31 +2282,15 @@ async function askGeminiFastInternal(question, debug) {
|
|
|
2234
2282
|
// SPA描画安定化のため追加待機
|
|
2235
2283
|
await new Promise(r => setTimeout(r, 500));
|
|
2236
2284
|
console.error('[Gemini] Waited 500ms for SPA rendering');
|
|
2237
|
-
// 既存チャット(URLにチャットID
|
|
2285
|
+
// 既存チャット(URLにチャットIDが含まれる)の場合、新規チャットへ遷移
|
|
2286
|
+
// 同じ会話に質問を投入すると前回のコンテキストが応答に影響するため
|
|
2238
2287
|
const geminiCurrentUrl = await client.evaluate('location.href');
|
|
2239
|
-
// 既存チャットのURLパターン: /app/xxxxx (チャットID)
|
|
2240
2288
|
const isExistingGeminiChat = /\/app\/[a-zA-Z0-9]+/.test(geminiCurrentUrl);
|
|
2241
2289
|
if (isExistingGeminiChat) {
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
const stuckCheckResult = await checkGeminiStuckState(client);
|
|
2247
|
-
if (stuckCheckResult.isStuck) {
|
|
2248
|
-
console.error(`[Gemini] Existing chat appears stuck (stop button detected for ${stuckCheckResult.waitedMs}ms). Clearing session and retrying.`);
|
|
2249
|
-
// 協調クリーンアップ(RelayServer + Client + Session を一括リセット)
|
|
2250
|
-
await resetConnection('gemini');
|
|
2251
|
-
// エラーを投げて、呼び出し元でリトライを促す
|
|
2252
|
-
throw new Error('GEMINI_STUCK_EXISTING_CHAT: Previous chat appears stuck (stop button visible). Session cleared, please retry.');
|
|
2253
|
-
}
|
|
2254
|
-
}
|
|
2255
|
-
catch (error) {
|
|
2256
|
-
// GEMINI_STUCK_* エラーは再スロー(リトライ用)
|
|
2257
|
-
if (error instanceof Error && error.message.includes('GEMINI_STUCK_')) {
|
|
2258
|
-
throw error;
|
|
2259
|
-
}
|
|
2260
|
-
console.error('[Gemini] No existing messages found, continuing as new chat');
|
|
2261
|
-
}
|
|
2290
|
+
console.error('[Gemini] Existing conversation detected, navigating to new chat...');
|
|
2291
|
+
await navigate(client, 'https://gemini.google.com/');
|
|
2292
|
+
await new Promise(r => setTimeout(r, 500));
|
|
2293
|
+
console.error('[Gemini] New chat page loaded');
|
|
2262
2294
|
}
|
|
2263
2295
|
const tWaitInput = nowMs();
|
|
2264
2296
|
await client.waitForFunction(`!!document.querySelector('[role="textbox"], div[contenteditable="true"], textarea') || !!document.querySelector('a[href*="accounts.google.com"]')`, 15000);
|
|
@@ -2680,7 +2712,7 @@ async function askGeminiFastInternal(question, debug) {
|
|
|
2680
2712
|
const tWaitResp = nowMs();
|
|
2681
2713
|
console.error('[Gemini] Waiting for response completion (polling with diagnostics)...');
|
|
2682
2714
|
// ChatGPT側と同様のポーリングループで応答完了を検出
|
|
2683
|
-
const maxWaitMs = getResponseWaitBudgetMs(t0, RESPONSE_WAIT_MAX_MS, 'gemini-response');
|
|
2715
|
+
const maxWaitMs = getResponseWaitBudgetMs(t0, RESPONSE_WAIT_MAX_MS, 'gemini-response', budgetMs);
|
|
2684
2716
|
const pollIntervalMs = 1000;
|
|
2685
2717
|
const startWait = Date.now();
|
|
2686
2718
|
let lastLoggedState = '';
|
|
@@ -2953,7 +2985,7 @@ async function askGeminiFastInternal(question, debug) {
|
|
|
2953
2985
|
console.error(`[Gemini] Response extracted: ${normalized.slice(0, 100)}...`);
|
|
2954
2986
|
const finalUrl = await client.evaluate('location.href');
|
|
2955
2987
|
if (finalUrl && finalUrl.includes('gemini.google.com')) {
|
|
2956
|
-
await saveAgentSession('gemini', finalUrl);
|
|
2988
|
+
await saveAgentSession('gemini', getBaseUrl('gemini', finalUrl));
|
|
2957
2989
|
}
|
|
2958
2990
|
timings.waitResponseMs = nowMs() - tWaitResp;
|
|
2959
2991
|
timings.totalMs = nowMs() - t0;
|
|
@@ -3054,22 +3086,22 @@ async function askGeminiFastInternal(question, debug) {
|
|
|
3054
3086
|
/**
|
|
3055
3087
|
* Geminiに質問して回答を取得(後方互換用)
|
|
3056
3088
|
*/
|
|
3057
|
-
export async function askGeminiFast(question, debug) {
|
|
3089
|
+
export async function askGeminiFast(question, debug, budgetMs) {
|
|
3058
3090
|
if (USE_DRIVERS) {
|
|
3059
|
-
const result = await askGeminiViaDriver(question, debug);
|
|
3091
|
+
const result = await askGeminiViaDriver(question, debug, budgetMs);
|
|
3060
3092
|
return result.answer;
|
|
3061
3093
|
}
|
|
3062
|
-
const result = await askGeminiFastInternal(question, debug);
|
|
3094
|
+
const result = await askGeminiFastInternal(question, debug, budgetMs);
|
|
3063
3095
|
return result.answer;
|
|
3064
3096
|
}
|
|
3065
3097
|
/**
|
|
3066
3098
|
* Geminiに質問して回答とタイミング情報を取得
|
|
3067
3099
|
*/
|
|
3068
|
-
export async function askGeminiFastWithTimings(question, debug) {
|
|
3100
|
+
export async function askGeminiFastWithTimings(question, debug, budgetMs) {
|
|
3069
3101
|
if (USE_DRIVERS) {
|
|
3070
|
-
return askGeminiViaDriver(question, debug);
|
|
3102
|
+
return askGeminiViaDriver(question, debug, budgetMs);
|
|
3071
3103
|
}
|
|
3072
|
-
return askGeminiFastInternal(question, debug);
|
|
3104
|
+
return askGeminiFastInternal(question, debug, budgetMs);
|
|
3073
3105
|
}
|
|
3074
3106
|
export async function takeCdpSnapshot(kind, options) {
|
|
3075
3107
|
const result = {
|
package/build/src/logger.js
CHANGED
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import fs from 'node:fs';
|
|
7
7
|
import debug from 'debug';
|
|
8
|
-
const
|
|
8
|
+
const cabDebugNamespace = 'cab:log';
|
|
9
9
|
const namespacesToEnable = [
|
|
10
|
-
|
|
10
|
+
cabDebugNamespace,
|
|
11
11
|
...(process.env['DEBUG'] ? [process.env['DEBUG']] : []),
|
|
12
12
|
];
|
|
13
13
|
export function saveLogsToFile(fileName) {
|
|
@@ -24,4 +24,4 @@ export function saveLogsToFile(fileName) {
|
|
|
24
24
|
});
|
|
25
25
|
return logFile;
|
|
26
26
|
}
|
|
27
|
-
export const logger = debug(
|
|
27
|
+
export const logger = debug(cabDebugNamespace);
|