yiyan-browser-agent 1.6.4 → 1.6.6

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 -62
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yiyan-browser-agent",
3
- "version": "1.6.4",
3
+ "version": "1.6.6",
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
@@ -278,57 +278,62 @@ class YiyanBrowser {
278
278
  */
279
279
  async waitForResponse() {
280
280
  const timeout = config.RESPONSE_TIMEOUT;
281
- const stableDelay = config.STABLE_DELAY;
282
281
  const start = Date.now();
283
282
 
284
- // Phase 1: wait for a new message to appear
283
+ // Phase 1: wait for response container to appear
285
284
  const initialCount = await this._getMessageCount();
286
- let appeared = false;
285
+ let appeared = false;
287
286
 
288
287
  for (let i = 0; i < 40; i++) {
289
288
  const count = await this._getMessageCount();
290
- if (count > initialCount) { appeared = true; break; }
289
+ if (count > initialCount) {
290
+ appeared = true;
291
+ break;
292
+ }
291
293
  await this.page.waitForTimeout(200);
292
294
  }
293
295
 
294
296
  if (!appeared) logger.warn('Response may have been delayed — continuing to wait...');
295
297
 
296
- // Phase 2: wait for text to stabilise (with multiple checks)
297
- let lastText = '';
298
- let stableStart = null;
299
- let stableCount = 0; // 连续稳定次数计数
298
+ // Phase 2: wait for completion marker (dialogCardBottom) to appear
300
299
  let dotCount = 0;
300
+ let lastLength = 0;
301
301
 
302
302
  while (Date.now() - start < timeout) {
303
303
  const text = await this._extractLastMessage();
304
+ lastLength = text.length;
304
305
 
305
- if (text !== lastText) {
306
- lastText = text;
307
- stableStart = null;
308
- stableCount = 0; // 内容变化,重置计数
309
- } else if (text.length > 0) {
310
- if (!stableStart) stableStart = Date.now();
311
- else if (Date.now() - stableStart >= stableDelay) {
312
- // 增加稳定性计数
313
- stableCount++;
314
-
315
- // 需要连续稳定检测 + _isGenerating 确认
316
- if (stableCount >= 2) { // 连续 2 次稳定检测
317
- if (!await this._isGenerating()) break;
318
- stableCount = 0; // _isGenerating 说还在生成,重置
319
- stableStart = null;
320
- } else {
321
- // 第一次稳定,继续等待下一次检测
322
- stableStart = null;
306
+ // Progress indicator
307
+ dotCount = (dotCount + 1) % 4;
308
+ logger.thinking(`Receiving response${'.'.repeat(dotCount)} (${lastLength} chars)`);
309
+
310
+ // 检测完成标记:dialogCardBottom 出现
311
+ const hasCompletion = await this.page.evaluate(() => {
312
+ const selectors = [
313
+ '.dialogCardBottom__qoXjps3z',
314
+ '[class*="dialogCardBottom"]',
315
+ '[class*="dialog-bottom"]',
316
+ '[class*="response-footer"]',
317
+ ];
318
+ for (const sel of selectors) {
319
+ const el = document.querySelector(sel);
320
+ if (el) {
321
+ const s = window.getComputedStyle(el);
322
+ if (s.display !== 'none' && s.visibility !== 'hidden') return true;
323
323
  }
324
324
  }
325
- }
325
+ return false;
326
+ });
326
327
 
327
- // Progress indicator
328
- dotCount = (dotCount + 1) % 4;
329
- logger.thinking(`Receiving response${'.'.repeat(dotCount)} (${text.length} chars)`);
328
+ if (hasCompletion) {
329
+ // 完成标记出现,等待一小段时间确保内容完整
330
+ await this.page.waitForTimeout(500);
331
+ logger.clearLine();
332
+ logger.dim('Completion marker detected, finishing...');
333
+ break;
334
+ }
330
335
 
331
- // 等待 200ms 给 DOM 时间更新,避免高频轮询读取不完整内容
336
+ // 等待 200ms 给 DOM 时间更新
332
337
  await this.page.waitForTimeout(200);
333
338
  }
334
339
 
@@ -498,7 +503,7 @@ class YiyanBrowser {
498
503
  '[class*="stop-gen"]',
499
504
  '[class*="stopGen"]',
500
505
  '[class*="generating"]',
501
- '[class*=" Generating"]', // Yiyan 可能的 class
506
+ '[class*=" Generating"]',
502
507
  ];
503
508
  for (const sel of stopSelectors) {
504
509
  const el = document.querySelector(sel);
@@ -519,7 +524,6 @@ class YiyanBrowser {
519
524
  '[class*="thinking"]',
520
525
  'svg[class*="loading"]',
521
526
  'svg[class*="spinner"]',
522
- // Yiyan 特有的加载指示
523
527
  '.loading-indicator',
524
528
  '.generating-indicator',
525
529
  ];
@@ -531,39 +535,18 @@ class YiyanBrowser {
531
535
  }
532
536
  }
533
537
 
534
- // ── 3. 检测输入框状态(生成时通常禁用)──
535
- const inputSelectors = [
536
- '[contenteditable="true"]',
537
- 'textarea',
538
- '[role="textbox"]',
539
- '.editable',
540
- ];
541
- for (const sel of inputSelectors) {
542
- const input = document.querySelector(sel);
543
- if (input) {
544
- // 检查是否禁用
545
- if (input.disabled) return true;
546
- if (input.getAttribute('aria-disabled') === 'true') return true;
547
- if (input.getAttribute('disabled') !== null) return true;
548
-
549
- // 检查是否只读(有时会用 readonly 表示生成中)
550
- if (input.readOnly || input.getAttribute('readonly') !== null) {
551
- // 但要排除本来就是 readonly 的输入框
552
- // 这里暂时不返回 true,需要更多测试
553
- }
554
- }
555
- }
556
-
557
- // ── 4. 检测是否缺少完成标记元素 ──
558
- // 如果没有复制按钮/重新生成按钮,可能还在生成
538
+ // ── 3. 检测是否缺少完成标记元素 ──
539
+ // dialogCardBottom Yiyan 响应完成后的底部操作区域
559
540
  const completionMarkers = [
541
+ '[class*="dialogCardBottom"]', // Yiyan 对话卡片底部
542
+ '.dialogCardBottom__qoXjps3z', // Yiyan 特定 class
560
543
  '[class*="copy-btn"]',
561
544
  '[class*="copyBtn"]',
562
545
  '[aria-label*="Copy" i]',
563
546
  '[aria-label*="复制"]',
564
547
  '[class*="regenerate"]',
565
548
  '[class*="retry"]',
566
- '[class*="action-btn"]', // Yiyan 的操作按钮区域
549
+ '[class*="action-btn"]',
567
550
  ];
568
551
  let hasCompletionMarker = false;
569
552
  for (const sel of completionMarkers) {
@@ -573,12 +556,10 @@ class YiyanBrowser {
573
556
  }
574
557
  }
575
558
 
576
- // 如果有响应内容但没有完成标记 → 可能还在生成
577
- // 这个检测放在后面,避免误判空响应
559
+ // 如果有响应内容但没有完成标记 → 还在生成
578
560
  const answerArea = document.querySelector('[class*="answer"], [class*="response"], [class*="markdown"]');
579
561
  if (answerArea && answerArea.innerText && answerArea.innerText.length > 50) {
580
562
  if (!hasCompletionMarker) {
581
- // 有内容但没有完成按钮,可能还在生成
582
563
  return true;
583
564
  }
584
565
  }