@browser_use/pi 0.1.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.
Files changed (85) hide show
  1. package/.env.example +6 -0
  2. package/LICENSE +21 -0
  3. package/README.md +68 -0
  4. package/dist/agent.d.ts +15 -0
  5. package/dist/agent.js +381 -0
  6. package/dist/agent.js.map +1 -0
  7. package/dist/browser.d.ts +52 -0
  8. package/dist/browser.js +264 -0
  9. package/dist/browser.js.map +1 -0
  10. package/dist/cdp.d.ts +39 -0
  11. package/dist/cdp.js +291 -0
  12. package/dist/cdp.js.map +1 -0
  13. package/dist/context.d.ts +24 -0
  14. package/dist/context.js +143 -0
  15. package/dist/context.js.map +1 -0
  16. package/dist/control.d.ts +18 -0
  17. package/dist/control.js +84 -0
  18. package/dist/control.js.map +1 -0
  19. package/dist/events.d.ts +40 -0
  20. package/dist/events.js +79 -0
  21. package/dist/events.js.map +1 -0
  22. package/dist/highlight.d.ts +3 -0
  23. package/dist/highlight.js +102 -0
  24. package/dist/highlight.js.map +1 -0
  25. package/dist/history.d.ts +22 -0
  26. package/dist/history.js +126 -0
  27. package/dist/history.js.map +1 -0
  28. package/dist/images.d.ts +14 -0
  29. package/dist/images.js +104 -0
  30. package/dist/images.js.map +1 -0
  31. package/dist/index.d.ts +77 -0
  32. package/dist/index.js +422 -0
  33. package/dist/index.js.map +1 -0
  34. package/dist/model-stream.d.ts +3 -0
  35. package/dist/model-stream.js +78 -0
  36. package/dist/model-stream.js.map +1 -0
  37. package/dist/observer.d.ts +16 -0
  38. package/dist/observer.js +56 -0
  39. package/dist/observer.js.map +1 -0
  40. package/dist/page.d.ts +58 -0
  41. package/dist/page.js +189 -0
  42. package/dist/page.js.map +1 -0
  43. package/dist/policy.d.ts +18 -0
  44. package/dist/policy.js +195 -0
  45. package/dist/policy.js.map +1 -0
  46. package/dist/prompt.d.ts +1 -0
  47. package/dist/prompt.js +41 -0
  48. package/dist/prompt.js.map +1 -0
  49. package/dist/protocol.d.ts +70 -0
  50. package/dist/protocol.js +7 -0
  51. package/dist/protocol.js.map +1 -0
  52. package/dist/recording.d.ts +44 -0
  53. package/dist/recording.js +120 -0
  54. package/dist/recording.js.map +1 -0
  55. package/dist/research-tools.d.ts +3 -0
  56. package/dist/research-tools.js +67 -0
  57. package/dist/research-tools.js.map +1 -0
  58. package/dist/runtime.d.ts +39 -0
  59. package/dist/runtime.js +268 -0
  60. package/dist/runtime.js.map +1 -0
  61. package/dist/server.d.ts +2 -0
  62. package/dist/server.js +251 -0
  63. package/dist/server.js.map +1 -0
  64. package/dist/telemetry.d.ts +3 -0
  65. package/dist/telemetry.js +41 -0
  66. package/dist/telemetry.js.map +1 -0
  67. package/dist/types.d.ts +93 -0
  68. package/dist/types.js +2 -0
  69. package/dist/types.js.map +1 -0
  70. package/dist/video.d.ts +18 -0
  71. package/dist/video.js +177 -0
  72. package/dist/video.js.map +1 -0
  73. package/dist/worker.d.ts +1 -0
  74. package/dist/worker.js +329 -0
  75. package/dist/worker.js.map +1 -0
  76. package/examples/README.md +58 -0
  77. package/examples/apply-to-job.ts +57 -0
  78. package/examples/ehr.ts +53 -0
  79. package/examples/extract.ts +50 -0
  80. package/examples/form.ts +36 -0
  81. package/examples/onepassword.ts +66 -0
  82. package/examples/qa.ts +72 -0
  83. package/examples/research.ts +35 -0
  84. package/examples/stripe-link.ts +166 -0
  85. package/package.json +66 -0
package/dist/index.js ADDED
@@ -0,0 +1,422 @@
1
+ import { mkdir, mkdtemp, open } from 'node:fs/promises';
2
+ import { tmpdir } from 'node:os';
3
+ import { join, resolve } from 'node:path';
4
+ import { builtinModels } from '@earendil-works/pi-ai/providers/all';
5
+ import { randomUUID } from 'node:crypto';
6
+ import { Type } from 'typebox';
7
+ import { navigationPolicy, validateSensitiveData } from './policy.js';
8
+ import { telemetry } from './telemetry.js';
9
+ import { openBrowser } from './browser.js';
10
+ import { BrowserRuntime, workerExecutable } from './runtime.js';
11
+ import { runAgent, zeroUsage } from './agent.js';
12
+ import { Recorder } from './recording.js';
13
+ import { RunControl } from './control.js';
14
+ import { loadHistory, saveHistory, workspaceFiles, redact, } from './history.js';
15
+ import { EventStream, formatEvent } from './events.js';
16
+ import { positiveInteger } from './protocol.js';
17
+ export { Browser } from './browser.js';
18
+ export { CellError } from './runtime.js';
19
+ export { Type } from 'typebox';
20
+ export { builtinModels } from '@earendil-works/pi-ai/providers/all';
21
+ /** One browser, workspace and JavaScript namespace. run() resets context; followUp() retains it. */
22
+ export class BrowserUse {
23
+ config;
24
+ model;
25
+ runtime;
26
+ browser;
27
+ workspace;
28
+ reportRun;
29
+ active = false;
30
+ closed = false;
31
+ controller;
32
+ closing;
33
+ messages = [];
34
+ totalUsage = zeroUsage();
35
+ runs = 0;
36
+ control;
37
+ streams = new Set();
38
+ sequence = 0;
39
+ activeRun;
40
+ manualCell;
41
+ runId = '';
42
+ hasConversation = false;
43
+ constructor(config, model, runtime, browser, workspace) {
44
+ this.config = config;
45
+ this.model = model;
46
+ this.runtime = runtime;
47
+ this.browser = browser;
48
+ this.workspace = workspace;
49
+ this.reportRun = telemetry(config.telemetry, config.browser);
50
+ }
51
+ static async create(options) {
52
+ if (options.telemetry !== undefined && typeof options.telemetry !== 'boolean')
53
+ throw new Error('telemetry must be boolean.');
54
+ navigationPolicy(options);
55
+ validateSensitiveData(options.sensitiveData);
56
+ options = {
57
+ ...options,
58
+ redact: [
59
+ ...(options.redact ?? []),
60
+ ...Object.values(options.sensitiveData ?? {}).map((secret) => secret.value),
61
+ ],
62
+ };
63
+ if (options.highlightActions !== undefined && typeof options.highlightActions !== 'boolean')
64
+ throw new Error('highlightActions must be boolean.');
65
+ if (options.researchTools !== undefined && typeof options.researchTools !== 'boolean')
66
+ throw new Error('researchTools must be boolean.');
67
+ if (options.recording && typeof options.recording === 'object') {
68
+ positiveInteger('recording.intervalMs', options.recording.intervalMs ?? 750);
69
+ positiveInteger('recording.maxFrames', options.recording.maxFrames ?? 400);
70
+ if ((options.recording.intervalMs ?? 750) < 100 ||
71
+ (options.recording.maxFrames ?? 400) > 10000)
72
+ throw new Error('Recording requires intervalMs >= 100 and maxFrames <= 10000.');
73
+ }
74
+ const restored = options.historyFile
75
+ ? await loadHistory(options.historyFile, options.model)
76
+ : undefined;
77
+ positiveInteger('hookTimeoutMs', options.hookTimeoutMs ?? 30_000);
78
+ positiveInteger('modelTimeoutMs', options.modelTimeoutMs ?? 300_000);
79
+ positiveInteger('compactionTimeoutMs', options.compactionTimeoutMs ?? 120_000);
80
+ const separator = options.model.indexOf('/');
81
+ if (separator < 1)
82
+ throw new Error('model must be provider/model, for example openai/gpt-5.4.');
83
+ const models = options.models ?? builtinModels();
84
+ const provider = options.model.slice(0, separator);
85
+ const resolvedModel = models.getModel(provider, options.model.slice(separator + 1));
86
+ // Pi 0.85.1 sends configuration_update via Messages, which OpenRouter Opus 5 rejects.
87
+ // Keep caller-supplied model collections untouched. Remove when upstream fixes routing.
88
+ const model = !options.models && options.model === 'openrouter/anthropic/claude-opus-5' && resolvedModel
89
+ ? {
90
+ ...resolvedModel,
91
+ api: 'openai-completions',
92
+ baseUrl: 'https://openrouter.ai/api/v1',
93
+ }
94
+ : resolvedModel;
95
+ if (!model)
96
+ throw new Error(`Unknown model ${options.model}. Supply a Pi models collection with this model registered.`);
97
+ const names = new Set([
98
+ 'javascript',
99
+ 'finish',
100
+ 'finish_from_js',
101
+ ...(options.researchTools ? ['read', 'write', 'edit', 'bash'] : []),
102
+ ]);
103
+ for (const tool of options.tools ?? []) {
104
+ if (names.has(tool.name))
105
+ throw new Error(`Duplicate or reserved tool name: ${tool.name}`);
106
+ names.add(tool.name);
107
+ }
108
+ const operationTimeoutMs = positiveInteger('operationTimeoutMs', options.operationTimeoutMs ?? 15_000);
109
+ positiveInteger('cellTimeoutMs', options.cellTimeoutMs ?? 30_000);
110
+ const maxOutputChars = positiveInteger('maxOutputChars', options.maxOutputChars ?? 12_000);
111
+ const executable = await workerExecutable(); // Fail before launching or provisioning a browser.
112
+ const workspace = options.workspace
113
+ ? resolve(options.workspace)
114
+ : await mkdtemp(join(tmpdir(), 'browser-use-artifacts-'));
115
+ await mkdir(workspace, { recursive: true });
116
+ const browser = await openBrowser(options.browser);
117
+ const runtime = new BrowserRuntime({
118
+ endpoint: browser.endpoint,
119
+ ...(options.allowedDomains !== undefined ? { allowedDomains: options.allowedDomains } : {}),
120
+ ...(options.prohibitedDomains !== undefined
121
+ ? { prohibitedDomains: options.prohibitedDomains }
122
+ : {}),
123
+ ...(options.sensitiveData ? { sensitiveData: options.sensitiveData } : {}),
124
+ ...(options.redact ? { redact: options.redact } : {}),
125
+ approveConnection: options.browser?.kind === 'chrome' && !!options.browser.approveConnection,
126
+ recording: !!options.recording,
127
+ highlightActions: !!options.highlightActions,
128
+ ...(options.browser && 'targetId' in options.browser && options.browser.targetId
129
+ ? { targetId: options.browser.targetId }
130
+ : {}),
131
+ workspace,
132
+ operationTimeoutMs,
133
+ maxOutputChars,
134
+ }, executable);
135
+ const config = { ...options, streamFn: options.streamFn ?? models.streamSimple.bind(models) };
136
+ const instance = new BrowserUse(config, model, runtime, browser, workspace);
137
+ if (restored) {
138
+ instance.messages = restored.messages;
139
+ instance.totalUsage = restored.usage;
140
+ instance.runs = restored.runs;
141
+ instance.hasConversation = true;
142
+ instance.messages.push({
143
+ role: 'user',
144
+ content: 'This conversation was restored from disk. JavaScript bindings and connections were reset. Inspect browser state and workspace before continuing. Never replay uncertain actions automatically.',
145
+ timestamp: Date.now(),
146
+ });
147
+ }
148
+ return instance;
149
+ }
150
+ async run(task, options = {}) {
151
+ return this.startRun(task, options, false);
152
+ }
153
+ async followUp(task, options = {}) {
154
+ if (!this.hasConversation)
155
+ throw new Error('Run a task or restore history before followUp().');
156
+ return this.startRun(task, options, true);
157
+ }
158
+ startRun(task, options, followUp) {
159
+ this.assertIdle();
160
+ if (!task.trim())
161
+ throw new Error('Provide a nonempty task.');
162
+ this.active = true;
163
+ if (!followUp)
164
+ this.messages = [];
165
+ this.runId = randomUUID();
166
+ this.controller = new AbortController();
167
+ this.control = new RunControl((paused) => this.emit({ type: paused ? 'paused' : 'resumed' }));
168
+ this.activeRun = this.performRun(task, options, followUp);
169
+ return this.activeRun;
170
+ }
171
+ async performRun(task, options, followUp) {
172
+ const controller = this.controller;
173
+ const control = this.control;
174
+ const signal = options.signal
175
+ ? AbortSignal.any([options.signal, controller.signal])
176
+ : controller.signal;
177
+ const directory = join(this.workspace, '.browser-use', 'runs');
178
+ const historyPath = join(directory, `${this.runId}.json`);
179
+ const eventsPath = join(directory, `${this.runId}.jsonl`);
180
+ let recorder;
181
+ let journal;
182
+ try {
183
+ await mkdir(directory, { recursive: true, mode: 0o700 });
184
+ journal = await open(eventsPath, 'wx', 0o600);
185
+ const record = async (data) => {
186
+ const event = this.emit(data);
187
+ // Deltas stream live. Persist finalized messages, not a full transcript for every token.
188
+ if (data.type === 'agent_event' &&
189
+ ['message_update', 'agent_end'].includes(data.event.type))
190
+ return;
191
+ const serialized = JSON.stringify(event, (key, value) => key === 'data' && typeof value === 'string' && value.length > 10000
192
+ ? '[image omitted from event log]'
193
+ : value);
194
+ await journal.writeFile(serialized.length > 256000
195
+ ? JSON.stringify({
196
+ sequence: event.sequence,
197
+ timestamp: event.timestamp,
198
+ runId: event.runId,
199
+ type: event.type,
200
+ truncated: true,
201
+ }) + '\n'
202
+ : serialized + '\n');
203
+ };
204
+ await record({ type: 'run_start', task, followUp });
205
+ if (this.config.recording && !signal.aborted) {
206
+ recorder = new Recorder(join(this.workspace, '.browser-use', 'recordings', this.runId), task, typeof this.config.recording === 'object' ? this.config.recording : {});
207
+ try {
208
+ const targetId = await this.runtime.initialize(signal);
209
+ await recorder.start(this.browser.endpoint, targetId, this.config.browser?.kind === 'chrome' && !!this.config.browser.approveConnection);
210
+ this.runtime.onAction = (action) => recorder?.action(action);
211
+ }
212
+ catch (error) {
213
+ await record({ type: 'warning', message: `Recording unavailable: ${String(error)}` });
214
+ }
215
+ }
216
+ const result = await runAgent(this.runtime, this.model, this.config, this.workspace, task, options.schema ?? Type.String(), {
217
+ ...options,
218
+ signal,
219
+ onEvent: async (event, eventSignal) => {
220
+ await record({ type: 'agent_event', event });
221
+ await options.onEvent?.(event, eventSignal);
222
+ },
223
+ }, {
224
+ messages: this.messages,
225
+ control,
226
+ eventsPath,
227
+ save: (messages) => {
228
+ this.messages = messages;
229
+ this.hasConversation = true;
230
+ },
231
+ });
232
+ this.runs++;
233
+ for (const key of ['input', 'output', 'cacheRead', 'cacheWrite', 'totalTokens'])
234
+ this.totalUsage[key] += result.usage[key];
235
+ for (const key of ['input', 'output', 'cacheRead', 'cacheWrite', 'total'])
236
+ this.totalUsage.cost[key] += result.usage.cost[key];
237
+ this.runtime.onAction = undefined;
238
+ const warnings = [...(result.warnings ?? [])];
239
+ let recordingPath;
240
+ if (recorder) {
241
+ try {
242
+ recordingPath = await recorder.stop(result.status, this.runtime.currentTarget);
243
+ }
244
+ catch (error) {
245
+ warnings.push(`Recording could not be saved: ${String(error)}`);
246
+ }
247
+ }
248
+ recorder = undefined;
249
+ const delivered = {
250
+ ...result,
251
+ ...(recordingPath ? { recordingPath } : {}),
252
+ runId: this.runId,
253
+ eventsPath,
254
+ };
255
+ try {
256
+ await saveHistory(historyPath, this.history, this.config.redact);
257
+ delivered.historyPath = historyPath;
258
+ }
259
+ catch (error) {
260
+ warnings.push(`History could not be saved: ${String(error)}`);
261
+ }
262
+ if (warnings.length)
263
+ delivered.warnings = warnings;
264
+ try {
265
+ await record({ type: 'run_end', result: delivered });
266
+ }
267
+ catch (error) {
268
+ delivered.warnings = [
269
+ ...(delivered.warnings ?? []),
270
+ `Event log could not be finalized: ${String(error)}`,
271
+ ];
272
+ }
273
+ this.reportRun(delivered);
274
+ return redact(delivered, this.config.redact ?? []);
275
+ }
276
+ finally {
277
+ this.runtime.onAction = undefined;
278
+ await this.manualCell?.catch(() => { });
279
+ if (recorder)
280
+ await recorder.stop('error', this.runtime.currentTarget).catch(() => { });
281
+ try {
282
+ await journal?.close();
283
+ }
284
+ finally {
285
+ control.finish();
286
+ this.active = false;
287
+ this.controller = undefined;
288
+ this.control = undefined;
289
+ }
290
+ }
291
+ }
292
+ emit(data) {
293
+ const event = redact({ ...data, sequence: ++this.sequence, timestamp: Date.now(), runId: this.runId }, this.config.redact ?? []);
294
+ for (const stream of this.streams)
295
+ stream.push(event);
296
+ const line = this.config.log === 'json'
297
+ ? JSON.stringify(event)
298
+ : this.config.log === 'pretty'
299
+ ? formatEvent(event)
300
+ : undefined;
301
+ if (line)
302
+ process.stderr.write(line + '\n');
303
+ return event;
304
+ }
305
+ /** Subscribe before starting work. Iterators finish when the session closes. */
306
+ events() {
307
+ if (this.closed)
308
+ throw new Error('BrowserUse is closed.');
309
+ const stream = new EventStream(() => this.streams.delete(stream));
310
+ this.streams.add(stream);
311
+ return stream;
312
+ }
313
+ get history() {
314
+ return redact({
315
+ version: 1,
316
+ model: this.config.model,
317
+ messages: this.messages,
318
+ usage: this.totalUsage,
319
+ runs: this.runs,
320
+ }, this.config.redact ?? []);
321
+ }
322
+ get usage() {
323
+ return structuredClone(this.totalUsage);
324
+ }
325
+ get isPaused() {
326
+ return this.control?.paused ?? false;
327
+ }
328
+ files() {
329
+ return workspaceFiles(this.workspace);
330
+ }
331
+ async saveHistory(path = join(this.workspace, '.browser-use', 'session.json')) {
332
+ this.assertIdle();
333
+ await saveHistory(path, this.history, this.config.redact);
334
+ return path;
335
+ }
336
+ pause() {
337
+ if (!this.control)
338
+ throw new Error('No active run to pause.');
339
+ return this.control.pause();
340
+ }
341
+ async resume() {
342
+ await this.manualCell?.catch(() => { });
343
+ this.control?.resume();
344
+ }
345
+ steer(text) {
346
+ if (!text.trim())
347
+ throw new Error('Provide nonempty steering text.');
348
+ if (!this.control?.steer)
349
+ throw new Error('No active agent to steer; use followUp() after a run.');
350
+ this.control.steer(text);
351
+ }
352
+ cancel() {
353
+ this.controller?.abort();
354
+ this.control?.resume();
355
+ }
356
+ /** Direct browser code. Use the same page and variables as the agent. */
357
+ async execute(code, options = {}) {
358
+ const duringPause = this.isPaused;
359
+ if (!duringPause)
360
+ this.assertIdle();
361
+ if (this.closed)
362
+ throw new Error('BrowserUse is closed.');
363
+ if (duringPause && this.manualCell)
364
+ throw new Error('A manual browser cell is already running.');
365
+ if (!duringPause)
366
+ this.active = true;
367
+ try {
368
+ const signal = duringPause && this.controller
369
+ ? options.signal
370
+ ? AbortSignal.any([options.signal, this.controller.signal])
371
+ : this.controller.signal
372
+ : options.signal;
373
+ const cell = this.runtime.execute(code, options.timeoutMs ?? this.config.cellTimeoutMs ?? 30_000, signal);
374
+ if (duringPause)
375
+ this.manualCell = cell;
376
+ return await cell;
377
+ }
378
+ finally {
379
+ if (duringPause)
380
+ this.manualCell = undefined;
381
+ else
382
+ this.active = false;
383
+ }
384
+ }
385
+ assertIdle() {
386
+ if (this.closed)
387
+ throw new Error('BrowserUse is closed. Create a new session.');
388
+ if (this.active)
389
+ throw new Error('This session is busy. Await the active operation or create a separate session.');
390
+ }
391
+ /** Idempotent. Cancels execution, closes our tab, and shuts down only browsers we launched. */
392
+ close() {
393
+ if (this.closing)
394
+ return this.closing;
395
+ this.closed = true;
396
+ this.cancel();
397
+ this.closing = (async () => {
398
+ try {
399
+ await this.activeRun?.catch(() => { });
400
+ await this.runtime.close();
401
+ }
402
+ finally {
403
+ try {
404
+ await this.browser.close();
405
+ }
406
+ finally {
407
+ for (const stream of [...this.streams])
408
+ stream.end();
409
+ }
410
+ }
411
+ })();
412
+ return this.closing;
413
+ }
414
+ async [Symbol.asyncDispose]() {
415
+ await this.close();
416
+ }
417
+ }
418
+ export { CDP } from './cdp.js';
419
+ export { Page, Tabs } from './page.js';
420
+ export { formatEvent } from './events.js';
421
+ export { exportRecording } from './video.js';
422
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGzC,OAAO,EAAE,IAAI,EAA6B,MAAM,SAAS,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACtE,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EACL,WAAW,EACX,WAAW,EACX,cAAc,EACd,MAAM,GAEP,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,WAAW,EAAE,WAAW,EAA4C,MAAM,aAAa,CAAC;AACjG,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAIhD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAQvC,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,OAAO,EAAE,IAAI,EAA6B,MAAM,SAAS,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AAEpE,oGAAoG;AACpG,MAAM,OAAO,UAAU;IAkBF;IACA;IACA;IACA;IACR;IArBM,SAAS,CAA+B;IACjD,MAAM,GAAG,KAAK,CAAC;IACf,MAAM,GAAG,KAAK,CAAC;IACf,UAAU,CAA8B;IACxC,OAAO,CAA4B;IACnC,QAAQ,GAAmB,EAAE,CAAC;IAC9B,UAAU,GAAG,SAAS,EAAE,CAAC;IACzB,IAAI,GAAG,CAAC,CAAC;IACT,OAAO,CAAyB;IAChC,OAAO,GAAG,IAAI,GAAG,EAAe,CAAC;IACjC,QAAQ,GAAG,CAAC,CAAC;IACb,SAAS,CAA0C;IACnD,UAAU,CAA+B;IACzC,KAAK,GAAG,EAAE,CAAC;IACX,eAAe,GAAG,KAAK,CAAC;IAEhC,YACmB,MAAkD,EAClD,KAAiB,EACjB,OAAuB,EACvB,OAAgD,EACxD,SAAiB;QAJT,WAAM,GAAN,MAAM,CAA4C;QAClD,UAAK,GAAL,KAAK,CAAY;QACjB,YAAO,GAAP,OAAO,CAAgB;QACvB,YAAO,GAAP,OAAO,CAAyC;QACxD,cAAS,GAAT,SAAS,CAAQ;QAE1B,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IAC/D,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAA0B;QAC5C,IAAI,OAAO,CAAC,SAAS,KAAK,SAAS,IAAI,OAAO,OAAO,CAAC,SAAS,KAAK,SAAS;YAC3E,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAChD,gBAAgB,CAAC,OAAO,CAAC,CAAC;QAC1B,qBAAqB,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;QAC7C,OAAO,GAAG;YACR,GAAG,OAAO;YACV,MAAM,EAAE;gBACN,GAAG,CAAC,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC;gBACzB,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,aAAa,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC;aAC5E;SACF,CAAC;QACF,IAAI,OAAO,CAAC,gBAAgB,KAAK,SAAS,IAAI,OAAO,OAAO,CAAC,gBAAgB,KAAK,SAAS;YACzF,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;QACvD,IAAI,OAAO,CAAC,aAAa,KAAK,SAAS,IAAI,OAAO,OAAO,CAAC,aAAa,KAAK,SAAS;YACnF,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;QACpD,IAAI,OAAO,CAAC,SAAS,IAAI,OAAO,OAAO,CAAC,SAAS,KAAK,QAAQ,EAAE,CAAC;YAC/D,eAAe,CAAC,sBAAsB,EAAE,OAAO,CAAC,SAAS,CAAC,UAAU,IAAI,GAAG,CAAC,CAAC;YAC7E,eAAe,CAAC,qBAAqB,EAAE,OAAO,CAAC,SAAS,CAAC,SAAS,IAAI,GAAG,CAAC,CAAC;YAC3E,IACE,CAAC,OAAO,CAAC,SAAS,CAAC,UAAU,IAAI,GAAG,CAAC,GAAG,GAAG;gBAC3C,CAAC,OAAO,CAAC,SAAS,CAAC,SAAS,IAAI,GAAG,CAAC,GAAG,KAAK;gBAE5C,MAAM,IAAI,KAAK,CAAC,8DAA8D,CAAC,CAAC;QACpF,CAAC;QACD,MAAM,QAAQ,GAAG,OAAO,CAAC,WAAW;YAClC,CAAC,CAAC,MAAM,WAAW,CAAC,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,KAAK,CAAC;YACvD,CAAC,CAAC,SAAS,CAAC;QACd,eAAe,CAAC,eAAe,EAAE,OAAO,CAAC,aAAa,IAAI,MAAM,CAAC,CAAC;QAClE,eAAe,CAAC,gBAAgB,EAAE,OAAO,CAAC,cAAc,IAAI,OAAO,CAAC,CAAC;QACrE,eAAe,CAAC,qBAAqB,EAAE,OAAO,CAAC,mBAAmB,IAAI,OAAO,CAAC,CAAC;QAC/E,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC7C,IAAI,SAAS,GAAG,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAC;QAChG,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,aAAa,EAAE,CAAC;QACjD,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;QACnD,MAAM,aAAa,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC;QACpF,sFAAsF;QACtF,wFAAwF;QACxF,MAAM,KAAK,GACT,CAAC,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,KAAK,KAAK,oCAAoC,IAAI,aAAa;YACxF,CAAC,CAAC;gBACE,GAAG,aAAa;gBAChB,GAAG,EAAE,oBAA6B;gBAClC,OAAO,EAAE,8BAA8B;aACxC;YACH,CAAC,CAAC,aAAa,CAAC;QACpB,IAAI,CAAC,KAAK;YACR,MAAM,IAAI,KAAK,CACb,iBAAiB,OAAO,CAAC,KAAK,6DAA6D,CAC5F,CAAC;QACJ,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC;YACpB,YAAY;YACZ,QAAQ;YACR,gBAAgB;YAChB,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;SACpE,CAAC,CAAC;QACH,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,IAAI,EAAE,EAAE,CAAC;YACvC,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC,oCAAoC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;YAC3F,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvB,CAAC;QACD,MAAM,kBAAkB,GAAG,eAAe,CACxC,oBAAoB,EACpB,OAAO,CAAC,kBAAkB,IAAI,MAAM,CACrC,CAAC;QACF,eAAe,CAAC,eAAe,EAAE,OAAO,CAAC,aAAa,IAAI,MAAM,CAAC,CAAC;QAClE,MAAM,cAAc,GAAG,eAAe,CAAC,gBAAgB,EAAE,OAAO,CAAC,cAAc,IAAI,MAAM,CAAC,CAAC;QAC3F,MAAM,UAAU,GAAG,MAAM,gBAAgB,EAAE,CAAC,CAAC,mDAAmD;QAChG,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS;YACjC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC;YAC5B,CAAC,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,wBAAwB,CAAC,CAAC,CAAC;QAC5D,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5C,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACnD,MAAM,OAAO,GAAG,IAAI,cAAc,CAChC;YACE,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,GAAG,CAAC,OAAO,CAAC,cAAc,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC3F,GAAG,CAAC,OAAO,CAAC,iBAAiB,KAAK,SAAS;gBACzC,CAAC,CAAC,EAAE,iBAAiB,EAAE,OAAO,CAAC,iBAAiB,EAAE;gBAClD,CAAC,CAAC,EAAE,CAAC;YACP,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC1E,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACrD,iBAAiB,EACf,OAAO,CAAC,OAAO,EAAE,IAAI,KAAK,QAAQ,IAAI,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,iBAAiB;YAC3E,SAAS,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS;YAC9B,gBAAgB,EAAE,CAAC,CAAC,OAAO,CAAC,gBAAgB;YAC5C,GAAG,CAAC,OAAO,CAAC,OAAO,IAAI,UAAU,IAAI,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,QAAQ;gBAC9E,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE;gBACxC,CAAC,CAAC,EAAE,CAAC;YACP,SAAS;YACT,kBAAkB;YAClB,cAAc;SACf,EACD,UAAU,CACX,CAAC;QACF,MAAM,MAAM,GAAG,EAAE,GAAG,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QAC9F,MAAM,QAAQ,GAAG,IAAI,UAAU,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;QAC5E,IAAI,QAAQ,EAAE,CAAC;YACb,QAAQ,CAAC,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC;YACtC,QAAQ,CAAC,UAAU,GAAG,QAAQ,CAAC,KAAK,CAAC;YACrC,QAAQ,CAAC,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC;YAC9B,QAAQ,CAAC,eAAe,GAAG,IAAI,CAAC;YAChC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC;gBACrB,IAAI,EAAE,MAAM;gBACZ,OAAO,EACL,gMAAgM;gBAClM,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;aACtB,CAAC,CAAC;QACL,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAOD,KAAK,CAAC,GAAG,CACP,IAAY,EACZ,UAA6C,EAAE;QAE/C,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;IAC7C,CAAC;IAOD,KAAK,CAAC,QAAQ,CACZ,IAAY,EACZ,UAA6C,EAAE;QAE/C,IAAI,CAAC,IAAI,CAAC,eAAe;YAAE,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;QAC/F,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IAC5C,CAAC;IAEO,QAAQ,CACd,IAAY,EACZ,OAA0C,EAC1C,QAAiB;QAEjB,IAAI,CAAC,UAAU,EAAE,CAAC;QAClB,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;QAC9D,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,IAAI,CAAC,QAAQ;YAAE,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;QAClC,IAAI,CAAC,KAAK,GAAG,UAAU,EAAE,CAAC;QAC1B,IAAI,CAAC,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QACxC,IAAI,CAAC,OAAO,GAAG,IAAI,UAAU,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;QAC9F,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;QAC1D,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAEO,KAAK,CAAC,UAAU,CACtB,IAAY,EACZ,OAA0C,EAC1C,QAAiB;QAEjB,MAAM,UAAU,GAAG,IAAI,CAAC,UAAW,CAAC;QACpC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAQ,CAAC;QAC9B,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM;YAC3B,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;YACtD,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC;QACtB,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,EAAE,MAAM,CAAC,CAAC;QAC/D,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,EAAE,GAAG,IAAI,CAAC,KAAK,OAAO,CAAC,CAAC;QAC1D,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,EAAE,GAAG,IAAI,CAAC,KAAK,QAAQ,CAAC,CAAC;QAC1D,IAAI,QAA8B,CAAC;QACnC,IAAI,OAAqD,CAAC;QAC1D,IAAI,CAAC;YACH,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;YACzD,OAAO,GAAG,MAAM,IAAI,CAAC,UAAU,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;YAC9C,MAAM,MAAM,GAAG,KAAK,EAAE,IAAsB,EAAE,EAAE;gBAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC9B,yFAAyF;gBACzF,IACE,IAAI,CAAC,IAAI,KAAK,aAAa;oBAC3B,CAAC,gBAAgB,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;oBAEzD,OAAO;gBACT,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,GAAG,EAAE,KAAc,EAAE,EAAE,CAC/D,GAAG,KAAK,MAAM,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,KAAK;oBACjE,CAAC,CAAC,gCAAgC;oBAClC,CAAC,CAAC,KAAK,CACV,CAAC;gBACF,MAAM,OAAQ,CAAC,SAAS,CACtB,UAAU,CAAC,MAAM,GAAG,MAAM;oBACxB,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC;wBACb,QAAQ,EAAE,KAAK,CAAC,QAAQ;wBACxB,SAAS,EAAE,KAAK,CAAC,SAAS;wBAC1B,KAAK,EAAE,KAAK,CAAC,KAAK;wBAClB,IAAI,EAAE,KAAK,CAAC,IAAI;wBAChB,SAAS,EAAE,IAAI;qBAChB,CAAC,GAAG,IAAI;oBACX,CAAC,CAAC,UAAU,GAAG,IAAI,CACtB,CAAC;YACJ,CAAC,CAAC;YACF,MAAM,MAAM,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;YACpD,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBAC7C,QAAQ,GAAG,IAAI,QAAQ,CACrB,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,EAAE,YAAY,EAAE,IAAI,CAAC,KAAK,CAAC,EAC9D,IAAI,EACJ,OAAO,IAAI,CAAC,MAAM,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CACvE,CAAC;gBACF,IAAI,CAAC;oBACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;oBACvD,MAAM,QAAQ,CAAC,KAAK,CAClB,IAAI,CAAC,OAAO,CAAC,QAAQ,EACrB,QAAQ,EACR,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,iBAAiB,CAClF,CAAC;oBACF,IAAI,CAAC,OAAO,CAAC,QAAQ,GAAG,CAAC,MAAM,EAAE,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;gBAC/D,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,MAAM,MAAM,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,0BAA0B,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC;gBACxF,CAAC;YACH,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,QAAQ,CAC3B,IAAI,CAAC,OAAO,EACZ,IAAI,CAAC,KAAK,EACV,IAAI,CAAC,MAAM,EACX,IAAI,CAAC,SAAS,EACd,IAAI,EACJ,OAAO,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,EAAE,EAC/B;gBACE,GAAG,OAAO;gBACV,MAAM;gBACN,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE;oBACpC,MAAM,MAAM,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC,CAAC;oBAC7C,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;gBAC9C,CAAC;aACF,EACD;gBACE,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,OAAO;gBACP,UAAU;gBACV,IAAI,EAAE,CAAC,QAAQ,EAAE,EAAE;oBACjB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;oBACzB,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC;gBAC9B,CAAC;aACF,CACF,CAAC;YACF,IAAI,CAAC,IAAI,EAAE,CAAC;YACZ,KAAK,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,CAAU;gBACtF,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC5C,KAAK,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,OAAO,CAAU;gBAChF,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACtD,IAAI,CAAC,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC;YAClC,MAAM,QAAQ,GAAa,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,CAAC;YACxD,IAAI,aAAiC,CAAC;YACtC,IAAI,QAAQ,EAAE,CAAC;gBACb,IAAI,CAAC;oBACH,aAAa,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;gBACjF,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,QAAQ,CAAC,IAAI,CAAC,iCAAiC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;gBAClE,CAAC;YACH,CAAC;YACD,QAAQ,GAAG,SAAS,CAAC;YACrB,MAAM,SAAS,GAAuB;gBACpC,GAAG,MAAM;gBACT,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC3C,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,UAAU;aACX,CAAC;YACF,IAAI,CAAC;gBACH,MAAM,WAAW,CAAC,WAAW,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;gBACjE,SAAS,CAAC,WAAW,GAAG,WAAW,CAAC;YACtC,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,QAAQ,CAAC,IAAI,CAAC,+BAA+B,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAChE,CAAC;YACD,IAAI,QAAQ,CAAC,MAAM;gBAAE,SAAS,CAAC,QAAQ,GAAG,QAAQ,CAAC;YACnD,IAAI,CAAC;gBACH,MAAM,MAAM,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;YACvD,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,SAAS,CAAC,QAAQ,GAAG;oBACnB,GAAG,CAAC,SAAS,CAAC,QAAQ,IAAI,EAAE,CAAC;oBAC7B,qCAAqC,MAAM,CAAC,KAAK,CAAC,EAAE;iBACrD,CAAC;YACJ,CAAC;YACD,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;YAC1B,OAAO,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;QACrD,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC;YAClC,MAAM,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YACvC,IAAI,QAAQ;gBAAE,MAAM,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YACvF,IAAI,CAAC;gBACH,MAAM,OAAO,EAAE,KAAK,EAAE,CAAC;YACzB,CAAC;oBAAS,CAAC;gBACT,OAAO,CAAC,MAAM,EAAE,CAAC;gBACjB,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;gBACpB,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;gBAC5B,IAAI,CAAC,OAAO,GAAG,SAAS,CAAC;YAC3B,CAAC;QACH,CAAC;IACH,CAAC;IAEO,IAAI,CAAC,IAAsB;QACjC,MAAM,KAAK,GAAG,MAAM,CAClB,EAAE,GAAG,IAAI,EAAE,QAAQ,EAAE,EAAE,IAAI,CAAC,QAAQ,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,EAChF,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CACzB,CAAC;QACF,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO;YAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACtD,MAAM,IAAI,GACR,IAAI,CAAC,MAAM,CAAC,GAAG,KAAK,MAAM;YACxB,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;YACvB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,KAAK,QAAQ;gBAC5B,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC;gBACpB,CAAC,CAAC,SAAS,CAAC;QAClB,IAAI,IAAI;YAAE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;QAC5C,OAAO,KAAK,CAAC;IACf,CAAC;IAED,gFAAgF;IAChF,MAAM;QACJ,IAAI,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;QAC1D,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;QAClE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACzB,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,IAAI,OAAO;QACT,OAAO,MAAM,CACX;YACE,OAAO,EAAE,CAAC;YACV,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK;YACxB,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,KAAK,EAAE,IAAI,CAAC,UAAU;YACtB,IAAI,EAAE,IAAI,CAAC,IAAI;SAChB,EACD,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CACzB,CAAC;IACJ,CAAC;IACD,IAAI,KAAK;QACP,OAAO,eAAe,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC1C,CAAC;IACD,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,OAAO,EAAE,MAAM,IAAI,KAAK,CAAC;IACvC,CAAC;IACD,KAAK;QACH,OAAO,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACxC,CAAC;IACD,KAAK,CAAC,WAAW,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,EAAE,cAAc,CAAC;QAC3E,IAAI,CAAC,UAAU,EAAE,CAAC;QAClB,MAAM,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC1D,OAAO,IAAI,CAAC;IACd,CAAC;IACD,KAAK;QACH,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;QAC9D,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IAC9B,CAAC;IACD,KAAK,CAAC,MAAM;QACV,MAAM,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACvC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;IACzB,CAAC;IACD,KAAK,CAAC,IAAY;QAChB,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;QACrE,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK;YACtB,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;QAC3E,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC3B,CAAC;IACD,MAAM;QACJ,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;IACzB,CAAC;IAED,yEAAyE;IACzE,KAAK,CAAC,OAAO,CAAC,IAAY,EAAE,UAAwD,EAAE;QACpF,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC;QAClC,IAAI,CAAC,WAAW;YAAE,IAAI,CAAC,UAAU,EAAE,CAAC;QACpC,IAAI,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;QAC1D,IAAI,WAAW,IAAI,IAAI,CAAC,UAAU;YAChC,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;QAC/D,IAAI,CAAC,WAAW;YAAE,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACrC,IAAI,CAAC;YACH,MAAM,MAAM,GACV,WAAW,IAAI,IAAI,CAAC,UAAU;gBAC5B,CAAC,CAAC,OAAO,CAAC,MAAM;oBACd,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;oBAC3D,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM;gBAC1B,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;YACrB,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAC/B,IAAI,EACJ,OAAO,CAAC,SAAS,IAAI,IAAI,CAAC,MAAM,CAAC,aAAa,IAAI,MAAM,EACxD,MAAM,CACP,CAAC;YACF,IAAI,WAAW;gBAAE,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;YACxC,OAAO,MAAM,IAAI,CAAC;QACpB,CAAC;gBAAS,CAAC;YACT,IAAI,WAAW;gBAAE,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;;gBACxC,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QAC3B,CAAC;IACH,CAAC;IAEO,UAAU;QAChB,IAAI,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;QAChF,IAAI,IAAI,CAAC,MAAM;YACb,MAAM,IAAI,KAAK,CACb,gFAAgF,CACjF,CAAC;IACN,CAAC;IAED,+FAA+F;IAC/F,KAAK;QACH,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC,OAAO,CAAC;QACtC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,IAAI,CAAC,OAAO,GAAG,CAAC,KAAK,IAAI,EAAE;YACzB,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;gBACtC,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YAC7B,CAAC;oBAAS,CAAC;gBACT,IAAI,CAAC;oBACH,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;gBAC7B,CAAC;wBAAS,CAAC;oBACT,KAAK,MAAM,MAAM,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC;wBAAE,MAAM,CAAC,GAAG,EAAE,CAAC;gBACvD,CAAC;YACH,CAAC;QACH,CAAC,CAAC,EAAE,CAAC;QACL,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAED,KAAK,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC;QACzB,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;CACF;AAED,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,IAAI,EAAE,IAAI,EAAe,MAAM,WAAW,CAAC;AAIpD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,EAAE,eAAe,EAAqB,MAAM,YAAY,CAAC","sourcesContent":["import { mkdir, mkdtemp, open } from 'node:fs/promises';\nimport { tmpdir } from 'node:os';\nimport { join, resolve } from 'node:path';\nimport { builtinModels } from '@earendil-works/pi-ai/providers/all';\nimport { randomUUID } from 'node:crypto';\nimport type { AgentMessage, StreamFn } from '@earendil-works/pi-agent-core';\nimport type { Api, Model, Usage } from '@earendil-works/pi-ai';\nimport { Type, type Static, type TSchema } from 'typebox';\nimport { navigationPolicy, validateSensitiveData } from './policy.js';\nimport { telemetry } from './telemetry.js';\nimport { openBrowser } from './browser.js';\nimport { BrowserRuntime, workerExecutable } from './runtime.js';\nimport { runAgent, zeroUsage } from './agent.js';\nimport { Recorder } from './recording.js';\nimport { RunControl } from './control.js';\nimport {\n loadHistory,\n saveHistory,\n workspaceFiles,\n redact,\n type SessionHistory,\n} from './history.js';\nimport { EventStream, formatEvent, type SessionEvent, type SessionEventData } from './events.js';\nimport { positiveInteger } from './protocol.js';\nimport type { BrowserUseOptions, RunOptions, RunResult } from './types.js';\n\nexport type { BrowserUseOptions, RunOptions, RunResult, StopReason, RunMetrics } from './types.js';\nexport { Browser } from './browser.js';\nexport type {\n BrowserOptions,\n CloudBrowserOptions,\n ChromeBrowserOptions,\n LocalBrowserOptions,\n} from './browser.js';\nexport type { CellResult, Image } from './protocol.js';\nexport { CellError } from './runtime.js';\nexport type { AgentTool, AgentEvent, StreamFn } from '@earendil-works/pi-agent-core';\nexport { Type, type Static, type TSchema } from 'typebox';\nexport { builtinModels } from '@earendil-works/pi-ai/providers/all';\n\n/** One browser, workspace and JavaScript namespace. run() resets context; followUp() retains it. */\nexport class BrowserUse {\n private readonly reportRun: ReturnType<typeof telemetry>;\n private active = false;\n private closed = false;\n private controller: AbortController | undefined;\n private closing: Promise<void> | undefined;\n private messages: AgentMessage[] = [];\n private totalUsage = zeroUsage();\n private runs = 0;\n private control: RunControl | undefined;\n private streams = new Set<EventStream>();\n private sequence = 0;\n private activeRun: Promise<RunResult<unknown>> | undefined;\n private manualCell: Promise<unknown> | undefined;\n private runId = '';\n private hasConversation = false;\n\n private constructor(\n private readonly config: BrowserUseOptions & { streamFn: StreamFn },\n private readonly model: Model<Api>,\n private readonly runtime: BrowserRuntime,\n private readonly browser: Awaited<ReturnType<typeof openBrowser>>,\n readonly workspace: string,\n ) {\n this.reportRun = telemetry(config.telemetry, config.browser);\n }\n\n static async create(options: BrowserUseOptions): Promise<BrowserUse> {\n if (options.telemetry !== undefined && typeof options.telemetry !== 'boolean')\n throw new Error('telemetry must be boolean.');\n navigationPolicy(options);\n validateSensitiveData(options.sensitiveData);\n options = {\n ...options,\n redact: [\n ...(options.redact ?? []),\n ...Object.values(options.sensitiveData ?? {}).map((secret) => secret.value),\n ],\n };\n if (options.highlightActions !== undefined && typeof options.highlightActions !== 'boolean')\n throw new Error('highlightActions must be boolean.');\n if (options.researchTools !== undefined && typeof options.researchTools !== 'boolean')\n throw new Error('researchTools must be boolean.');\n if (options.recording && typeof options.recording === 'object') {\n positiveInteger('recording.intervalMs', options.recording.intervalMs ?? 750);\n positiveInteger('recording.maxFrames', options.recording.maxFrames ?? 400);\n if (\n (options.recording.intervalMs ?? 750) < 100 ||\n (options.recording.maxFrames ?? 400) > 10000\n )\n throw new Error('Recording requires intervalMs >= 100 and maxFrames <= 10000.');\n }\n const restored = options.historyFile\n ? await loadHistory(options.historyFile, options.model)\n : undefined;\n positiveInteger('hookTimeoutMs', options.hookTimeoutMs ?? 30_000);\n positiveInteger('modelTimeoutMs', options.modelTimeoutMs ?? 300_000);\n positiveInteger('compactionTimeoutMs', options.compactionTimeoutMs ?? 120_000);\n const separator = options.model.indexOf('/');\n if (separator < 1) throw new Error('model must be provider/model, for example openai/gpt-5.4.');\n const models = options.models ?? builtinModels();\n const provider = options.model.slice(0, separator);\n const resolvedModel = models.getModel(provider, options.model.slice(separator + 1));\n // Pi 0.85.1 sends configuration_update via Messages, which OpenRouter Opus 5 rejects.\n // Keep caller-supplied model collections untouched. Remove when upstream fixes routing.\n const model =\n !options.models && options.model === 'openrouter/anthropic/claude-opus-5' && resolvedModel\n ? {\n ...resolvedModel,\n api: 'openai-completions' as const,\n baseUrl: 'https://openrouter.ai/api/v1',\n }\n : resolvedModel;\n if (!model)\n throw new Error(\n `Unknown model ${options.model}. Supply a Pi models collection with this model registered.`,\n );\n const names = new Set([\n 'javascript',\n 'finish',\n 'finish_from_js',\n ...(options.researchTools ? ['read', 'write', 'edit', 'bash'] : []),\n ]);\n for (const tool of options.tools ?? []) {\n if (names.has(tool.name)) throw new Error(`Duplicate or reserved tool name: ${tool.name}`);\n names.add(tool.name);\n }\n const operationTimeoutMs = positiveInteger(\n 'operationTimeoutMs',\n options.operationTimeoutMs ?? 15_000,\n );\n positiveInteger('cellTimeoutMs', options.cellTimeoutMs ?? 30_000);\n const maxOutputChars = positiveInteger('maxOutputChars', options.maxOutputChars ?? 12_000);\n const executable = await workerExecutable(); // Fail before launching or provisioning a browser.\n const workspace = options.workspace\n ? resolve(options.workspace)\n : await mkdtemp(join(tmpdir(), 'browser-use-artifacts-'));\n await mkdir(workspace, { recursive: true });\n const browser = await openBrowser(options.browser);\n const runtime = new BrowserRuntime(\n {\n endpoint: browser.endpoint,\n ...(options.allowedDomains !== undefined ? { allowedDomains: options.allowedDomains } : {}),\n ...(options.prohibitedDomains !== undefined\n ? { prohibitedDomains: options.prohibitedDomains }\n : {}),\n ...(options.sensitiveData ? { sensitiveData: options.sensitiveData } : {}),\n ...(options.redact ? { redact: options.redact } : {}),\n approveConnection:\n options.browser?.kind === 'chrome' && !!options.browser.approveConnection,\n recording: !!options.recording,\n highlightActions: !!options.highlightActions,\n ...(options.browser && 'targetId' in options.browser && options.browser.targetId\n ? { targetId: options.browser.targetId }\n : {}),\n workspace,\n operationTimeoutMs,\n maxOutputChars,\n },\n executable,\n );\n const config = { ...options, streamFn: options.streamFn ?? models.streamSimple.bind(models) };\n const instance = new BrowserUse(config, model, runtime, browser, workspace);\n if (restored) {\n instance.messages = restored.messages;\n instance.totalUsage = restored.usage;\n instance.runs = restored.runs;\n instance.hasConversation = true;\n instance.messages.push({\n role: 'user',\n content:\n 'This conversation was restored from disk. JavaScript bindings and connections were reset. Inspect browser state and workspace before continuing. Never replay uncertain actions automatically.',\n timestamp: Date.now(),\n });\n }\n return instance;\n }\n\n run(task: string, options?: RunOptions): Promise<RunResult<string>>;\n run<S extends TSchema>(\n task: string,\n options: RunOptions & { schema: S },\n ): Promise<RunResult<Static<S>>>;\n async run(\n task: string,\n options: RunOptions & { schema?: TSchema } = {},\n ): Promise<RunResult<unknown>> {\n return this.startRun(task, options, false);\n }\n\n followUp(task: string, options?: RunOptions): Promise<RunResult<string>>;\n followUp<S extends TSchema>(\n task: string,\n options: RunOptions & { schema: S },\n ): Promise<RunResult<Static<S>>>;\n async followUp(\n task: string,\n options: RunOptions & { schema?: TSchema } = {},\n ): Promise<RunResult<unknown>> {\n if (!this.hasConversation) throw new Error('Run a task or restore history before followUp().');\n return this.startRun(task, options, true);\n }\n\n private startRun(\n task: string,\n options: RunOptions & { schema?: TSchema },\n followUp: boolean,\n ): Promise<RunResult<unknown>> {\n this.assertIdle();\n if (!task.trim()) throw new Error('Provide a nonempty task.');\n this.active = true;\n if (!followUp) this.messages = [];\n this.runId = randomUUID();\n this.controller = new AbortController();\n this.control = new RunControl((paused) => this.emit({ type: paused ? 'paused' : 'resumed' }));\n this.activeRun = this.performRun(task, options, followUp);\n return this.activeRun;\n }\n\n private async performRun(\n task: string,\n options: RunOptions & { schema?: TSchema },\n followUp: boolean,\n ): Promise<RunResult<unknown>> {\n const controller = this.controller!;\n const control = this.control!;\n const signal = options.signal\n ? AbortSignal.any([options.signal, controller.signal])\n : controller.signal;\n const directory = join(this.workspace, '.browser-use', 'runs');\n const historyPath = join(directory, `${this.runId}.json`);\n const eventsPath = join(directory, `${this.runId}.jsonl`);\n let recorder: Recorder | undefined;\n let journal: Awaited<ReturnType<typeof open>> | undefined;\n try {\n await mkdir(directory, { recursive: true, mode: 0o700 });\n journal = await open(eventsPath, 'wx', 0o600);\n const record = async (data: SessionEventData) => {\n const event = this.emit(data);\n // Deltas stream live. Persist finalized messages, not a full transcript for every token.\n if (\n data.type === 'agent_event' &&\n ['message_update', 'agent_end'].includes(data.event.type)\n )\n return;\n const serialized = JSON.stringify(event, (key, value: unknown) =>\n key === 'data' && typeof value === 'string' && value.length > 10000\n ? '[image omitted from event log]'\n : value,\n );\n await journal!.writeFile(\n serialized.length > 256000\n ? JSON.stringify({\n sequence: event.sequence,\n timestamp: event.timestamp,\n runId: event.runId,\n type: event.type,\n truncated: true,\n }) + '\\n'\n : serialized + '\\n',\n );\n };\n await record({ type: 'run_start', task, followUp });\n if (this.config.recording && !signal.aborted) {\n recorder = new Recorder(\n join(this.workspace, '.browser-use', 'recordings', this.runId),\n task,\n typeof this.config.recording === 'object' ? this.config.recording : {},\n );\n try {\n const targetId = await this.runtime.initialize(signal);\n await recorder.start(\n this.browser.endpoint,\n targetId,\n this.config.browser?.kind === 'chrome' && !!this.config.browser.approveConnection,\n );\n this.runtime.onAction = (action) => recorder?.action(action);\n } catch (error) {\n await record({ type: 'warning', message: `Recording unavailable: ${String(error)}` });\n }\n }\n const result = await runAgent(\n this.runtime,\n this.model,\n this.config,\n this.workspace,\n task,\n options.schema ?? Type.String(),\n {\n ...options,\n signal,\n onEvent: async (event, eventSignal) => {\n await record({ type: 'agent_event', event });\n await options.onEvent?.(event, eventSignal);\n },\n },\n {\n messages: this.messages,\n control,\n eventsPath,\n save: (messages) => {\n this.messages = messages;\n this.hasConversation = true;\n },\n },\n );\n this.runs++;\n for (const key of ['input', 'output', 'cacheRead', 'cacheWrite', 'totalTokens'] as const)\n this.totalUsage[key] += result.usage[key];\n for (const key of ['input', 'output', 'cacheRead', 'cacheWrite', 'total'] as const)\n this.totalUsage.cost[key] += result.usage.cost[key];\n this.runtime.onAction = undefined;\n const warnings: string[] = [...(result.warnings ?? [])];\n let recordingPath: string | undefined;\n if (recorder) {\n try {\n recordingPath = await recorder.stop(result.status, this.runtime.currentTarget);\n } catch (error) {\n warnings.push(`Recording could not be saved: ${String(error)}`);\n }\n }\n recorder = undefined;\n const delivered: RunResult<unknown> = {\n ...result,\n ...(recordingPath ? { recordingPath } : {}),\n runId: this.runId,\n eventsPath,\n };\n try {\n await saveHistory(historyPath, this.history, this.config.redact);\n delivered.historyPath = historyPath;\n } catch (error) {\n warnings.push(`History could not be saved: ${String(error)}`);\n }\n if (warnings.length) delivered.warnings = warnings;\n try {\n await record({ type: 'run_end', result: delivered });\n } catch (error) {\n delivered.warnings = [\n ...(delivered.warnings ?? []),\n `Event log could not be finalized: ${String(error)}`,\n ];\n }\n this.reportRun(delivered);\n return redact(delivered, this.config.redact ?? []);\n } finally {\n this.runtime.onAction = undefined;\n await this.manualCell?.catch(() => {});\n if (recorder) await recorder.stop('error', this.runtime.currentTarget).catch(() => {});\n try {\n await journal?.close();\n } finally {\n control.finish();\n this.active = false;\n this.controller = undefined;\n this.control = undefined;\n }\n }\n }\n\n private emit(data: SessionEventData): SessionEvent {\n const event = redact(\n { ...data, sequence: ++this.sequence, timestamp: Date.now(), runId: this.runId },\n this.config.redact ?? [],\n );\n for (const stream of this.streams) stream.push(event);\n const line =\n this.config.log === 'json'\n ? JSON.stringify(event)\n : this.config.log === 'pretty'\n ? formatEvent(event)\n : undefined;\n if (line) process.stderr.write(line + '\\n');\n return event;\n }\n\n /** Subscribe before starting work. Iterators finish when the session closes. */\n events(): EventStream {\n if (this.closed) throw new Error('BrowserUse is closed.');\n const stream = new EventStream(() => this.streams.delete(stream));\n this.streams.add(stream);\n return stream;\n }\n\n get history(): SessionHistory {\n return redact(\n {\n version: 1,\n model: this.config.model,\n messages: this.messages,\n usage: this.totalUsage,\n runs: this.runs,\n },\n this.config.redact ?? [],\n );\n }\n get usage(): Usage {\n return structuredClone(this.totalUsage);\n }\n get isPaused() {\n return this.control?.paused ?? false;\n }\n files() {\n return workspaceFiles(this.workspace);\n }\n async saveHistory(path = join(this.workspace, '.browser-use', 'session.json')) {\n this.assertIdle();\n await saveHistory(path, this.history, this.config.redact);\n return path;\n }\n pause(): Promise<void> {\n if (!this.control) throw new Error('No active run to pause.');\n return this.control.pause();\n }\n async resume() {\n await this.manualCell?.catch(() => {});\n this.control?.resume();\n }\n steer(text: string) {\n if (!text.trim()) throw new Error('Provide nonempty steering text.');\n if (!this.control?.steer)\n throw new Error('No active agent to steer; use followUp() after a run.');\n this.control.steer(text);\n }\n cancel() {\n this.controller?.abort();\n this.control?.resume();\n }\n\n /** Direct browser code. Use the same page and variables as the agent. */\n async execute(code: string, options: { timeoutMs?: number; signal?: AbortSignal } = {}) {\n const duringPause = this.isPaused;\n if (!duringPause) this.assertIdle();\n if (this.closed) throw new Error('BrowserUse is closed.');\n if (duringPause && this.manualCell)\n throw new Error('A manual browser cell is already running.');\n if (!duringPause) this.active = true;\n try {\n const signal =\n duringPause && this.controller\n ? options.signal\n ? AbortSignal.any([options.signal, this.controller.signal])\n : this.controller.signal\n : options.signal;\n const cell = this.runtime.execute(\n code,\n options.timeoutMs ?? this.config.cellTimeoutMs ?? 30_000,\n signal,\n );\n if (duringPause) this.manualCell = cell;\n return await cell;\n } finally {\n if (duringPause) this.manualCell = undefined;\n else this.active = false;\n }\n }\n\n private assertIdle() {\n if (this.closed) throw new Error('BrowserUse is closed. Create a new session.');\n if (this.active)\n throw new Error(\n 'This session is busy. Await the active operation or create a separate session.',\n );\n }\n\n /** Idempotent. Cancels execution, closes our tab, and shuts down only browsers we launched. */\n close(): Promise<void> {\n if (this.closing) return this.closing;\n this.closed = true;\n this.cancel();\n this.closing = (async () => {\n try {\n await this.activeRun?.catch(() => {});\n await this.runtime.close();\n } finally {\n try {\n await this.browser.close();\n } finally {\n for (const stream of [...this.streams]) stream.end();\n }\n }\n })();\n return this.closing;\n }\n\n async [Symbol.asyncDispose]() {\n await this.close();\n }\n}\n\nexport { CDP } from './cdp.js';\nexport { Page, Tabs, type AXNode } from './page.js';\n\nexport type { SessionHistory, WorkspaceFile } from './history.js';\nexport type { SessionEvent } from './events.js';\nexport { formatEvent } from './events.js';\n\nexport { exportRecording, type VideoOptions } from './video.js';\nexport type { RecordingOptions } from './recording.js';\n\nexport type { DomainOptions, SensitiveData } from './policy.js';\n"]}
@@ -0,0 +1,3 @@
1
+ import type { StreamFn } from '@earendil-works/pi-agent-core';
2
+ /** Bound connection setup and the entire response, even if a transport ignores abort. */
3
+ export declare function deadlineStream(streamFn: StreamFn, timeoutMs: number): StreamFn;
@@ -0,0 +1,78 @@
1
+ import { createAssistantMessageEventStream } from '@earendil-works/pi-ai';
2
+ /** Bound connection setup and the entire response, even if a transport ignores abort. */
3
+ export function deadlineStream(streamFn, timeoutMs) {
4
+ return (model, context, options) => {
5
+ const output = createAssistantMessageEventStream();
6
+ const controller = new AbortController();
7
+ let ended = false;
8
+ let partial;
9
+ let timer;
10
+ const cleanup = () => {
11
+ clearTimeout(timer);
12
+ options?.signal?.removeEventListener('abort', cancel);
13
+ };
14
+ const fail = (message, cancelled = false) => {
15
+ if (ended)
16
+ return;
17
+ ended = true;
18
+ cleanup();
19
+ // Freeze partial evidence. A late provider response must not mutate run history.
20
+ const error = {
21
+ role: 'assistant',
22
+ content: [],
23
+ api: model.api,
24
+ provider: model.provider,
25
+ model: model.id,
26
+ usage: {
27
+ input: 0,
28
+ output: 0,
29
+ cacheRead: 0,
30
+ cacheWrite: 0,
31
+ totalTokens: 0,
32
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
33
+ },
34
+ timestamp: Date.now(),
35
+ ...(partial ? structuredClone(partial) : {}),
36
+ stopReason: cancelled ? 'aborted' : 'error',
37
+ errorMessage: message,
38
+ };
39
+ output.push({ type: 'error', reason: error.stopReason, error });
40
+ output.end();
41
+ controller.abort();
42
+ };
43
+ const cancel = () => fail('Model request cancelled.', true);
44
+ options?.signal?.addEventListener('abort', cancel, { once: true });
45
+ if (options?.signal?.aborted)
46
+ cancel();
47
+ else {
48
+ timer = setTimeout(() => fail(`Model stream exceeded ${timeoutMs} ms.`), timeoutMs);
49
+ void (async () => {
50
+ try {
51
+ const source = await streamFn(model, context, { ...options, signal: controller.signal });
52
+ if (ended)
53
+ return;
54
+ for await (const event of source) {
55
+ if (ended)
56
+ return;
57
+ if ('partial' in event)
58
+ partial = event.partial;
59
+ if (event.type === 'done' || event.type === 'error') {
60
+ ended = true;
61
+ cleanup();
62
+ output.push(event);
63
+ output.end();
64
+ return;
65
+ }
66
+ output.push(event);
67
+ }
68
+ fail('Model stream ended before a terminal response event.');
69
+ }
70
+ catch (error) {
71
+ fail(error instanceof Error ? error.message : String(error));
72
+ }
73
+ })();
74
+ }
75
+ return output;
76
+ };
77
+ }
78
+ //# sourceMappingURL=model-stream.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-stream.js","sourceRoot":"","sources":["../src/model-stream.ts"],"names":[],"mappings":"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","sourcesContent":["import type { StreamFn } from '@earendil-works/pi-agent-core';\nimport { createAssistantMessageEventStream, type AssistantMessage } from '@earendil-works/pi-ai';\n\n/** Bound connection setup and the entire response, even if a transport ignores abort. */\nexport function deadlineStream(streamFn: StreamFn, timeoutMs: number): StreamFn {\n return (model, context, options) => {\n const output = createAssistantMessageEventStream();\n const controller = new AbortController();\n let ended = false;\n let partial: AssistantMessage | undefined;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const cleanup = () => {\n clearTimeout(timer);\n options?.signal?.removeEventListener('abort', cancel);\n };\n const fail = (message: string, cancelled = false) => {\n if (ended) return;\n ended = true;\n cleanup();\n // Freeze partial evidence. A late provider response must not mutate run history.\n const error: AssistantMessage = {\n role: 'assistant',\n content: [],\n api: model.api,\n provider: model.provider,\n model: model.id,\n usage: {\n input: 0,\n output: 0,\n cacheRead: 0,\n cacheWrite: 0,\n totalTokens: 0,\n cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n },\n timestamp: Date.now(),\n ...(partial ? structuredClone(partial) : {}),\n stopReason: cancelled ? 'aborted' : 'error',\n errorMessage: message,\n };\n output.push({ type: 'error', reason: error.stopReason as 'error' | 'aborted', error });\n output.end();\n controller.abort();\n };\n const cancel = () => fail('Model request cancelled.', true);\n options?.signal?.addEventListener('abort', cancel, { once: true });\n if (options?.signal?.aborted) cancel();\n else {\n timer = setTimeout(() => fail(`Model stream exceeded ${timeoutMs} ms.`), timeoutMs);\n void (async () => {\n try {\n const source = await streamFn(model, context, { ...options, signal: controller.signal });\n if (ended) return;\n for await (const event of source) {\n if (ended) return;\n if ('partial' in event) partial = event.partial;\n if (event.type === 'done' || event.type === 'error') {\n ended = true;\n cleanup();\n output.push(event);\n output.end();\n return;\n }\n output.push(event);\n }\n fail('Model stream ended before a terminal response event.');\n } catch (error) {\n fail(error instanceof Error ? error.message : String(error));\n }\n })();\n }\n return output;\n };\n}\n"]}
@@ -0,0 +1,16 @@
1
+ import type { AgentEvent } from '@earendil-works/pi-agent-core';
2
+ /** One active observation and one latest pending event. Never queues unbounded work. */
3
+ export declare class Observer {
4
+ private callback;
5
+ private timeoutMs;
6
+ private pending;
7
+ private running;
8
+ private controller;
9
+ private closed;
10
+ private dropped;
11
+ readonly warnings: string[];
12
+ constructor(callback: (event: AgentEvent, signal: AbortSignal) => void | Promise<void>, timeoutMs: number);
13
+ push(event: AgentEvent): void;
14
+ private drain;
15
+ close(abort?: boolean): Promise<void>;
16
+ }