@anweat/dsh-browser 0.1.17 → 0.2.0
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 +266 -88
- package/assets/skills/dsh-browser/SKILL.md +120 -0
- package/assets/skills/dsh-browser/references/develop.md +48 -0
- package/assets/skills/dsh-browser/references/observe.md +91 -0
- package/assets/skills/dsh-browser/references/opencli.md +25 -0
- package/assets/skills/dsh-browser/references/recipes.md +149 -0
- package/assets/skills/dsh-browser/references/userscripts.md +44 -0
- package/cordis.patch.yml +11 -3
- package/lib/actions/act.d.ts +3 -0
- package/lib/actions/act.js +147 -0
- package/lib/actions/act.js.map +1 -0
- package/lib/actions/automation.d.ts +3 -0
- package/lib/actions/automation.js +356 -0
- package/lib/actions/automation.js.map +1 -0
- package/lib/actions/crawl.d.ts +3 -0
- package/lib/actions/crawl.js +28 -0
- package/lib/actions/crawl.js.map +1 -0
- package/lib/actions/errors.d.ts +53 -0
- package/lib/actions/errors.js +178 -0
- package/lib/actions/errors.js.map +1 -0
- package/lib/actions/index-view.d.ts +42 -0
- package/lib/actions/index-view.js +268 -0
- package/lib/actions/index-view.js.map +1 -0
- package/lib/actions/inspect.d.ts +3 -0
- package/lib/actions/inspect.js +35 -0
- package/lib/actions/inspect.js.map +1 -0
- package/lib/actions/observe.d.ts +3 -0
- package/lib/actions/observe.js +121 -0
- package/lib/actions/observe.js.map +1 -0
- package/lib/actions/opencli.d.ts +3 -0
- package/lib/actions/opencli.js +51 -0
- package/lib/actions/opencli.js.map +1 -0
- package/lib/actions/registry.d.ts +35 -0
- package/lib/actions/registry.js +89 -0
- package/lib/actions/registry.js.map +1 -0
- package/lib/actions/run.d.ts +34 -0
- package/lib/actions/run.js +226 -0
- package/lib/actions/run.js.map +1 -0
- package/lib/actions/runtime.d.ts +3 -0
- package/lib/actions/runtime.js +33 -0
- package/lib/actions/runtime.js.map +1 -0
- package/lib/actions/schema.d.ts +31 -0
- package/lib/actions/schema.js +309 -0
- package/lib/actions/schema.js.map +1 -0
- package/lib/actions/script.d.ts +3 -0
- package/lib/actions/script.js +97 -0
- package/lib/actions/script.js.map +1 -0
- package/lib/actions/shared.d.ts +31 -0
- package/lib/actions/shared.js +45 -0
- package/lib/actions/shared.js.map +1 -0
- package/lib/actions/surface.d.ts +22 -0
- package/lib/actions/surface.js +18 -0
- package/lib/actions/surface.js.map +1 -0
- package/lib/actions/target.d.ts +3 -0
- package/lib/actions/target.js +66 -0
- package/lib/actions/target.js.map +1 -0
- package/lib/actions/types.d.ts +181 -0
- package/lib/actions/types.js +48 -0
- package/lib/actions/types.js.map +1 -0
- package/lib/activation-rules.d.ts +29 -0
- package/lib/activation-rules.js +33 -0
- package/lib/activation-rules.js.map +1 -0
- package/lib/approval-policy.d.ts +40 -2
- package/lib/approval-policy.js +184 -97
- package/lib/approval-policy.js.map +1 -1
- package/lib/automation-assets-rpc.d.ts +8 -2
- package/lib/automation-assets-rpc.js +68 -10
- package/lib/automation-assets-rpc.js.map +1 -1
- package/lib/automation-assets.d.ts +152 -4
- package/lib/automation-assets.js +255 -15
- package/lib/automation-assets.js.map +1 -1
- package/lib/automation-convert.d.ts +23 -0
- package/lib/automation-convert.js +110 -0
- package/lib/automation-convert.js.map +1 -0
- package/lib/automation-development.d.ts +26 -0
- package/lib/automation-development.js +47 -0
- package/lib/automation-development.js.map +1 -1
- package/lib/automation-execution.d.ts +57 -1
- package/lib/automation-execution.js +167 -11
- package/lib/automation-execution.js.map +1 -1
- package/lib/automation-journal.d.ts +92 -0
- package/lib/automation-journal.js +449 -0
- package/lib/automation-journal.js.map +1 -0
- package/lib/automation-v2.d.ts +138 -0
- package/lib/automation-v2.js +631 -0
- package/lib/automation-v2.js.map +1 -0
- package/lib/automation.d.ts +82 -5
- package/lib/automation.js +239 -82
- package/lib/automation.js.map +1 -1
- package/lib/browser-service.d.ts +309 -32
- package/lib/browser-service.js +636 -182
- package/lib/browser-service.js.map +1 -1
- package/lib/client/SettingsCard.js +95 -57
- package/lib/client/SettingsCard.js.map +1 -1
- package/lib/client/asset-editor.d.ts +55 -0
- package/lib/client/asset-editor.js +101 -0
- package/lib/client/asset-editor.js.map +1 -0
- package/lib/client/automation-assets-client.d.ts +99 -2
- package/lib/client/automation-assets-client.js +243 -10
- package/lib/client/automation-assets-client.js.map +1 -1
- package/lib/client/form.d.ts +48 -4
- package/lib/client/form.js +142 -29
- package/lib/client/form.js.map +1 -1
- package/lib/client/index.d.ts +25 -2
- package/lib/client/index.js +5 -1
- package/lib/client/index.js.map +1 -1
- package/lib/client/locales.d.ts +85 -6
- package/lib/client/locales.js +64 -12
- package/lib/client/locales.js.map +1 -1
- package/lib/client/prompts-form.d.ts +67 -0
- package/lib/client/prompts-form.js +140 -0
- package/lib/client/prompts-form.js.map +1 -0
- package/lib/client/prompts-status-client.d.ts +34 -0
- package/lib/client/prompts-status-client.js +53 -0
- package/lib/client/prompts-status-client.js.map +1 -0
- package/lib/client/settings-namespace.d.ts +1 -1
- package/lib/client/settings-namespace.js +1 -1
- package/lib/client/settings-namespace.js.map +1 -1
- package/lib/client.js +1915 -330
- package/lib/client.js.map +1 -1
- package/lib/config.d.ts +50 -1
- package/lib/config.js +31 -1
- package/lib/config.js.map +1 -1
- package/lib/dialogs.d.ts +37 -0
- package/lib/dialogs.js +73 -0
- package/lib/dialogs.js.map +1 -0
- package/lib/freedom.d.ts +23 -7
- package/lib/freedom.js +48 -59
- package/lib/freedom.js.map +1 -1
- package/lib/index.d.ts +5 -13
- package/lib/index.js +51 -30
- package/lib/index.js.map +1 -1
- package/lib/journal.d.ts +109 -0
- package/lib/journal.js +238 -0
- package/lib/journal.js.map +1 -0
- package/lib/locator.d.ts +82 -0
- package/lib/locator.js +190 -0
- package/lib/locator.js.map +1 -0
- package/lib/observe-script.d.ts +27 -0
- package/lib/observe-script.js +565 -0
- package/lib/observe-script.js.map +1 -0
- package/lib/observe.d.ts +179 -0
- package/lib/observe.js +368 -0
- package/lib/observe.js.map +1 -0
- package/lib/policy-keys.d.ts +30 -0
- package/lib/policy-keys.js +34 -0
- package/lib/policy-keys.js.map +1 -0
- package/lib/prompt-limits.d.ts +30 -0
- package/lib/prompt-limits.js +31 -0
- package/lib/prompt-limits.js.map +1 -0
- package/lib/prompts.d.ts +131 -0
- package/lib/prompts.js +295 -0
- package/lib/prompts.js.map +1 -0
- package/lib/skill.d.ts +100 -0
- package/lib/skill.js +181 -0
- package/lib/skill.js.map +1 -0
- package/lib/tool-defs.d.ts +72 -0
- package/lib/tool-defs.js +67 -0
- package/lib/tool-defs.js.map +1 -0
- package/lib/tools.d.ts +19 -4
- package/lib/tools.js +124 -922
- package/lib/tools.js.map +1 -1
- package/package.json +15 -11
- package/scripts/check-host-rpc.mjs +11 -4
- package/scripts/dump-prompts.mjs +29 -0
- package/scripts/measure-tool-surface.mjs +190 -0
- package/lib/settings-scope.d.ts +0 -56
- package/lib/settings-scope.js +0 -51
- package/lib/settings-scope.js.map +0 -1
package/lib/browser-service.d.ts
CHANGED
|
@@ -20,11 +20,17 @@
|
|
|
20
20
|
*/
|
|
21
21
|
import { type CliResult } from './deps.ts';
|
|
22
22
|
import type { ResolvedConfig } from './config.ts';
|
|
23
|
-
import { type
|
|
23
|
+
import { type ResolvedAuthProfile } from './auth-profiles.ts';
|
|
24
|
+
import { type ResolvedRulePack } from './rule-packs.ts';
|
|
25
|
+
import { type AnyRecipeStep, type RecipeRunResult, type RecipeStepResult } from './automation.ts';
|
|
26
|
+
import type { OutputSpec, Postcondition } from './automation-v2.ts';
|
|
24
27
|
import { type UserscriptValidation } from './scripts.ts';
|
|
25
28
|
import { type AutomationMode } from './freedom.ts';
|
|
26
29
|
import { type OpencliCatalogFilter, type OpencliCatalogItem } from './opencli-catalog.ts';
|
|
27
30
|
import { UsageGovernor } from './usage-policy.ts';
|
|
31
|
+
import { type BrowserTarget } from './locator.ts';
|
|
32
|
+
import { SessionJournal } from './journal.ts';
|
|
33
|
+
import { type ObserveRegion, type ObserveSection } from './observe.ts';
|
|
28
34
|
export interface RenderRule {
|
|
29
35
|
hostname: string;
|
|
30
36
|
contentSelectors: string[];
|
|
@@ -59,9 +65,21 @@ export interface InteractiveState {
|
|
|
59
65
|
url: string;
|
|
60
66
|
title: string;
|
|
61
67
|
text: string;
|
|
68
|
+
/** The session page this state describes (`t1`, `t2`, ...). Absent only when the page is already gone. */
|
|
69
|
+
targetId?: string;
|
|
70
|
+
/**
|
|
71
|
+
* The page's generation when this state was read. It changes whenever the page's main frame navigates
|
|
72
|
+
* (see {@link SessionState.generationClock}); pass it back as `expectGeneration` to refuse acting on a page
|
|
73
|
+
* that moved on since it was observed.
|
|
74
|
+
*/
|
|
75
|
+
generation?: number;
|
|
62
76
|
screenshotPath?: string;
|
|
77
|
+
/** The page the action ran on closed itself (a popup's own close button): url/title/text describe the page the session fell back to, or are empty. */
|
|
78
|
+
closedPage?: true;
|
|
63
79
|
}
|
|
64
|
-
|
|
80
|
+
/** The page state after a recipe, plus what the run did ({@link RecipeRunResult}). */
|
|
81
|
+
export interface RecipeServiceResult extends InteractiveState, RecipeRunResult {
|
|
82
|
+
/** Same array as `completedSteps`; kept for service consumers written before B2. */
|
|
65
83
|
steps: RecipeStepResult[];
|
|
66
84
|
}
|
|
67
85
|
export interface ScriptRunResult {
|
|
@@ -82,21 +100,7 @@ export interface EvaluateResult {
|
|
|
82
100
|
export interface FileUploadResult extends InteractiveState {
|
|
83
101
|
files: string[];
|
|
84
102
|
}
|
|
85
|
-
export
|
|
86
|
-
selector?: string;
|
|
87
|
-
name?: string;
|
|
88
|
-
url?: string;
|
|
89
|
-
}
|
|
90
|
-
export interface BrowserLocatorSpec {
|
|
91
|
-
selector?: string;
|
|
92
|
-
role?: string;
|
|
93
|
-
name?: string;
|
|
94
|
-
text?: string;
|
|
95
|
-
label?: string;
|
|
96
|
-
exact?: boolean;
|
|
97
|
-
frame?: BrowserFrameSpec;
|
|
98
|
-
}
|
|
99
|
-
export type BrowserTarget = string | BrowserLocatorSpec;
|
|
103
|
+
export type { BrowserFrameSpec, BrowserLocatorSpec, BrowserTarget } from './locator.ts';
|
|
100
104
|
export interface BrowserConsoleRecord {
|
|
101
105
|
type: string;
|
|
102
106
|
text: string;
|
|
@@ -157,7 +161,10 @@ export interface BrowserStatus {
|
|
|
157
161
|
opencliInstalled: boolean;
|
|
158
162
|
opencliEntryPath?: string;
|
|
159
163
|
automationMode: AutomationMode;
|
|
164
|
+
/** Tool names registered for the model under the configured toolSurface. */
|
|
160
165
|
exposedTools: string[];
|
|
166
|
+
/** Browser actions (`group.action`) the model can run. */
|
|
167
|
+
exposedActions: string[];
|
|
161
168
|
directInteractionPolicy: 'deny' | 'ask' | 'allow';
|
|
162
169
|
mutatingRecipePolicy: 'deny' | 'ask' | 'allow';
|
|
163
170
|
externalUserscriptPolicy: 'deny' | 'ask' | 'allow';
|
|
@@ -180,25 +187,154 @@ export interface BrowserStatus {
|
|
|
180
187
|
activeUrl?: string;
|
|
181
188
|
activeAuthProfile?: string;
|
|
182
189
|
}
|
|
190
|
+
/**
|
|
191
|
+
* The interactive page state owned by ONE session.
|
|
192
|
+
*
|
|
193
|
+
* A single `BrowserService` instance is provided to every consumer, so before
|
|
194
|
+
* this existed two concurrent sessions shared one `activePage`: whichever
|
|
195
|
+
* session called `target.open` last owned the page, and the other session's
|
|
196
|
+
* `observe.read` / `script.evaluate` / `inspect.console` then operated on a
|
|
197
|
+
* page it never opened — including the other session's cookies and DOM.
|
|
198
|
+
*
|
|
199
|
+
* State is therefore keyed by session. The browser PROCESS stays shared on
|
|
200
|
+
* purpose: launching N Chromium processes costs hundreds of MB each, while one
|
|
201
|
+
* process with N `BrowserContext`s is what Chromium itself does for N profiles
|
|
202
|
+
* and is properly isolated (separate cookies, storage, cache, permissions).
|
|
203
|
+
* "Different tabs" would not be enough — pages in the SAME context share
|
|
204
|
+
* cookies and storage, so each session gets its own context, not just its own
|
|
205
|
+
* page.
|
|
206
|
+
*/
|
|
207
|
+
interface SessionState {
|
|
208
|
+
context?: any;
|
|
209
|
+
/** The ACTIVE page: the one every action targets. Always one of `pages` while set. */
|
|
210
|
+
page?: any;
|
|
211
|
+
/** Every open page of this session's context (the page it opened plus popups), in the order they appeared. */
|
|
212
|
+
pages: SessionPage[];
|
|
213
|
+
/** Counter behind the `t1`, `t2`, ... target ids of this session. */
|
|
214
|
+
nextTarget: number;
|
|
215
|
+
/**
|
|
216
|
+
* Source of page generations. A page takes the next value when it is tracked and again on every main-frame
|
|
217
|
+
* navigation (cross-document, reload, history back/forward, `location` assignment, `pushState`/`replaceState`,
|
|
218
|
+
* hash changes), so values only grow and never repeat inside a session, not even across pages: an
|
|
219
|
+
* `expectGeneration` from one page can never match another page by coincidence. Subframe navigation and
|
|
220
|
+
* DOM re-rendering do not change it.
|
|
221
|
+
*/
|
|
222
|
+
generationClock: number;
|
|
223
|
+
profile?: ResolvedAuthProfile;
|
|
224
|
+
rulePack?: ResolvedRulePack;
|
|
225
|
+
captureConsole: boolean;
|
|
226
|
+
captureNetwork: boolean;
|
|
227
|
+
capturedConsole: BrowserConsoleRecord[];
|
|
228
|
+
capturedRequests: BrowserRequestRecord[];
|
|
229
|
+
/** Monotonic tick of last use, for least-recently-used eviction. */
|
|
230
|
+
lastUsed: number;
|
|
231
|
+
}
|
|
232
|
+
/** One tracked page of a session. */
|
|
233
|
+
interface SessionPage {
|
|
234
|
+
id: string;
|
|
235
|
+
page: any;
|
|
236
|
+
generation: number;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Session key for a tool execution.
|
|
240
|
+
*
|
|
241
|
+
* `ToolExecution.agent` is documented as "the agent on whose behalf the call
|
|
242
|
+
* runs (set by the agent loop)". Two session identities hang off it and BOTH are
|
|
243
|
+
* the session, not the turn:
|
|
244
|
+
*
|
|
245
|
+
* - `agent.session.id` — the live `Agent` face exposes `readonly session:
|
|
246
|
+
* Session`, and `Session.id` is a `SessionId`. This is the path the
|
|
247
|
+
* automation-asset recorder already uses in production, so it is tried first.
|
|
248
|
+
* - `agent.id` — the base `Agent` contract documents `readonly id: SessionId`
|
|
249
|
+
* as "Session-backed Agent identity". Used as a fallback.
|
|
250
|
+
*
|
|
251
|
+
* On DSH 0.2.0-rc.2 both are present and equal (the agent loop documents `id` as the
|
|
252
|
+
* "shared agent/session identity"). `ToolExecution.agent` is typed as the base `Agent`,
|
|
253
|
+
* whose only guaranteed member is `id`, so reading the live face first and the base
|
|
254
|
+
* contract second is a type-level hedge rather than an old-host adaptation.
|
|
255
|
+
*
|
|
256
|
+
* A session therefore keeps ONE page across all of its turns, and two
|
|
257
|
+
* concurrent sessions never share one. Calls carrying no agent at all
|
|
258
|
+
* (automation-asset replays, non-agent dispatchers) land in one shared bucket,
|
|
259
|
+
* which is the pre-existing single-session behaviour rather than a new hazard.
|
|
260
|
+
*/
|
|
261
|
+
export declare function sessionKeyFor(agent: SessionIdentity | undefined): string;
|
|
262
|
+
/** The two shapes a live Agent presents for session identity. */
|
|
263
|
+
export interface SessionIdentity {
|
|
264
|
+
readonly id?: unknown;
|
|
265
|
+
readonly session?: {
|
|
266
|
+
readonly id?: unknown;
|
|
267
|
+
};
|
|
268
|
+
}
|
|
183
269
|
export declare class BrowserService {
|
|
184
270
|
private readonly config;
|
|
185
271
|
private browser;
|
|
186
272
|
private launching?;
|
|
187
|
-
|
|
188
|
-
private
|
|
189
|
-
|
|
190
|
-
private
|
|
273
|
+
/** Per-session interactive state. Replaces the former global activePage. */
|
|
274
|
+
private readonly sessions;
|
|
275
|
+
/** The tracked entry (target id, generation) of every page the service created. */
|
|
276
|
+
private readonly pageEntries;
|
|
277
|
+
private clock;
|
|
191
278
|
private readonly authProfiles;
|
|
192
279
|
private readonly usageGovernor;
|
|
193
280
|
private opencliCatalogCache?;
|
|
194
|
-
|
|
195
|
-
private
|
|
196
|
-
|
|
197
|
-
private
|
|
281
|
+
/** Per-session exploration journals (see src/journal.ts). Released with the session, never written to disk. */
|
|
282
|
+
private readonly journals;
|
|
283
|
+
/** How many sessions may hold a context+page at once before LRU eviction. */
|
|
284
|
+
private readonly sessionLimit;
|
|
198
285
|
constructor(config: ResolvedConfig);
|
|
199
286
|
available(): boolean;
|
|
287
|
+
/**
|
|
288
|
+
* This session's exploration journal, created on first use. It outlives `target.close` (the session is
|
|
289
|
+
* still the same) and is released when the session is evicted or the service closes. A session that never
|
|
290
|
+
* records anything costs nothing: journals are only created by the action dispatcher.
|
|
291
|
+
*/
|
|
292
|
+
journalFor(session: string): SessionJournal;
|
|
293
|
+
/** The active page of a session as `{targetId, generation, url}`, without opening or creating anything. */
|
|
294
|
+
pageStamp(session: string): {
|
|
295
|
+
targetId?: string;
|
|
296
|
+
generation?: number;
|
|
297
|
+
url?: string;
|
|
298
|
+
} | undefined;
|
|
299
|
+
/**
|
|
300
|
+
* Whether the control a fill/type would hit is a secret field (password, one-time code, name that says so).
|
|
301
|
+
* Best effort and quick: any trouble (no page, several matches, a slow page) answers false, and the journal
|
|
302
|
+
* still treats secret-looking values and secret-looking locators as sensitive.
|
|
303
|
+
*/
|
|
304
|
+
inputSensitivity(target: BrowserTarget, opts?: {
|
|
305
|
+
session?: string;
|
|
306
|
+
}): Promise<boolean>;
|
|
307
|
+
/**
|
|
308
|
+
* The state bucket belonging to a tool execution's session.
|
|
309
|
+
*
|
|
310
|
+
* Tools use this for the few operations that act on the bucket itself
|
|
311
|
+
* (`target.close`) rather than passing a key into a method.
|
|
312
|
+
*/
|
|
313
|
+
sessionState(agent: SessionIdentity | undefined): SessionState | undefined;
|
|
200
314
|
private assertEnabled;
|
|
201
315
|
private browserConnected;
|
|
316
|
+
/**
|
|
317
|
+
* The state bucket for one session, created on demand.
|
|
318
|
+
*
|
|
319
|
+
* Eviction is least-recently-used and never touches the caller's own bucket,
|
|
320
|
+
* so a session cannot have its page closed out from under it by a burst of
|
|
321
|
+
* other sessions.
|
|
322
|
+
*/
|
|
323
|
+
private state;
|
|
324
|
+
/**
|
|
325
|
+
* Look up an existing bucket WITHOUT creating one and WITHOUT evicting.
|
|
326
|
+
*
|
|
327
|
+
* Queries (`runtime.status`, `inspect.console`, `inspect.requests`) must go
|
|
328
|
+
* through this, not {@link state}. Creating a bucket for a session that only
|
|
329
|
+
* *asks* a question would both leak a slot and push a live session past the
|
|
330
|
+
* limit, so a read could evict the very page it was trying to describe.
|
|
331
|
+
*/
|
|
332
|
+
private peek;
|
|
333
|
+
/** Close the least-recently-used sessions that exceed the limit. */
|
|
334
|
+
private evictSessions;
|
|
335
|
+
/** Close one session's page+context without persisting its auth state. */
|
|
336
|
+
private disposeState;
|
|
337
|
+
/** Drop all per-session state after a browser-level failure. */
|
|
202
338
|
private clearActiveState;
|
|
203
339
|
private handleBrowserDisconnected;
|
|
204
340
|
private trackBrowser;
|
|
@@ -271,25 +407,65 @@ export declare class BrowserService {
|
|
|
271
407
|
rulePack?: string;
|
|
272
408
|
inputs?: Record<string, string>;
|
|
273
409
|
}): Promise<ScriptRunResult>;
|
|
410
|
+
/**
|
|
411
|
+
* Return the calling session's live page, creating one when needed.
|
|
412
|
+
*
|
|
413
|
+
* `session` is the key from {@link sessionKeyFor}. Every read and write below
|
|
414
|
+
* is confined to that bucket, which is what stops one session from observing
|
|
415
|
+
* or mutating another's page, cookies, console or network log.
|
|
416
|
+
*/
|
|
274
417
|
private ensureActivePage;
|
|
275
|
-
|
|
418
|
+
/**
|
|
419
|
+
* Add a page to the session's list and wire its capture and close handling.
|
|
420
|
+
* Idempotent: the context 'page' event and the explicit call both land here.
|
|
421
|
+
*/
|
|
422
|
+
private trackPage;
|
|
276
423
|
private resetCapture;
|
|
277
424
|
private resolveTarget;
|
|
425
|
+
/**
|
|
426
|
+
* Run an action on a strict locator. More than one match performs nothing and
|
|
427
|
+
* fails with LOCATOR_AMBIGUOUS plus a summary of the first candidates.
|
|
428
|
+
*/
|
|
429
|
+
private onTarget;
|
|
278
430
|
private screenshotFile;
|
|
279
431
|
private captureScreenshot;
|
|
432
|
+
/** `{targetId, generation}` of a tracked page (empty for a page the service does not track). */
|
|
433
|
+
private stamp;
|
|
434
|
+
/**
|
|
435
|
+
* Refuse to act when the page's generation is not the one the caller observed. Nothing has been done yet
|
|
436
|
+
* at this point, so the caller only needs to observe again.
|
|
437
|
+
*/
|
|
438
|
+
private assertGeneration;
|
|
280
439
|
private readState;
|
|
281
440
|
open(url: string, opts?: {
|
|
282
441
|
waitMs?: number;
|
|
283
442
|
authProfile?: string;
|
|
284
443
|
rulePack?: string;
|
|
285
444
|
capture?: readonly ('console' | 'network')[];
|
|
445
|
+
session?: string;
|
|
286
446
|
}): Promise<InteractiveState>;
|
|
287
447
|
click(target: BrowserTarget, opts?: {
|
|
448
|
+
expectGeneration?: number;
|
|
288
449
|
timeoutMs?: number;
|
|
289
450
|
waitMs?: number;
|
|
451
|
+
session?: string;
|
|
290
452
|
}): Promise<InteractiveState>;
|
|
291
453
|
type(target: BrowserTarget, text: string, opts?: {
|
|
454
|
+
expectGeneration?: number;
|
|
455
|
+
timeoutMs?: number;
|
|
456
|
+
session?: string;
|
|
457
|
+
}): Promise<InteractiveState>;
|
|
458
|
+
/** Type key by key (pressSequentially), so per-key handlers fire; unlike `type`, which replaces the whole value. */
|
|
459
|
+
typeKeys(target: BrowserTarget, text: string, opts?: {
|
|
460
|
+
expectGeneration?: number;
|
|
461
|
+
delayMs?: number;
|
|
462
|
+
timeoutMs?: number;
|
|
463
|
+
session?: string;
|
|
464
|
+
}): Promise<InteractiveState>;
|
|
465
|
+
clear(target: BrowserTarget, opts?: {
|
|
466
|
+
expectGeneration?: number;
|
|
292
467
|
timeoutMs?: number;
|
|
468
|
+
session?: string;
|
|
293
469
|
}): Promise<InteractiveState>;
|
|
294
470
|
wait(target: BrowserTarget | undefined, opts?: {
|
|
295
471
|
urlPattern?: string;
|
|
@@ -297,34 +473,95 @@ export declare class BrowserService {
|
|
|
297
473
|
timeMs?: number;
|
|
298
474
|
state?: 'visible' | 'hidden' | 'attached' | 'detached';
|
|
299
475
|
timeoutMs?: number;
|
|
476
|
+
session?: string;
|
|
300
477
|
}): Promise<InteractiveState>;
|
|
301
478
|
press(target: BrowserTarget | undefined, key: string, opts?: {
|
|
479
|
+
expectGeneration?: number;
|
|
302
480
|
timeoutMs?: number;
|
|
481
|
+
session?: string;
|
|
303
482
|
}): Promise<InteractiveState>;
|
|
304
483
|
select(target: BrowserTarget, values: readonly string[], opts?: {
|
|
484
|
+
expectGeneration?: number;
|
|
305
485
|
timeoutMs?: number;
|
|
486
|
+
session?: string;
|
|
306
487
|
}): Promise<InteractiveState>;
|
|
307
488
|
check(target: BrowserTarget, checked?: boolean, opts?: {
|
|
489
|
+
expectGeneration?: number;
|
|
308
490
|
timeoutMs?: number;
|
|
491
|
+
session?: string;
|
|
309
492
|
}): Promise<InteractiveState>;
|
|
310
493
|
hover(target: BrowserTarget, opts?: {
|
|
494
|
+
expectGeneration?: number;
|
|
311
495
|
timeoutMs?: number;
|
|
312
496
|
waitMs?: number;
|
|
497
|
+
session?: string;
|
|
313
498
|
}): Promise<InteractiveState>;
|
|
314
499
|
setFiles(target: BrowserTarget, files: readonly string[], opts?: {
|
|
500
|
+
expectGeneration?: number;
|
|
315
501
|
timeoutMs?: number;
|
|
502
|
+
session?: string;
|
|
316
503
|
}): Promise<FileUploadResult>;
|
|
317
504
|
evaluate(expression: string, opts?: {
|
|
318
505
|
timeoutMs?: number;
|
|
506
|
+
session?: string;
|
|
319
507
|
}): Promise<EvaluateResult>;
|
|
508
|
+
/**
|
|
509
|
+
* The pages this session holds: the one it opened plus any popup that page
|
|
510
|
+
* (or a later one) opened in the same context. Pure query: it never creates
|
|
511
|
+
* a bucket and never changes the active page.
|
|
512
|
+
*/
|
|
513
|
+
listTargets(opts?: {
|
|
514
|
+
session?: string;
|
|
515
|
+
}): Promise<{
|
|
516
|
+
targets: {
|
|
517
|
+
id: string;
|
|
518
|
+
url: string;
|
|
519
|
+
title: string;
|
|
520
|
+
active: boolean;
|
|
521
|
+
generation: number;
|
|
522
|
+
}[];
|
|
523
|
+
}>;
|
|
524
|
+
/** Make one of this session's pages the active page: every later action, read, and screenshot targets it. */
|
|
525
|
+
selectTarget(id: string, opts?: {
|
|
526
|
+
session?: string;
|
|
527
|
+
}): Promise<InteractiveState & {
|
|
528
|
+
id: string;
|
|
529
|
+
}>;
|
|
320
530
|
scroll(deltaY: number, opts?: {
|
|
531
|
+
expectGeneration?: number;
|
|
321
532
|
waitMs?: number;
|
|
533
|
+
session?: string;
|
|
534
|
+
}): Promise<InteractiveState>;
|
|
535
|
+
read(opts?: {
|
|
536
|
+
session?: string;
|
|
322
537
|
}): Promise<InteractiveState>;
|
|
323
|
-
|
|
538
|
+
/**
|
|
539
|
+
* Run a read of the page. If the page navigates under it ("Execution context was destroyed"), the read is
|
|
540
|
+
* tried once more on the new document; if that fails the same way the page is still moving, which is a
|
|
541
|
+
* stale observation (TARGET_STALE), not a failed action. Nothing a read does changes the page.
|
|
542
|
+
*/
|
|
543
|
+
private readingNavigation;
|
|
544
|
+
/**
|
|
545
|
+
* Structured observation of the active page (or of one element's subtree): readable text, controls, links,
|
|
546
|
+
* and tables, each section bounded by `maxItems` and the whole record by `maxBytes` (see src/observe.ts).
|
|
547
|
+
* With only the default `content` section, no scope and no limits it is exactly {@link read}.
|
|
548
|
+
*/
|
|
549
|
+
observe(opts?: {
|
|
550
|
+
sections?: readonly ObserveSection[];
|
|
551
|
+
target?: BrowserTarget;
|
|
552
|
+
region?: ObserveRegion;
|
|
553
|
+
maxItems?: number;
|
|
554
|
+
maxBytes?: number;
|
|
555
|
+
includeValues?: boolean;
|
|
556
|
+
timeoutMs?: number;
|
|
557
|
+
session?: string;
|
|
558
|
+
}): Promise<Record<string, unknown>>;
|
|
559
|
+
private observeOnce;
|
|
324
560
|
consoleMessages(opts?: {
|
|
325
561
|
level?: string;
|
|
326
562
|
limit?: number;
|
|
327
563
|
clear?: boolean;
|
|
564
|
+
session?: string;
|
|
328
565
|
}): {
|
|
329
566
|
enabled: boolean;
|
|
330
567
|
records: BrowserConsoleRecord[];
|
|
@@ -332,21 +569,61 @@ export declare class BrowserService {
|
|
|
332
569
|
networkRequests(opts?: {
|
|
333
570
|
limit?: number;
|
|
334
571
|
clear?: boolean;
|
|
572
|
+
session?: string;
|
|
335
573
|
}): {
|
|
336
574
|
enabled: boolean;
|
|
337
575
|
records: BrowserRequestRecord[];
|
|
338
576
|
};
|
|
339
|
-
screenshot(options?: BrowserScreenshotOptions
|
|
577
|
+
screenshot(options?: BrowserScreenshotOptions & {
|
|
578
|
+
session?: string;
|
|
579
|
+
}): Promise<{
|
|
340
580
|
path: string;
|
|
341
581
|
}>;
|
|
342
|
-
|
|
582
|
+
/**
|
|
583
|
+
* Run a recipe on the session's page.
|
|
584
|
+
*
|
|
585
|
+
* A business failure comes back as a value (`executionStatus`, `failedStep`,
|
|
586
|
+
* `completedSteps`, `effects`), never as an exception; only problems before
|
|
587
|
+
* any step ran (no page, navigation failure, a malformed recipe) throw.
|
|
588
|
+
*
|
|
589
|
+
* Cancelling stops this recipe only: the session page stays open and usable.
|
|
590
|
+
* A step that is already running cannot be interrupted, so the call returns
|
|
591
|
+
* once that step has returned. The caller therefore still holds the session
|
|
592
|
+
* (browser_call is serialized per agent) until the page is quiet again.
|
|
593
|
+
*/
|
|
594
|
+
recipe(steps: readonly AnyRecipeStep[], opts?: {
|
|
343
595
|
url?: string;
|
|
344
596
|
waitMs?: number;
|
|
345
597
|
authProfile?: string;
|
|
346
598
|
rulePack?: string;
|
|
347
599
|
signal?: AbortSignal;
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
600
|
+
session?: string;
|
|
601
|
+
legacyRecipe?: boolean;
|
|
602
|
+
/** 2: strict LocatorSpec steps, goto/clear, postconditions (see src/automation-v2.ts). Default 1. */
|
|
603
|
+
schemaVersion?: 1 | 2;
|
|
604
|
+
postconditions?: readonly Postcondition[];
|
|
605
|
+
outputSchema?: readonly OutputSpec[];
|
|
606
|
+
/** v2 goto may land on these domains. */
|
|
607
|
+
allowedDomains?: readonly string[];
|
|
608
|
+
/** v2 goto may also stay on the origin the recipe started on (inline recipes; stored assets are limited to their domains). */
|
|
609
|
+
gotoSameOrigin?: boolean;
|
|
610
|
+
/** Run in a brand-new BrowserContext (its own cookies and storage) that is closed afterwards; the session's page is not touched. Needs `url`. */
|
|
611
|
+
isolated?: boolean;
|
|
612
|
+
}): Promise<RecipeServiceResult>;
|
|
613
|
+
/** A recipe in its own context: nothing of the caller's session (page, cookies, storage, journal) is shared or changed. */
|
|
614
|
+
private isolatedRecipe;
|
|
615
|
+
private runRecipeOn;
|
|
616
|
+
/**
|
|
617
|
+
* Close one session's page.
|
|
618
|
+
*
|
|
619
|
+
* `session` is the caller's bucket: a tool call closes only the page that
|
|
620
|
+
* session opened. Only a caller with no session (a service consumer outside
|
|
621
|
+
* the agent loop) reaches the shared bucket, which preserves the historical
|
|
622
|
+
* behaviour for those consumers.
|
|
623
|
+
*/
|
|
624
|
+
closePage(session?: SessionState): Promise<void>;
|
|
625
|
+
status(opts?: {
|
|
626
|
+
session?: string;
|
|
627
|
+
}): Promise<BrowserStatus>;
|
|
351
628
|
close(): Promise<void>;
|
|
352
629
|
}
|