yiyan-browser-agent 1.11.0 → 1.11.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/package.json +1 -1
- package/src/browser.js +52 -40
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "yiyan-browser-agent",
|
|
3
|
-
"version": "1.11.
|
|
3
|
+
"version": "1.11.1",
|
|
4
4
|
"description": "AI coding agent powered by Yiyan (文心一言) via browser automation (chat.baidu.com) — no API key needed. Performance-optimized. Enhanced with comprehensive security.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
package/src/browser.js
CHANGED
|
@@ -320,6 +320,7 @@ class YiyanBrowser {
|
|
|
320
320
|
let lastThinkingText = '';
|
|
321
321
|
let stableCount = 0;
|
|
322
322
|
let lastStableTime = Date.now();
|
|
323
|
+
let textChangedAt = Date.now(); // 文本最后变化时间
|
|
323
324
|
let dotCount = 0;
|
|
324
325
|
let hasCompletionMarker = false;
|
|
325
326
|
|
|
@@ -373,6 +374,7 @@ class YiyanBrowser {
|
|
|
373
374
|
lastText = text;
|
|
374
375
|
stableCount = 0;
|
|
375
376
|
lastStableTime = Date.now();
|
|
377
|
+
textChangedAt = Date.now();
|
|
376
378
|
}
|
|
377
379
|
|
|
378
380
|
// ── 完成标记检测 (chat.baidu.com) ──
|
|
@@ -404,10 +406,12 @@ class YiyanBrowser {
|
|
|
404
406
|
}
|
|
405
407
|
|
|
406
408
|
// ── 完成判断 ──
|
|
407
|
-
// 条件1:
|
|
408
|
-
// 条件2
|
|
409
|
+
// 条件1: 完成标记出现 + 稳定 2 次
|
|
410
|
+
// 条件2: 稳定 3 次(即使没有完成标记)
|
|
411
|
+
// 条件3(兜底): 文本长时间稳定不变(≥5秒),强制认为完成
|
|
409
412
|
const condition1 = hasCompletionMarker && stableCount >= 2;
|
|
410
413
|
const condition2 = stableCount >= 3;
|
|
414
|
+
const longStable = (Date.now() - textChangedAt) >= 5000 && text.length > 0;
|
|
411
415
|
|
|
412
416
|
if (condition1 || condition2) {
|
|
413
417
|
// 检查 _isGenerating 作为最终确认
|
|
@@ -420,6 +424,13 @@ class YiyanBrowser {
|
|
|
420
424
|
// _isGenerating 说还在生成,重置计数继续等待
|
|
421
425
|
stableCount = 0;
|
|
422
426
|
lastStableTime = Date.now();
|
|
427
|
+
} else if (longStable) {
|
|
428
|
+
// 兜底:文本已经 5 秒没变化了,强制完成
|
|
429
|
+
logger.dim('Long stable fallback — text unchanged for 5s, forcing completion');
|
|
430
|
+
await this.page.waitForTimeout(300);
|
|
431
|
+
logger.clearLine();
|
|
432
|
+
logger.success('Response complete (stable timeout)');
|
|
433
|
+
break;
|
|
423
434
|
}
|
|
424
435
|
|
|
425
436
|
// Progress indicator
|
|
@@ -560,33 +571,13 @@ class YiyanBrowser {
|
|
|
560
571
|
|
|
561
572
|
async _isGenerating() {
|
|
562
573
|
return await this.page.evaluate(() => {
|
|
563
|
-
// ── 1.
|
|
564
|
-
const typingSelectors = [
|
|
565
|
-
'.cosd-markdown-content-typingall',
|
|
566
|
-
'.markdown-typing-all',
|
|
567
|
-
'[class*="typing"]',
|
|
568
|
-
'[class*="generating"]',
|
|
569
|
-
'[class*="loading-indicator"]',
|
|
570
|
-
'svg[class*="loading"]',
|
|
571
|
-
'svg[class*="spinner"]',
|
|
572
|
-
'[class*="blink"]',
|
|
573
|
-
'[class*="cursor-blink"]',
|
|
574
|
-
'[class*="pulsing"]',
|
|
575
|
-
];
|
|
576
|
-
for (const sel of typingSelectors) {
|
|
577
|
-
const el = document.querySelector(sel);
|
|
578
|
-
if (el) {
|
|
579
|
-
const s = window.getComputedStyle(el);
|
|
580
|
-
if (s.display !== 'none' && s.visibility !== 'hidden') return true;
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
// ── 2. 检测停止按钮 ──
|
|
574
|
+
// ── 1. 检测停止按钮(最可靠的生成中信号)──
|
|
585
575
|
const stopSelectors = [
|
|
586
576
|
'button[aria-label*="Stop" i]',
|
|
587
577
|
'button[aria-label*="停止"]',
|
|
588
578
|
'[class*="stop-gen"]',
|
|
589
579
|
'[class*="stopGen"]',
|
|
580
|
+
'[class*="stop-btn"]',
|
|
590
581
|
];
|
|
591
582
|
for (const sel of stopSelectors) {
|
|
592
583
|
const el = document.querySelector(sel);
|
|
@@ -596,35 +587,56 @@ class YiyanBrowser {
|
|
|
596
587
|
}
|
|
597
588
|
}
|
|
598
589
|
|
|
599
|
-
// ──
|
|
590
|
+
// ── 2. 检测活跃的 CSS 动画(真正的 loading spinner,不是永久类名)──
|
|
591
|
+
// 只检测 svg 动画元素和明确的 loading 指示器
|
|
592
|
+
const activeAnimSelectors = [
|
|
593
|
+
'svg[class*="loading"]',
|
|
594
|
+
'svg[class*="spinner"]',
|
|
595
|
+
'[class*="loading-indicator"]',
|
|
596
|
+
'[class*="generating-indicator"]',
|
|
597
|
+
];
|
|
598
|
+
for (const sel of activeAnimSelectors) {
|
|
599
|
+
const el = document.querySelector(sel);
|
|
600
|
+
if (el) {
|
|
601
|
+
const s = window.getComputedStyle(el);
|
|
602
|
+
if (s.display !== 'none' && s.visibility !== 'hidden') return true;
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
// ── 3. 如果有完成标记 → 肯定已完成 ──
|
|
600
607
|
const completionMarkers = [
|
|
601
608
|
'.cos-icon.cos-icon-copy',
|
|
602
609
|
'.cos-icon-copy',
|
|
610
|
+
'.feedback-hover-show',
|
|
603
611
|
'.cos-icon.cos-icon-share1',
|
|
604
|
-
'.cos-icon-feedback',
|
|
612
|
+
'.cos-icon.cos-icon-feedback',
|
|
605
613
|
'[class*="copy-btn"]',
|
|
606
|
-
'[class*="copyBtn"]',
|
|
607
614
|
'[aria-label*="Copy" i]',
|
|
608
615
|
'[aria-label*="复制"]',
|
|
609
|
-
'[class*="regenerate"]',
|
|
610
|
-
'[class*="retry"]',
|
|
611
|
-
'[class*="action-btn"]',
|
|
612
|
-
'.feedback-hover-show',
|
|
613
616
|
];
|
|
614
|
-
let hasCompletionMarker = false;
|
|
615
617
|
for (const sel of completionMarkers) {
|
|
616
|
-
if (document.querySelector(sel))
|
|
617
|
-
hasCompletionMarker = true;
|
|
618
|
-
break;
|
|
619
|
-
}
|
|
618
|
+
if (document.querySelector(sel)) return false;
|
|
620
619
|
}
|
|
621
620
|
|
|
622
|
-
//
|
|
621
|
+
// ── 4. 检查是否有光标闪烁(生成中的光标)──
|
|
622
|
+
// 用 getComputedStyle 检测 animation,而不是类名
|
|
623
623
|
const answerArea = document.querySelector(
|
|
624
|
-
'.ai-entry-block.ai-markdown, .answer-container, .cs-answer-container
|
|
624
|
+
'.ai-entry-block.ai-markdown, .answer-container, .cs-answer-container'
|
|
625
625
|
);
|
|
626
|
-
if (answerArea
|
|
627
|
-
|
|
626
|
+
if (answerArea) {
|
|
627
|
+
// 查找最后子元素是否有动画光标
|
|
628
|
+
const lastChild = answerArea.lastElementChild;
|
|
629
|
+
if (lastChild) {
|
|
630
|
+
const s = window.getComputedStyle(lastChild);
|
|
631
|
+
// 如果最后一个元素有活跃的动画 → 还在生成
|
|
632
|
+
if (s.animationName && s.animationName !== 'none' &&
|
|
633
|
+
s.display !== 'none' && s.visibility !== 'hidden') {
|
|
634
|
+
return true;
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
// 有回答内容但没有完成标记 → 可能还在生成
|
|
639
|
+
if (answerArea.innerText && answerArea.innerText.length > 5) {
|
|
628
640
|
return true;
|
|
629
641
|
}
|
|
630
642
|
}
|