yiyan-browser-agent 1.7.9 → 1.8.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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/browser.js +43 -66
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yiyan-browser-agent",
3
- "version": "1.7.9",
3
+ "version": "1.8.1",
4
4
  "description": "AI coding agent powered by Yiyan (文心一言) via browser automation — no API key needed",
5
5
  "main": "src/index.js",
6
6
  "bin": {
package/src/browser.js CHANGED
@@ -297,26 +297,49 @@ class YiyanBrowser {
297
297
  if (!appeared) logger.warn('Response may have been delayed — continuing to wait...');
298
298
 
299
299
  // Phase 2: wait for completion
300
- // 条件: dialogCardBottom 出现 + 连续两次内容稳定
300
+ // 条件: dialogCardBottom 出现 + answer稳定 + 思考区域稳定
301
301
  let lastText = '';
302
+ let lastThinkingText = '';
302
303
  let stableCount = 0;
303
- let lastCheckTime = Date.now(); // 在 Phase 2 开始时重新设置
304
+ let thinkingStableCount = 0;
305
+ let lastCheckTime = Date.now();
304
306
  let dotCount = 0;
305
307
  let hasCompletionMarker = false;
306
308
 
307
309
  while (Date.now() - start < timeout) {
308
310
  const text = await this._extractLastMessage();
309
311
 
310
- // ── 稳定性检测:内容不变则计数 ──
312
+ // ── 思考区域内容检测 ──
313
+ const thinkingInfo = await this.page.evaluate(() => {
314
+ const thinkingEl = document.querySelector('.container__SPpahQHm, [class*="container__SPpah"]');
315
+ if (!thinkingEl) return { text: '', exists: false };
316
+
317
+ const s = window.getComputedStyle(thinkingEl);
318
+ const isVisible = s.display !== 'none' && s.visibility !== 'hidden';
319
+ const text = isVisible ? (thinkingEl.innerText || '') : '';
320
+
321
+ return { text, exists: true };
322
+ });
323
+
324
+ // ── 思考区域稳定性检测 ──
325
+ if (thinkingInfo.text === lastThinkingText && thinkingInfo.text.length > 5) {
326
+ if (Date.now() - lastCheckTime >= stableDelay) {
327
+ thinkingStableCount++;
328
+ logger.dim(`Thinking stable: ${thinkingStableCount}/2 (${thinkingInfo.text.length} chars)`);
329
+ }
330
+ } else if (thinkingInfo.text !== lastThinkingText) {
331
+ lastThinkingText = thinkingInfo.text;
332
+ thinkingStableCount = 0;
333
+ lastCheckTime = Date.now();
334
+ }
335
+
336
+ // ── answer 稳定性检测 ──
311
337
  if (text === lastText && text.length > 50) {
312
- // 内容没变化,检查是否达到稳定时间
313
338
  if (Date.now() - lastCheckTime >= stableDelay) {
314
339
  stableCount++;
315
- lastCheckTime = Date.now();
316
- logger.dim(`Stable count: ${stableCount}/2 (${text.length} chars)`);
340
+ logger.dim(`Answer stable: ${stableCount}/2 (${text.length} chars)`);
317
341
  }
318
- } else {
319
- // 内容变化,重置
342
+ } else if (text !== lastText) {
320
343
  lastText = text;
321
344
  stableCount = 0;
322
345
  lastCheckTime = Date.now();
@@ -344,30 +367,14 @@ class YiyanBrowser {
344
367
  hasCompletionMarker = true;
345
368
  }
346
369
 
347
- // ── 完成判断:标记出现 + 连续两次稳定 + 思考区域已消失 ──
348
- if (hasCompletionMarker && stableCount >= 2) {
349
- // 检查思考区域是否存在且有内容
350
- const thinkingStatus = await this.page.evaluate(() => {
351
- const thinkingEl = document.querySelector('.container__SPpahQHm, [class*="container__SPpah"]');
352
- if (!thinkingEl) return { exists: false, hasContent: false };
353
-
354
- const s = window.getComputedStyle(thinkingEl);
355
- const isVisible = s.display !== 'none' && s.visibility !== 'hidden';
356
- const text = thinkingEl.innerText || '';
357
- const hasContent = text.length > 5;
358
-
359
- return { exists: true, isVisible, hasContent };
360
- });
361
-
362
- // 思考区域存在且可见且有内容 → 还在思考,继续等待
363
- if (thinkingStatus.exists && thinkingStatus.isVisible && thinkingStatus.hasContent) {
364
- stableCount = 0;
365
- lastCheckTime = Date.now();
366
- logger.dim('Thinking in progress, continue waiting...');
367
- continue;
368
- }
370
+ // ── 完成判断 ──
371
+ // 条件1: 标记出现 + answer稳定 + 思考区域稳定
372
+ // 条件2(备用): 两者都稳定达到 4 次(即使没有完成标记)
373
+ const condition1 = hasCompletionMarker && stableCount >= 2 && thinkingStableCount >= 2;
374
+ const condition2 = stableCount >= 4 && thinkingStableCount >= 4;
369
375
 
370
- // 思考区域已消失/不可见/无内容 检查 _isGenerating
376
+ if (condition1 || condition2) {
377
+ // 检查 _isGenerating 作为最终确认
371
378
  if (!await this._isGenerating()) {
372
379
  await this.page.waitForTimeout(500);
373
380
  logger.clearLine();
@@ -376,6 +383,7 @@ class YiyanBrowser {
376
383
  }
377
384
  // _isGenerating 说还在生成,重置计数继续等待
378
385
  stableCount = 0;
386
+ thinkingStableCount = 0;
379
387
  lastCheckTime = Date.now();
380
388
  }
381
389
 
@@ -472,19 +480,7 @@ class YiyanBrowser {
472
480
  return result.trim();
473
481
  }
474
482
 
475
- // ── 先检查思考区域是否有内容 ──
476
- const thinkingEl = document.querySelector('.container__SPpahQHm, [class*="container__SPpah"]');
477
- if (thinkingEl) {
478
- const s = window.getComputedStyle(thinkingEl);
479
- const isVisible = s.display !== 'none' && s.visibility !== 'hidden';
480
- const thinkingText = thinkingEl.innerText || '';
481
- if (isVisible && thinkingText.length > 5) {
482
- // 思考区域有内容,返回空字符串(等待思考完成)
483
- return '';
484
- }
485
- }
486
-
487
- // ── 思考区域无内容,从 answer_text_id 提取 ──
483
+ // ── answer_text_id 提取内容 ──
488
484
  const answerEl = document.querySelector('#answer_text_id');
489
485
  if (answerEl) {
490
486
  return getFullText(answerEl);
@@ -497,26 +493,7 @@ class YiyanBrowser {
497
493
 
498
494
  async _isGenerating() {
499
495
  return await this.page.evaluate(() => {
500
- // ── 1. 检测思考过程区域(最重要)──
501
- const thinkingSelectors = [
502
- '.container__SPpahQHm', // Yiyan 思考过程区域
503
- '[class*="container__SPpah"]',
504
- '[class*="thinking"]',
505
- '[class*="Thinking"]',
506
- '[class*="thought"]',
507
- ];
508
- for (const sel of thinkingSelectors) {
509
- const el = document.querySelector(sel);
510
- if (el) {
511
- const s = window.getComputedStyle(el);
512
- // 元素可见且有内容
513
- if (s.display !== 'none' && s.visibility !== 'hidden' && el.innerText && el.innerText.length > 5) {
514
- return true; // 思考区域有内容,还在生成
515
- }
516
- }
517
- }
518
-
519
- // ── 2. 检测停止按钮/生成状态 UI ──
496
+ // ── 1. 检测停止按钮/生成状态 UI ──
520
497
  const stopSelectors = [
521
498
  'button[aria-label*="Stop" i]',
522
499
  'button[aria-label*="停止"]',
@@ -533,7 +510,7 @@ class YiyanBrowser {
533
510
  }
534
511
  }
535
512
 
536
- // ── 3. 检测加载动画/typing指示器 ──
513
+ // ── 2. 检测加载动画/typing指示器 ──
537
514
  const loaderSelectors = [
538
515
  '[class*="typing"]',
539
516
  '[class*="loading"]',
@@ -555,7 +532,7 @@ class YiyanBrowser {
555
532
  }
556
533
  }
557
534
 
558
- // ── 4. 检测是否缺少完成标记元素 ──
535
+ // ── 3. 检测是否缺少完成标记元素 ──
559
536
  const completionMarkers = [
560
537
  '[class*="dialogCardBottom"]',
561
538
  '.dialogCardBottom__qoXjps3z',