yiyan-browser-agent 1.0.5 → 1.0.7
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 +19 -45
package/package.json
CHANGED
package/src/browser.js
CHANGED
|
@@ -135,10 +135,14 @@ class YiyanBrowser {
|
|
|
135
135
|
|
|
136
136
|
async _navigate(url) {
|
|
137
137
|
try {
|
|
138
|
-
// Wait for network idle
|
|
138
|
+
// Wait for network idle, then extra wait for dynamic content
|
|
139
139
|
await this.page.goto(url, { waitUntil: 'networkidle', timeout: 30_000 });
|
|
140
|
+
// Give React/Vue SPA time to render
|
|
141
|
+
await this.page.waitForTimeout(800);
|
|
140
142
|
} catch (err) {
|
|
141
143
|
logger.warn(`Navigation warning: ${err.message}`);
|
|
144
|
+
// Fallback: longer wait if networkidle fails
|
|
145
|
+
await this.page.waitForTimeout(2000);
|
|
142
146
|
}
|
|
143
147
|
}
|
|
144
148
|
|
|
@@ -149,8 +153,7 @@ class YiyanBrowser {
|
|
|
149
153
|
const el = await this.page.waitForSelector(sel, { timeout: 2_000, state: 'visible' });
|
|
150
154
|
if (el) {
|
|
151
155
|
await el.click();
|
|
152
|
-
|
|
153
|
-
await this.page.waitForLoadState('domcontentloaded', { timeout: 3_000 }).catch(() => {});
|
|
156
|
+
await this.page.waitForTimeout(500);
|
|
154
157
|
logger.dim('Started new chat session');
|
|
155
158
|
return;
|
|
156
159
|
}
|
|
@@ -165,8 +168,9 @@ class YiyanBrowser {
|
|
|
165
168
|
// ── Login handling (optimized) ─────────────────────────────────────────────
|
|
166
169
|
|
|
167
170
|
async _ensureLoggedIn() {
|
|
168
|
-
//
|
|
171
|
+
// Wait for page to be fully interactive
|
|
169
172
|
await this.page.waitForLoadState('domcontentloaded', { timeout: 5_000 }).catch(() => {});
|
|
173
|
+
await this.page.waitForTimeout(500);
|
|
170
174
|
|
|
171
175
|
const needsLogin = await this.page.evaluate(() => {
|
|
172
176
|
const url = window.location.href;
|
|
@@ -186,7 +190,6 @@ class YiyanBrowser {
|
|
|
186
190
|
if (needsLogin) {
|
|
187
191
|
this._printLoginBanner();
|
|
188
192
|
await this._waitForEnter();
|
|
189
|
-
// Wait for navigation after login
|
|
190
193
|
await this.page.waitForNavigation({ waitUntil: 'networkidle', timeout: 30_000 }).catch(() => {});
|
|
191
194
|
}
|
|
192
195
|
}
|
|
@@ -225,51 +228,21 @@ class YiyanBrowser {
|
|
|
225
228
|
});
|
|
226
229
|
}
|
|
227
230
|
|
|
228
|
-
// ── Sending Messages (
|
|
231
|
+
// ── Sending Messages (stable: keyboard.type) ────────────────────────────────
|
|
229
232
|
|
|
230
233
|
async sendMessage(text) {
|
|
231
234
|
const { el } = await this._findInput();
|
|
232
235
|
|
|
233
|
-
// Focus
|
|
234
|
-
await el.
|
|
236
|
+
// Focus and select all existing content
|
|
237
|
+
await el.click({ clickCount: 3, force: true });
|
|
238
|
+
await this.page.waitForTimeout(200);
|
|
235
239
|
|
|
236
|
-
// Clear
|
|
237
|
-
await
|
|
238
|
-
|
|
239
|
-
if (e.innerText) e.innerText = '';
|
|
240
|
-
});
|
|
241
|
-
|
|
242
|
-
// Use clipboard paste for instant input (much faster than typing)
|
|
243
|
-
await this.page.evaluate(async (text) => {
|
|
244
|
-
// Try modern clipboard API first
|
|
245
|
-
try {
|
|
246
|
-
await navigator.clipboard.writeText(text);
|
|
247
|
-
document.execCommand('paste');
|
|
248
|
-
return;
|
|
249
|
-
} catch {}
|
|
250
|
-
|
|
251
|
-
// Fallback: direct DOM manipulation with proper event dispatch
|
|
252
|
-
const activeEl = document.activeElement;
|
|
253
|
-
if (activeEl && activeEl.isContentEditable) {
|
|
254
|
-
activeEl.textContent = text;
|
|
255
|
-
|
|
256
|
-
// Dispatch input event so Yiyan recognizes the content
|
|
257
|
-
const inputEvent = new InputEvent('input', {
|
|
258
|
-
bubbles: true,
|
|
259
|
-
cancelable: true,
|
|
260
|
-
inputType: 'insertText',
|
|
261
|
-
data: text,
|
|
262
|
-
});
|
|
263
|
-
activeEl.dispatchEvent(inputEvent);
|
|
264
|
-
|
|
265
|
-
// Also dispatch change event for good measure
|
|
266
|
-
const changeEvent = new Event('change', { bubbles: true });
|
|
267
|
-
activeEl.dispatchEvent(changeEvent);
|
|
268
|
-
}
|
|
269
|
-
}, text);
|
|
240
|
+
// Clear by pressing Delete
|
|
241
|
+
await this.page.keyboard.press('Delete');
|
|
242
|
+
await this.page.waitForTimeout(100);
|
|
270
243
|
|
|
271
|
-
//
|
|
272
|
-
await this.page.
|
|
244
|
+
// Type text character by character (stable, works reliably)
|
|
245
|
+
await this.page.keyboard.type(text, { delay: 30 });
|
|
273
246
|
|
|
274
247
|
// Press Enter to send
|
|
275
248
|
await this.page.keyboard.press('Enter');
|
|
@@ -278,7 +251,8 @@ class YiyanBrowser {
|
|
|
278
251
|
async _findInput() {
|
|
279
252
|
for (const sel of SEL.chatInput) {
|
|
280
253
|
try {
|
|
281
|
-
|
|
254
|
+
// Increased timeout for initial page load
|
|
255
|
+
const el = await this.page.waitForSelector(sel, { timeout: 8_000, state: 'visible' });
|
|
282
256
|
if (!el) continue;
|
|
283
257
|
const tagName = await el.evaluate(e => e.tagName.toLowerCase());
|
|
284
258
|
const isContentEditable = await el.evaluate(e => e.isContentEditable);
|