@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.
- package/.env.example +6 -0
- package/LICENSE +21 -0
- package/README.md +68 -0
- package/dist/agent.d.ts +15 -0
- package/dist/agent.js +381 -0
- package/dist/agent.js.map +1 -0
- package/dist/browser.d.ts +52 -0
- package/dist/browser.js +264 -0
- package/dist/browser.js.map +1 -0
- package/dist/cdp.d.ts +39 -0
- package/dist/cdp.js +291 -0
- package/dist/cdp.js.map +1 -0
- package/dist/context.d.ts +24 -0
- package/dist/context.js +143 -0
- package/dist/context.js.map +1 -0
- package/dist/control.d.ts +18 -0
- package/dist/control.js +84 -0
- package/dist/control.js.map +1 -0
- package/dist/events.d.ts +40 -0
- package/dist/events.js +79 -0
- package/dist/events.js.map +1 -0
- package/dist/highlight.d.ts +3 -0
- package/dist/highlight.js +102 -0
- package/dist/highlight.js.map +1 -0
- package/dist/history.d.ts +22 -0
- package/dist/history.js +126 -0
- package/dist/history.js.map +1 -0
- package/dist/images.d.ts +14 -0
- package/dist/images.js +104 -0
- package/dist/images.js.map +1 -0
- package/dist/index.d.ts +77 -0
- package/dist/index.js +422 -0
- package/dist/index.js.map +1 -0
- package/dist/model-stream.d.ts +3 -0
- package/dist/model-stream.js +78 -0
- package/dist/model-stream.js.map +1 -0
- package/dist/observer.d.ts +16 -0
- package/dist/observer.js +56 -0
- package/dist/observer.js.map +1 -0
- package/dist/page.d.ts +58 -0
- package/dist/page.js +189 -0
- package/dist/page.js.map +1 -0
- package/dist/policy.d.ts +18 -0
- package/dist/policy.js +195 -0
- package/dist/policy.js.map +1 -0
- package/dist/prompt.d.ts +1 -0
- package/dist/prompt.js +41 -0
- package/dist/prompt.js.map +1 -0
- package/dist/protocol.d.ts +70 -0
- package/dist/protocol.js +7 -0
- package/dist/protocol.js.map +1 -0
- package/dist/recording.d.ts +44 -0
- package/dist/recording.js +120 -0
- package/dist/recording.js.map +1 -0
- package/dist/research-tools.d.ts +3 -0
- package/dist/research-tools.js +67 -0
- package/dist/research-tools.js.map +1 -0
- package/dist/runtime.d.ts +39 -0
- package/dist/runtime.js +268 -0
- package/dist/runtime.js.map +1 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.js +251 -0
- package/dist/server.js.map +1 -0
- package/dist/telemetry.d.ts +3 -0
- package/dist/telemetry.js +41 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/types.d.ts +93 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/video.d.ts +18 -0
- package/dist/video.js +177 -0
- package/dist/video.js.map +1 -0
- package/dist/worker.d.ts +1 -0
- package/dist/worker.js +329 -0
- package/dist/worker.js.map +1 -0
- package/examples/README.md +58 -0
- package/examples/apply-to-job.ts +57 -0
- package/examples/ehr.ts +53 -0
- package/examples/extract.ts +50 -0
- package/examples/form.ts +36 -0
- package/examples/onepassword.ts +66 -0
- package/examples/qa.ts +72 -0
- package/examples/research.ts +35 -0
- package/examples/stripe-link.ts +166 -0
- package/package.json +66 -0
package/dist/cdp.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cdp.js","sourceRoot":"","sources":["../src/cdp.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ProtocolMapping } from 'devtools-protocol/types/protocol-mapping.js';\nimport { approveChromeConnection } from './browser.js';\nimport { positiveInteger } from './protocol.js';\n\ntype Commands = ProtocolMapping.Commands;\ntype Events = ProtocolMapping.Events;\ntype Pending = { resolve(value: unknown): void; reject(error: Error): void };\ntype Listener = {\n method: string;\n sessionId: string | undefined;\n accept(params: unknown): void;\n reject(error: Error): void;\n};\n\n/** Explicit commands and one-shot events over one flattened CDP WebSocket. No proxies. */\nexport class CDP {\n private nextId = 0;\n // Shared with the lazy connection. Observation follows protocol sessions, not JS variable names.\n private activity = {\n targets: new Map<string, string>(),\n parents: new Map<string, string>(),\n targetId: undefined as string | undefined,\n };\n get observationTargetId() {\n let targetId = this.activity.targetId;\n const visited = new Set<string>();\n while (targetId && this.activity.parents.has(targetId) && !visited.has(targetId)) {\n visited.add(targetId);\n targetId = this.activity.parents.get(targetId);\n }\n return targetId;\n }\n targetForSession(sessionId: string) {\n return this.activity.targets.get(sessionId);\n }\n /** Optional metadata observer; errors cannot change command delivery. Never receives responses. */\n observeCommand: ((method: string, params: unknown, sessionId?: string) => void) | undefined;\n /** Passive result tap. Exceptions cannot change command delivery. May contain page data. */\n observeResponse:\n ((method: string, params: unknown, result: unknown, sessionId?: string) => void) | undefined;\n observeEvent: ((method: string, params: unknown, sessionId?: string) => void) | undefined;\n private pending = new Map<number, Pending>();\n private listeners = new Set<Listener>();\n private constructor(\n private socket: WebSocket | undefined,\n readonly timeoutMs: number,\n ) {\n if (!socket) return;\n socket.addEventListener('message', ({ data }) => {\n try {\n const message = JSON.parse(String(data));\n if (message.id !== undefined) {\n const request = this.pending.get(message.id);\n if (message.error)\n request?.reject(new Error(`CDP ${message.error.code}: ${message.error.message}`));\n else request?.resolve(message.result);\n } else {\n this.observeEvent?.(message.method, message.params, message.sessionId);\n if (message.method === 'Target.detachedFromTarget')\n this.activity.targets.delete(message.params.sessionId);\n for (const listener of [...this.listeners]) {\n if (listener.method === message.method && listener.sessionId === message.sessionId)\n listener.accept(message.params);\n }\n }\n } catch {\n this.fail(new Error('Malformed CDP message.'));\n socket.close();\n }\n });\n socket.addEventListener('close', () =>\n this.fail(new Error('CDP connection closed. Inspect state before retrying.')),\n );\n socket.addEventListener('error', () => this.fail(new Error('CDP connection failed.')));\n }\n\n private endpoint: string | undefined;\n private approveConnection = false;\n private delegate: Promise<CDP> | undefined;\n private closed = false;\n\n /** Defer network access until the first browser operation. Never replay a command. */\n static lazy(endpoint: string, timeoutMs = 15_000, approveConnection = false) {\n const connection = new CDP(undefined, timeoutMs);\n connection.endpoint = endpoint;\n connection.approveConnection = approveConnection;\n return connection;\n }\n private connected(): Promise<CDP> {\n if (this.closed) return Promise.reject(new Error('CDP connection is closed.'));\n this.delegate ??= CDP.connect(this.endpoint!, this.timeoutMs, this.approveConnection)\n .then((connection) => {\n if (this.closed) {\n connection.close();\n throw new Error('CDP connection is closed.');\n }\n connection.activity = this.activity;\n connection.observeEvent = (method, params, session) =>\n this.observeEvent?.(method, params, session);\n connection.observeCommand = (method, params, sessionId) =>\n this.observeCommand?.(method, params, sessionId);\n return connection;\n })\n .catch((error) => {\n this.delegate = undefined;\n throw error;\n });\n return this.delegate;\n }\n\n static async connect(\n endpoint: string,\n timeoutMs = 15_000,\n approveConnection = false,\n ): Promise<CDP> {\n if (approveConnection && process.platform !== 'darwin')\n throw new Error('Chrome approval is macOS only.');\n positiveInteger('timeoutMs', timeoutMs);\n const url = new URL(endpoint);\n if (url.protocol === 'http:' || url.protocol === 'https:') {\n url.pathname = `${url.pathname.replace(/\\/$/, '')}/json/version`;\n const response = await fetch(url, { signal: AbortSignal.timeout(timeoutMs) });\n if (!response.ok) throw new Error(`CDP discovery failed (${response.status}).`);\n endpoint = ((await response.json()) as { webSocketDebuggerUrl: string }).webSocketDebuggerUrl;\n } else if (!['ws:', 'wss:'].includes(url.protocol))\n throw new Error('Unsupported CDP endpoint protocol.');\n const socket = new WebSocket(endpoint);\n const connection = new CDP(socket, timeoutMs);\n await new Promise<void>((resolve, reject) => {\n const approval = new AbortController();\n const finish = (error?: Error) => {\n approval.abort();\n clearTimeout(timer);\n socket.removeEventListener('open', open);\n socket.removeEventListener('error', failed);\n socket.removeEventListener('close', failed);\n if (error) {\n socket.close();\n reject(error);\n } else resolve();\n };\n const open = () => finish();\n const failed = () => finish(new Error('Could not connect to CDP endpoint.'));\n const timer = setTimeout(() => finish(new Error('CDP connection timed out.')), timeoutMs);\n socket.addEventListener('open', open, { once: true });\n socket.addEventListener('error', failed, { once: true });\n socket.addEventListener('close', failed, { once: true });\n if (approveConnection) {\n void (async () => {\n while (!approval.signal.aborted) {\n await new Promise((resolve) => setTimeout(resolve, 300));\n if (approval.signal.aborted) return;\n if ((await approveChromeConnection(approval.signal)) === 'ready') return;\n }\n })().catch((error) => {\n if (!approval.signal.aborted) finish(error);\n });\n }\n });\n return connection;\n }\n\n async send<M extends keyof Commands>(\n method: M,\n params: Commands[M]['paramsType'][0] = {} as Commands[M]['paramsType'][0],\n sessionId?: string,\n ): Promise<Commands[M]['returnType']> {\n // Capture the observer at dispatch, so late responses cannot enter a later cell.\n const observe = this.observeResponse;\n const result = this.endpoint\n ? await (await this.connected()).send(method, params, sessionId)\n : await this.sendMessage(method, params, sessionId);\n if (method === 'Target.attachToTarget') {\n const attached = result as Commands['Target.attachToTarget']['returnType'];\n const target = (params as Commands['Target.attachToTarget']['paramsType'][0]).targetId;\n this.activity.targets.set(attached.sessionId, target);\n this.activity.targetId = target;\n } else if (method === 'Target.detachFromTarget') {\n const detached = params as Commands['Target.detachFromTarget']['paramsType'][0];\n if (detached?.sessionId) this.activity.targets.delete(detached.sessionId);\n } else if (method === 'Target.closeTarget' && (result as { success?: boolean }).success) {\n const target = (params as Commands['Target.closeTarget']['paramsType'][0]).targetId;\n if (this.observationTargetId === target || this.activity.targetId === target)\n this.activity.targetId = undefined;\n for (const [id, value] of this.activity.targets)\n if (value === target) this.activity.targets.delete(id);\n this.activity.parents.delete(target);\n }\n if (method === 'Target.getTargets' || method === 'Target.getTargetInfo') {\n const infos =\n method === 'Target.getTargets'\n ? (result as Commands['Target.getTargets']['returnType']).targetInfos\n : [(result as Commands['Target.getTargetInfo']['returnType']).targetInfo];\n for (const info of infos)\n if (info.type === 'iframe' && info.parentFrameId)\n this.activity.parents.set(info.targetId, info.parentFrameId);\n }\n if (method === 'Page.getFrameTree' && sessionId) {\n const targetId = this.targetForSession(sessionId);\n const visit = (tree: import('devtools-protocol').Protocol.Page.FrameTree) => {\n if (targetId && tree.frame.id !== targetId)\n this.activity.parents.set(tree.frame.id, targetId);\n tree.childFrames?.forEach(visit);\n };\n visit((result as Commands['Page.getFrameTree']['returnType']).frameTree);\n }\n try {\n observe?.(method, params, result, sessionId);\n } catch {}\n return result;\n }\n\n private sendMessage<M extends keyof Commands>(\n method: M,\n params: Commands[M]['paramsType'][0],\n sessionId?: string,\n ): Promise<Commands[M]['returnType']> {\n if (!this.socket || this.socket.readyState !== WebSocket.OPEN)\n return Promise.reject(new Error('CDP connection is closed.'));\n if (this.pending.size >= 256)\n return Promise.reject(new Error('Too many pending CDP commands (256).'));\n if (sessionId) this.activity.targetId = this.targetForSession(sessionId);\n try {\n this.observeCommand?.(method, params, sessionId);\n } catch {}\n const id = ++this.nextId;\n return new Promise((resolve, reject) => {\n const finish = (error?: Error, value?: unknown) => {\n clearTimeout(timer);\n this.pending.delete(id);\n if (error) reject(error);\n else resolve(value as Commands[M]['returnType']);\n };\n const timer = setTimeout(\n () =>\n finish(\n new Error(`CDP ${method} exceeded ${this.timeoutMs} ms; the action may have happened.`),\n ),\n this.timeoutMs,\n );\n this.pending.set(id, {\n resolve: (value) => finish(undefined, value),\n reject: (error) => finish(error),\n });\n try {\n this.socket!.send(\n JSON.stringify({ id, method, params, ...(sessionId ? { sessionId } : {}) }),\n );\n } catch (error) {\n finish(error instanceof Error ? error : new Error(String(error)));\n }\n });\n }\n\n waitFor<M extends keyof Events>(\n method: M,\n options: {\n sessionId?: string;\n timeoutMs?: number;\n signal?: AbortSignal;\n predicate?: (event: Events[M][0]) => boolean;\n } = {},\n ): Promise<Events[M][0]> {\n const timeoutMs = positiveInteger('timeoutMs', options.timeoutMs ?? this.timeoutMs);\n if (this.endpoint)\n return this.connected().then((connection) => connection.waitFor(method, options));\n const promise = new Promise<Events[M][0]>((resolve, reject) => {\n const finish = (error?: Error, value?: unknown) => {\n clearTimeout(timer);\n this.listeners.delete(listener);\n options.signal?.removeEventListener('abort', abort);\n if (error) reject(error);\n else resolve(value as Events[M][0]);\n };\n const listener: Listener = {\n method,\n sessionId: options.sessionId,\n accept: (value) => {\n try {\n if (!options.predicate || options.predicate(value as Events[M][0]))\n finish(undefined, value);\n } catch (e) {\n finish(e instanceof Error ? e : new Error(String(e)));\n }\n },\n reject: (error) => finish(error),\n };\n const abort = () => finish(new Error(`CDP ${method} wait cancelled.`));\n const timer = setTimeout(\n () => finish(new Error(`CDP event ${method} exceeded ${timeoutMs} ms.`)),\n timeoutMs,\n );\n this.listeners.add(listener);\n options.signal?.addEventListener('abort', abort, { once: true });\n if (options.signal?.aborted) abort();\n else if (this.socket?.readyState !== WebSocket.OPEN)\n finish(new Error('CDP connection is closed.'));\n });\n // A caller commonly registers a waiter before an action, then awaits it afterward.\n void promise.catch(() => {});\n return promise;\n }\n\n private fail(error: Error) {\n for (const request of [...this.pending.values()]) request.reject(error);\n for (const listener of [...this.listeners]) listener.reject(error);\n }\n close() {\n this.closed = true;\n this.activity.targets.clear();\n this.activity.parents.clear();\n this.activity.targetId = undefined;\n void this.delegate?.then((connection) => connection.close()).catch(() => {});\n this.fail(new Error('CDP connection closed.'));\n this.socket?.close();\n }\n}\n"]}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { AgentMessage, StreamFn } from '@earendil-works/pi-agent-core';
|
|
2
|
+
import type { Api, Model, Usage } from '@earendil-works/pi-ai';
|
|
3
|
+
/** Wire metadata and encrypted reasoning are not ordinary text tokens. */
|
|
4
|
+
export declare function contextChars(messages: AgentMessage[]): number;
|
|
5
|
+
/** A provider projection; the original transcript remains available for accounting and audit. */
|
|
6
|
+
export declare class RunContext {
|
|
7
|
+
private model;
|
|
8
|
+
private stream;
|
|
9
|
+
private workspace;
|
|
10
|
+
private maxChars;
|
|
11
|
+
private enabled;
|
|
12
|
+
private secrets;
|
|
13
|
+
private covered;
|
|
14
|
+
private summary;
|
|
15
|
+
private usageAfter;
|
|
16
|
+
compactions: number;
|
|
17
|
+
usage: Usage[];
|
|
18
|
+
constructor(model: Model<Api>, stream: StreamFn, workspace: string, maxChars: number, enabled: boolean, secrets?: string[]);
|
|
19
|
+
project(messages: AgentMessage[]): AgentMessage[];
|
|
20
|
+
tokens(messages: AgentMessage[], system: string): number;
|
|
21
|
+
needsCompaction(messages: AgentMessage[], system: string): boolean;
|
|
22
|
+
fits(messages: AgentMessage[], system: string): boolean;
|
|
23
|
+
prepare(messages: AgentMessage[], system: string, signal?: AbortSignal): Promise<void>;
|
|
24
|
+
}
|
package/dist/context.js
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { estimateTokens, generateSummaryWithUsage } from '@earendil-works/pi-coding-agent';
|
|
2
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { randomUUID } from 'node:crypto';
|
|
5
|
+
import { redact } from './history.js';
|
|
6
|
+
/** Wire metadata and encrypted reasoning are not ordinary text tokens. */
|
|
7
|
+
export function contextChars(messages) {
|
|
8
|
+
return JSON.stringify(messages, (key, value) => {
|
|
9
|
+
if (key === 'thinkingSignature' || key === 'textSignature')
|
|
10
|
+
return undefined;
|
|
11
|
+
if (value && typeof value === 'object' && 'role' in value && value.role === 'toolResult') {
|
|
12
|
+
const { details: _details, ...message } = value;
|
|
13
|
+
return message;
|
|
14
|
+
}
|
|
15
|
+
if (value && typeof value === 'object' && 'type' in value && value.type === 'image')
|
|
16
|
+
return { type: 'image' };
|
|
17
|
+
return value;
|
|
18
|
+
}).length;
|
|
19
|
+
}
|
|
20
|
+
/** A provider projection; the original transcript remains available for accounting and audit. */
|
|
21
|
+
export class RunContext {
|
|
22
|
+
model;
|
|
23
|
+
stream;
|
|
24
|
+
workspace;
|
|
25
|
+
maxChars;
|
|
26
|
+
enabled;
|
|
27
|
+
secrets;
|
|
28
|
+
covered = 0;
|
|
29
|
+
summary;
|
|
30
|
+
usageAfter = 0;
|
|
31
|
+
compactions = 0;
|
|
32
|
+
usage = [];
|
|
33
|
+
constructor(model, stream, workspace, maxChars, enabled, secrets = []) {
|
|
34
|
+
this.model = model;
|
|
35
|
+
this.stream = stream;
|
|
36
|
+
this.workspace = workspace;
|
|
37
|
+
this.maxChars = maxChars;
|
|
38
|
+
this.enabled = enabled;
|
|
39
|
+
this.secrets = secrets;
|
|
40
|
+
}
|
|
41
|
+
project(messages) {
|
|
42
|
+
const projected = this.summary ? [this.summary, ...messages.slice(this.covered)] : messages;
|
|
43
|
+
const images = projected.filter((m) => m.role === 'toolResult' && m.content.some((c) => c.type === 'image'));
|
|
44
|
+
const keep = new Set(images.slice(-2));
|
|
45
|
+
return projected.map((m) => m.role === 'toolResult' && !keep.has(m)
|
|
46
|
+
? { ...m, content: m.content.filter((c) => c.type !== 'image') }
|
|
47
|
+
: m);
|
|
48
|
+
}
|
|
49
|
+
tokens(messages, system) {
|
|
50
|
+
const projected = this.project(messages);
|
|
51
|
+
const estimate = projected.reduce((sum, m) => sum + estimateTokens(m), Math.ceil(system.length / 4));
|
|
52
|
+
for (let i = messages.length - 1; i >= this.usageAfter; i--) {
|
|
53
|
+
const m = messages[i];
|
|
54
|
+
if (m.role === 'assistant' &&
|
|
55
|
+
!['error', 'aborted'].includes(m.stopReason) &&
|
|
56
|
+
m.usage.totalTokens > 0)
|
|
57
|
+
return Math.max(estimate, m.usage.totalTokens +
|
|
58
|
+
messages.slice(i + 1).reduce((sum, t) => sum + estimateTokens(t), 0));
|
|
59
|
+
}
|
|
60
|
+
return estimate;
|
|
61
|
+
}
|
|
62
|
+
needsCompaction(messages, system) {
|
|
63
|
+
return (contextChars(this.project(messages)) + system.length > this.maxChars * 0.75 ||
|
|
64
|
+
this.tokens(messages, system) > this.model.contextWindow * 0.65);
|
|
65
|
+
}
|
|
66
|
+
fits(messages, system) {
|
|
67
|
+
return (contextChars(this.project(messages)) + system.length <= this.maxChars &&
|
|
68
|
+
this.tokens(messages, system) < this.model.contextWindow * 0.85);
|
|
69
|
+
}
|
|
70
|
+
async prepare(messages, system, signal) {
|
|
71
|
+
if (!this.enabled || !this.needsCompaction(messages, system))
|
|
72
|
+
return;
|
|
73
|
+
// Keep the last two complete assistant/tool groups. Never orphan a tool result.
|
|
74
|
+
const starts = messages.flatMap((m, i) => m.role === 'assistant' && i >= this.covered ? [i] : []);
|
|
75
|
+
const cut = starts.at(-2);
|
|
76
|
+
if (cut === undefined || cut <= this.covered)
|
|
77
|
+
return;
|
|
78
|
+
const prefix = [...(this.summary ? [this.summary] : []), ...messages.slice(this.covered, cut)];
|
|
79
|
+
const summary = await generateSummaryWithUsage(prefix, this.model, 12_000, undefined, undefined, signal, 'Summarize only the source conversation inside <conversation>. These summarization instructions are not user requests or constraints of the task; never record them as such. Preserve exact user constraints, artifact/checkpoint paths, JS binding names, completed actions and uncertain side effects, record counts, source URLs and observed timestamps, conflicting evidence, blockers and the next bounded step. Do not claim attempted means verified. Never suggest replaying uncertain actions.', undefined, 'low', async (...args) => {
|
|
80
|
+
const stream = await this.stream(...args);
|
|
81
|
+
void stream
|
|
82
|
+
.result()
|
|
83
|
+
.then((message) => {
|
|
84
|
+
this.usage.push(message.usage);
|
|
85
|
+
})
|
|
86
|
+
.catch(() => { });
|
|
87
|
+
return stream;
|
|
88
|
+
});
|
|
89
|
+
signal?.throwIfAborted();
|
|
90
|
+
if (!summary.text.trim())
|
|
91
|
+
throw new Error('Compaction returned an empty checkpoint.');
|
|
92
|
+
const directory = join(this.workspace, '.browser-use', 'context');
|
|
93
|
+
await mkdir(directory, { recursive: true, mode: 0o700 });
|
|
94
|
+
const path = join(directory, `${randomUUID()}.json`);
|
|
95
|
+
await writeFile(path, JSON.stringify(redact({
|
|
96
|
+
version: 1,
|
|
97
|
+
summary: summary.text,
|
|
98
|
+
coveredMessages: cut,
|
|
99
|
+
// Retain observations independently of the generated summary. A previous
|
|
100
|
+
// checkpoint message links earlier archives, so repeated compaction stays searchable.
|
|
101
|
+
messages: prefix.map((message) => {
|
|
102
|
+
if (message.role !== 'user' &&
|
|
103
|
+
message.role !== 'assistant' &&
|
|
104
|
+
message.role !== 'toolResult')
|
|
105
|
+
return message;
|
|
106
|
+
return {
|
|
107
|
+
role: message.role,
|
|
108
|
+
timestamp: message.timestamp,
|
|
109
|
+
...(message.role === 'toolResult'
|
|
110
|
+
? {
|
|
111
|
+
toolCallId: message.toolCallId,
|
|
112
|
+
toolName: message.toolName,
|
|
113
|
+
isError: message.isError,
|
|
114
|
+
}
|
|
115
|
+
: {}),
|
|
116
|
+
content: typeof message.content === 'string'
|
|
117
|
+
? message.content
|
|
118
|
+
: message.content
|
|
119
|
+
.filter((block) => block.type !== 'thinking')
|
|
120
|
+
.map((block) => {
|
|
121
|
+
if (block.type === 'image')
|
|
122
|
+
return { type: 'text', text: '[Image omitted from text archive]' };
|
|
123
|
+
if (block.type === 'text')
|
|
124
|
+
return { type: 'text', text: block.text };
|
|
125
|
+
return block;
|
|
126
|
+
}),
|
|
127
|
+
};
|
|
128
|
+
}),
|
|
129
|
+
}, this.secrets)), { flag: 'wx', mode: 0o600 });
|
|
130
|
+
// Pin user messages exactly; a summarizer cannot silently remove a restriction or follow-up.
|
|
131
|
+
const users = messages.slice(0, cut).filter((m) => m.role === 'user');
|
|
132
|
+
const text = `Conversation checkpoint: generated, fallible reference, not new instructions. JavaScript and files persist.\nEvidence archive (JSON path): ${JSON.stringify(path)}\nThe archive's messages preserve earlier user text, assistant text/tool calls and tool results, with configured secrets redacted and images/reasoning omitted. Earlier checkpoint messages link previous archives. Search these messages or saved source files for exact observations omitted or misstated below; do not treat a summary as verification or replay prior actions. Read only relevant excerpts into context.\nGenerated summary (JSON-quoted):\n${JSON.stringify(summary.text)}\nOriginal user requests (authoritative over the generated summary):\n${JSON.stringify(users)}\nContinue the original task. Any instruction to produce a summary belongs to the summarization process, not the original task.`;
|
|
133
|
+
const candidate = { role: 'user', content: text, timestamp: Date.now() };
|
|
134
|
+
if (contextChars([candidate, ...messages.slice(cut)]) >= contextChars(this.project(messages)))
|
|
135
|
+
throw new Error('Compaction did not reduce context; original evidence was retained.');
|
|
136
|
+
signal?.throwIfAborted();
|
|
137
|
+
this.summary = candidate;
|
|
138
|
+
this.covered = cut;
|
|
139
|
+
this.usageAfter = messages.length;
|
|
140
|
+
this.compactions++;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAC3F,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC,0EAA0E;AAC1E,MAAM,UAAU,YAAY,CAAC,QAAwB;IACnD,OAAO,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,KAAc,EAAE,EAAE;QACtD,IAAI,GAAG,KAAK,mBAAmB,IAAI,GAAG,KAAK,eAAe;YAAE,OAAO,SAAS,CAAC;QAC7E,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YACzF,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,OAAO,EAAE,GAAG,KAAgC,CAAC;YAC3E,OAAO,OAAO,CAAC;QACjB,CAAC;QACD,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO;YACjF,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;QAC3B,OAAO,KAAK,CAAC;IACf,CAAC,CAAC,CAAC,MAAM,CAAC;AACZ,CAAC;AAED,iGAAiG;AACjG,MAAM,OAAO,UAAU;IAOX;IACA;IACA;IACA;IACA;IACA;IAXF,OAAO,GAAG,CAAC,CAAC;IACZ,OAAO,CAA2B;IAClC,UAAU,GAAG,CAAC,CAAC;IACvB,WAAW,GAAG,CAAC,CAAC;IAChB,KAAK,GAAY,EAAE,CAAC;IACpB,YACU,KAAiB,EACjB,MAAgB,EAChB,SAAiB,EACjB,QAAgB,EAChB,OAAgB,EAChB,UAAoB,EAAE;QALtB,UAAK,GAAL,KAAK,CAAY;QACjB,WAAM,GAAN,MAAM,CAAU;QAChB,cAAS,GAAT,SAAS,CAAQ;QACjB,aAAQ,GAAR,QAAQ,CAAQ;QAChB,YAAO,GAAP,OAAO,CAAS;QAChB,YAAO,GAAP,OAAO,CAAe;IAC7B,CAAC;IACJ,OAAO,CAAC,QAAwB;QAC9B,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;QAC5F,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,CAC7B,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,YAAY,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAC5E,CAAC;QACF,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACvC,OAAO,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CACzB,CAAC,CAAC,IAAI,KAAK,YAAY,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;YACrC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,EAAE;YAChE,CAAC,CAAC,CAAC,CACN,CAAC;IACJ,CAAC;IACD,MAAM,CAAC,QAAwB,EAAE,MAAc;QAC7C,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACzC,MAAM,QAAQ,GAAG,SAAS,CAAC,MAAM,CAC/B,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,cAAc,CAAC,CAAC,CAAC,EACnC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAC7B,CAAC;QACF,KAAK,IAAI,CAAC,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC,EAAE,EAAE,CAAC;YAC5D,MAAM,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAE,CAAC;YACvB,IACE,CAAC,CAAC,IAAI,KAAK,WAAW;gBACtB,CAAC,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC;gBAC5C,CAAC,CAAC,KAAK,CAAC,WAAW,GAAG,CAAC;gBAEvB,OAAO,IAAI,CAAC,GAAG,CACb,QAAQ,EACR,CAAC,CAAC,KAAK,CAAC,WAAW;oBACjB,QAAQ,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CACvE,CAAC;QACN,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,eAAe,CAAC,QAAwB,EAAE,MAAc;QACtD,OAAO,CACL,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,QAAQ,GAAG,IAAI;YAC3E,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,GAAG,IAAI,CAChE,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,QAAwB,EAAE,MAAc;QAC3C,OAAO,CACL,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,IAAI,IAAI,CAAC,QAAQ;YACrE,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,GAAG,IAAI,CAChE,CAAC;IACJ,CAAC;IACD,KAAK,CAAC,OAAO,CAAC,QAAwB,EAAE,MAAc,EAAE,MAAoB;QAC1E,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,MAAM,CAAC;YAAE,OAAO;QACrE,gFAAgF;QAChF,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACvC,CAAC,CAAC,IAAI,KAAK,WAAW,IAAI,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CACvD,CAAC;QACF,MAAM,GAAG,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1B,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO;QACrD,MAAM,MAAM,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;QAC/F,MAAM,OAAO,GAAG,MAAM,wBAAwB,CAC5C,MAAM,EACN,IAAI,CAAC,KAAK,EACV,MAAM,EACN,SAAS,EACT,SAAS,EACT,MAAM,EACN,yeAAye,EACze,SAAS,EACT,KAAK,EACL,KAAK,EAAE,GAAG,IAAI,EAAE,EAAE;YAChB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;YAC1C,KAAK,MAAM;iBACR,MAAM,EAAE;iBACR,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE;gBAChB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YACjC,CAAC,CAAC;iBACD,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YACnB,OAAO,MAAM,CAAC;QAChB,CAAC,CACF,CAAC;QACF,MAAM,EAAE,cAAc,EAAE,CAAC;QACzB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;QACtF,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,EAAE,SAAS,CAAC,CAAC;QAClE,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACzD,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,EAAE,GAAG,UAAU,EAAE,OAAO,CAAC,CAAC;QACrD,MAAM,SAAS,CACb,IAAI,EACJ,IAAI,CAAC,SAAS,CACZ,MAAM,CACJ;YACE,OAAO,EAAE,CAAC;YACV,OAAO,EAAE,OAAO,CAAC,IAAI;YACrB,eAAe,EAAE,GAAG;YACpB,yEAAyE;YACzE,sFAAsF;YACtF,QAAQ,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;gBAC/B,IACE,OAAO,CAAC,IAAI,KAAK,MAAM;oBACvB,OAAO,CAAC,IAAI,KAAK,WAAW;oBAC5B,OAAO,CAAC,IAAI,KAAK,YAAY;oBAE7B,OAAO,OAAO,CAAC;gBACjB,OAAO;oBACL,IAAI,EAAE,OAAO,CAAC,IAAI;oBAClB,SAAS,EAAE,OAAO,CAAC,SAAS;oBAC5B,GAAG,CAAC,OAAO,CAAC,IAAI,KAAK,YAAY;wBAC/B,CAAC,CAAC;4BACE,UAAU,EAAE,OAAO,CAAC,UAAU;4BAC9B,QAAQ,EAAE,OAAO,CAAC,QAAQ;4BAC1B,OAAO,EAAE,OAAO,CAAC,OAAO;yBACzB;wBACH,CAAC,CAAC,EAAE,CAAC;oBACP,OAAO,EACL,OAAO,OAAO,CAAC,OAAO,KAAK,QAAQ;wBACjC,CAAC,CAAC,OAAO,CAAC,OAAO;wBACjB,CAAC,CAAC,OAAO,CAAC,OAAO;6BACZ,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,UAAU,CAAC;6BAC5C,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;4BACb,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO;gCACxB,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,mCAAmC,EAAE,CAAC;4BACrE,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM;gCAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC;4BACrE,OAAO,KAAK,CAAC;wBACf,CAAC,CAAC;iBACX,CAAC;YACJ,CAAC,CAAC;SACH,EACD,IAAI,CAAC,OAAO,CACb,CACF,EACD,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAC5B,CAAC;QACF,6FAA6F;QAC7F,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC;QACtE,MAAM,IAAI,GAAG,8IAA8I,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,mcAAmc,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,yEAAyE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,iIAAiI,CAAC;QAC92B,MAAM,SAAS,GAAiB,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;QACvF,IAAI,YAAY,CAAC,CAAC,SAAS,EAAE,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;YAC3F,MAAM,IAAI,KAAK,CAAC,oEAAoE,CAAC,CAAC;QACxF,MAAM,EAAE,cAAc,EAAE,CAAC;QACzB,IAAI,CAAC,OAAO,GAAG,SAAS,CAAC;QACzB,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC;QACnB,IAAI,CAAC,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC;QAClC,IAAI,CAAC,WAAW,EAAE,CAAC;IACrB,CAAC;CACF","sourcesContent":["import type { AgentMessage, StreamFn } from '@earendil-works/pi-agent-core';\nimport type { Api, Model, Usage } from '@earendil-works/pi-ai';\nimport { estimateTokens, generateSummaryWithUsage } from '@earendil-works/pi-coding-agent';\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { randomUUID } from 'node:crypto';\nimport { redact } from './history.js';\n\n/** Wire metadata and encrypted reasoning are not ordinary text tokens. */\nexport function contextChars(messages: AgentMessage[]): number {\n return JSON.stringify(messages, (key, value: unknown) => {\n if (key === 'thinkingSignature' || key === 'textSignature') return undefined;\n if (value && typeof value === 'object' && 'role' in value && value.role === 'toolResult') {\n const { details: _details, ...message } = value as Record<string, unknown>;\n return message;\n }\n if (value && typeof value === 'object' && 'type' in value && value.type === 'image')\n return { type: 'image' };\n return value;\n }).length;\n}\n\n/** A provider projection; the original transcript remains available for accounting and audit. */\nexport class RunContext {\n private covered = 0;\n private summary: AgentMessage | undefined;\n private usageAfter = 0;\n compactions = 0;\n usage: Usage[] = [];\n constructor(\n private model: Model<Api>,\n private stream: StreamFn,\n private workspace: string,\n private maxChars: number,\n private enabled: boolean,\n private secrets: string[] = [],\n ) {}\n project(messages: AgentMessage[]): AgentMessage[] {\n const projected = this.summary ? [this.summary, ...messages.slice(this.covered)] : messages;\n const images = projected.filter(\n (m) => m.role === 'toolResult' && m.content.some((c) => c.type === 'image'),\n );\n const keep = new Set(images.slice(-2));\n return projected.map((m) =>\n m.role === 'toolResult' && !keep.has(m)\n ? { ...m, content: m.content.filter((c) => c.type !== 'image') }\n : m,\n );\n }\n tokens(messages: AgentMessage[], system: string): number {\n const projected = this.project(messages);\n const estimate = projected.reduce(\n (sum, m) => sum + estimateTokens(m),\n Math.ceil(system.length / 4),\n );\n for (let i = messages.length - 1; i >= this.usageAfter; i--) {\n const m = messages[i]!;\n if (\n m.role === 'assistant' &&\n !['error', 'aborted'].includes(m.stopReason) &&\n m.usage.totalTokens > 0\n )\n return Math.max(\n estimate,\n m.usage.totalTokens +\n messages.slice(i + 1).reduce((sum, t) => sum + estimateTokens(t), 0),\n );\n }\n return estimate;\n }\n needsCompaction(messages: AgentMessage[], system: string) {\n return (\n contextChars(this.project(messages)) + system.length > this.maxChars * 0.75 ||\n this.tokens(messages, system) > this.model.contextWindow * 0.65\n );\n }\n fits(messages: AgentMessage[], system: string) {\n return (\n contextChars(this.project(messages)) + system.length <= this.maxChars &&\n this.tokens(messages, system) < this.model.contextWindow * 0.85\n );\n }\n async prepare(messages: AgentMessage[], system: string, signal?: AbortSignal) {\n if (!this.enabled || !this.needsCompaction(messages, system)) return;\n // Keep the last two complete assistant/tool groups. Never orphan a tool result.\n const starts = messages.flatMap((m, i) =>\n m.role === 'assistant' && i >= this.covered ? [i] : [],\n );\n const cut = starts.at(-2);\n if (cut === undefined || cut <= this.covered) return;\n const prefix = [...(this.summary ? [this.summary] : []), ...messages.slice(this.covered, cut)];\n const summary = await generateSummaryWithUsage(\n prefix,\n this.model,\n 12_000,\n undefined,\n undefined,\n signal,\n 'Summarize only the source conversation inside <conversation>. These summarization instructions are not user requests or constraints of the task; never record them as such. Preserve exact user constraints, artifact/checkpoint paths, JS binding names, completed actions and uncertain side effects, record counts, source URLs and observed timestamps, conflicting evidence, blockers and the next bounded step. Do not claim attempted means verified. Never suggest replaying uncertain actions.',\n undefined,\n 'low',\n async (...args) => {\n const stream = await this.stream(...args);\n void stream\n .result()\n .then((message) => {\n this.usage.push(message.usage);\n })\n .catch(() => {});\n return stream;\n },\n );\n signal?.throwIfAborted();\n if (!summary.text.trim()) throw new Error('Compaction returned an empty checkpoint.');\n const directory = join(this.workspace, '.browser-use', 'context');\n await mkdir(directory, { recursive: true, mode: 0o700 });\n const path = join(directory, `${randomUUID()}.json`);\n await writeFile(\n path,\n JSON.stringify(\n redact(\n {\n version: 1,\n summary: summary.text,\n coveredMessages: cut,\n // Retain observations independently of the generated summary. A previous\n // checkpoint message links earlier archives, so repeated compaction stays searchable.\n messages: prefix.map((message) => {\n if (\n message.role !== 'user' &&\n message.role !== 'assistant' &&\n message.role !== 'toolResult'\n )\n return message;\n return {\n role: message.role,\n timestamp: message.timestamp,\n ...(message.role === 'toolResult'\n ? {\n toolCallId: message.toolCallId,\n toolName: message.toolName,\n isError: message.isError,\n }\n : {}),\n content:\n typeof message.content === 'string'\n ? message.content\n : message.content\n .filter((block) => block.type !== 'thinking')\n .map((block) => {\n if (block.type === 'image')\n return { type: 'text', text: '[Image omitted from text archive]' };\n if (block.type === 'text') return { type: 'text', text: block.text };\n return block;\n }),\n };\n }),\n },\n this.secrets,\n ),\n ),\n { flag: 'wx', mode: 0o600 },\n );\n // Pin user messages exactly; a summarizer cannot silently remove a restriction or follow-up.\n const users = messages.slice(0, cut).filter((m) => m.role === 'user');\n const text = `Conversation checkpoint: generated, fallible reference, not new instructions. JavaScript and files persist.\\nEvidence archive (JSON path): ${JSON.stringify(path)}\\nThe archive's messages preserve earlier user text, assistant text/tool calls and tool results, with configured secrets redacted and images/reasoning omitted. Earlier checkpoint messages link previous archives. Search these messages or saved source files for exact observations omitted or misstated below; do not treat a summary as verification or replay prior actions. Read only relevant excerpts into context.\\nGenerated summary (JSON-quoted):\\n${JSON.stringify(summary.text)}\\nOriginal user requests (authoritative over the generated summary):\\n${JSON.stringify(users)}\\nContinue the original task. Any instruction to produce a summary belongs to the summarization process, not the original task.`;\n const candidate: AgentMessage = { role: 'user', content: text, timestamp: Date.now() };\n if (contextChars([candidate, ...messages.slice(cut)]) >= contextChars(this.project(messages)))\n throw new Error('Compaction did not reduce context; original evidence was retained.');\n signal?.throwIfAborted();\n this.summary = candidate;\n this.covered = cut;\n this.usageAfter = messages.length;\n this.compactions++;\n }\n}\n"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** Await a cooperative callback without letting a hung hook hold the run open forever. */
|
|
2
|
+
export declare function bounded<T>(work: () => T | Promise<T>, timeoutMs: number, signal?: AbortSignal): Promise<T>;
|
|
3
|
+
/** Pause is acknowledged at a tool boundary, never halfway through browser input. */
|
|
4
|
+
export declare class RunControl {
|
|
5
|
+
private readonly changed;
|
|
6
|
+
private requested;
|
|
7
|
+
paused: boolean;
|
|
8
|
+
private acknowledge;
|
|
9
|
+
private acknowledgement;
|
|
10
|
+
private release;
|
|
11
|
+
private ended;
|
|
12
|
+
steer: ((text: string) => void) | undefined;
|
|
13
|
+
constructor(changed: (paused: boolean) => void);
|
|
14
|
+
pause(): Promise<void>;
|
|
15
|
+
checkpoint(signal?: AbortSignal): Promise<void>;
|
|
16
|
+
resume(): void;
|
|
17
|
+
finish(): void;
|
|
18
|
+
}
|
package/dist/control.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/** Await a cooperative callback without letting a hung hook hold the run open forever. */
|
|
2
|
+
export async function bounded(work, timeoutMs, signal) {
|
|
3
|
+
signal?.throwIfAborted();
|
|
4
|
+
let timer;
|
|
5
|
+
let abort;
|
|
6
|
+
const interrupted = new Promise((_resolve, reject) => {
|
|
7
|
+
timer = setTimeout(() => reject(new Error(`Hook exceeded ${timeoutMs} ms.`)), timeoutMs);
|
|
8
|
+
abort = () => reject(new Error('Run cancelled while awaiting hook.'));
|
|
9
|
+
signal?.addEventListener('abort', abort, { once: true });
|
|
10
|
+
});
|
|
11
|
+
try {
|
|
12
|
+
return await Promise.race([Promise.resolve().then(work), interrupted]);
|
|
13
|
+
}
|
|
14
|
+
finally {
|
|
15
|
+
clearTimeout(timer);
|
|
16
|
+
if (abort)
|
|
17
|
+
signal?.removeEventListener('abort', abort);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/** Pause is acknowledged at a tool boundary, never halfway through browser input. */
|
|
21
|
+
export class RunControl {
|
|
22
|
+
changed;
|
|
23
|
+
requested = false;
|
|
24
|
+
paused = false;
|
|
25
|
+
acknowledge;
|
|
26
|
+
acknowledgement;
|
|
27
|
+
release;
|
|
28
|
+
ended = false;
|
|
29
|
+
steer;
|
|
30
|
+
constructor(changed) {
|
|
31
|
+
this.changed = changed;
|
|
32
|
+
}
|
|
33
|
+
pause() {
|
|
34
|
+
if (this.ended)
|
|
35
|
+
return Promise.resolve();
|
|
36
|
+
if (!this.acknowledgement) {
|
|
37
|
+
this.requested = true;
|
|
38
|
+
this.acknowledgement = new Promise((resolve) => {
|
|
39
|
+
this.acknowledge = resolve;
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
return this.acknowledgement;
|
|
43
|
+
}
|
|
44
|
+
async checkpoint(signal) {
|
|
45
|
+
signal?.throwIfAborted();
|
|
46
|
+
if (!this.requested || this.ended)
|
|
47
|
+
return;
|
|
48
|
+
const resumed = new Promise((resolve) => {
|
|
49
|
+
this.release = resolve;
|
|
50
|
+
});
|
|
51
|
+
this.paused = true;
|
|
52
|
+
this.changed(true);
|
|
53
|
+
this.acknowledge?.();
|
|
54
|
+
const abort = () => this.resume();
|
|
55
|
+
signal?.addEventListener('abort', abort, { once: true });
|
|
56
|
+
if (signal?.aborted)
|
|
57
|
+
abort();
|
|
58
|
+
try {
|
|
59
|
+
await resumed;
|
|
60
|
+
signal?.throwIfAborted();
|
|
61
|
+
}
|
|
62
|
+
finally {
|
|
63
|
+
signal?.removeEventListener('abort', abort);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
resume() {
|
|
67
|
+
const wasPaused = this.paused;
|
|
68
|
+
this.requested = false;
|
|
69
|
+
this.paused = false;
|
|
70
|
+
this.acknowledge?.();
|
|
71
|
+
this.release?.();
|
|
72
|
+
this.release = undefined;
|
|
73
|
+
this.acknowledgement = undefined;
|
|
74
|
+
this.acknowledge = undefined;
|
|
75
|
+
if (wasPaused)
|
|
76
|
+
this.changed(false);
|
|
77
|
+
}
|
|
78
|
+
finish() {
|
|
79
|
+
this.ended = true;
|
|
80
|
+
this.resume();
|
|
81
|
+
this.steer = undefined;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=control.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"control.js","sourceRoot":"","sources":["../src/control.ts"],"names":[],"mappings":"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","sourcesContent":["/** Await a cooperative callback without letting a hung hook hold the run open forever. */\nexport async function bounded<T>(\n work: () => T | Promise<T>,\n timeoutMs: number,\n signal?: AbortSignal,\n): Promise<T> {\n signal?.throwIfAborted();\n let timer: ReturnType<typeof setTimeout> | undefined;\n let abort: (() => void) | undefined;\n const interrupted = new Promise<never>((_resolve, reject) => {\n timer = setTimeout(() => reject(new Error(`Hook exceeded ${timeoutMs} ms.`)), timeoutMs);\n abort = () => reject(new Error('Run cancelled while awaiting hook.'));\n signal?.addEventListener('abort', abort, { once: true });\n });\n try {\n return await Promise.race([Promise.resolve().then(work), interrupted]);\n } finally {\n clearTimeout(timer);\n if (abort) signal?.removeEventListener('abort', abort);\n }\n}\n\n/** Pause is acknowledged at a tool boundary, never halfway through browser input. */\nexport class RunControl {\n private requested = false;\n paused = false;\n private acknowledge: (() => void) | undefined;\n private acknowledgement: Promise<void> | undefined;\n private release: (() => void) | undefined;\n private ended = false;\n steer: ((text: string) => void) | undefined;\n\n constructor(private readonly changed: (paused: boolean) => void) {}\n\n pause(): Promise<void> {\n if (this.ended) return Promise.resolve();\n if (!this.acknowledgement) {\n this.requested = true;\n this.acknowledgement = new Promise((resolve) => {\n this.acknowledge = resolve;\n });\n }\n return this.acknowledgement;\n }\n\n async checkpoint(signal?: AbortSignal): Promise<void> {\n signal?.throwIfAborted();\n if (!this.requested || this.ended) return;\n const resumed = new Promise<void>((resolve) => {\n this.release = resolve;\n });\n this.paused = true;\n this.changed(true);\n this.acknowledge?.();\n const abort = () => this.resume();\n signal?.addEventListener('abort', abort, { once: true });\n if (signal?.aborted) abort();\n try {\n await resumed;\n signal?.throwIfAborted();\n } finally {\n signal?.removeEventListener('abort', abort);\n }\n }\n\n resume() {\n const wasPaused = this.paused;\n this.requested = false;\n this.paused = false;\n this.acknowledge?.();\n this.release?.();\n this.release = undefined;\n this.acknowledgement = undefined;\n this.acknowledge = undefined;\n if (wasPaused) this.changed(false);\n }\n\n finish() {\n this.ended = true;\n this.resume();\n this.steer = undefined;\n }\n}\n"]}
|
package/dist/events.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { AgentEvent } from '@earendil-works/pi-agent-core';
|
|
2
|
+
import type { RunResult } from './types.js';
|
|
3
|
+
export type SessionEventData = {
|
|
4
|
+
type: 'run_start';
|
|
5
|
+
task: string;
|
|
6
|
+
followUp: boolean;
|
|
7
|
+
} | {
|
|
8
|
+
type: 'agent_event';
|
|
9
|
+
event: AgentEvent;
|
|
10
|
+
} | {
|
|
11
|
+
type: 'run_end';
|
|
12
|
+
result: RunResult<unknown>;
|
|
13
|
+
} | {
|
|
14
|
+
type: 'paused' | 'resumed';
|
|
15
|
+
} | {
|
|
16
|
+
type: 'warning';
|
|
17
|
+
message: string;
|
|
18
|
+
};
|
|
19
|
+
export type SessionEvent = SessionEventData & {
|
|
20
|
+
sequence: number;
|
|
21
|
+
timestamp: number;
|
|
22
|
+
runId: string;
|
|
23
|
+
};
|
|
24
|
+
/** Slow consumers fail explicitly. They never stall the agent or grow an unbounded queue. */
|
|
25
|
+
export declare class EventStream implements AsyncIterableIterator<SessionEvent> {
|
|
26
|
+
private readonly dispose;
|
|
27
|
+
private readonly capacity;
|
|
28
|
+
private queue;
|
|
29
|
+
private bytes;
|
|
30
|
+
private wake;
|
|
31
|
+
private ended;
|
|
32
|
+
private error;
|
|
33
|
+
constructor(dispose: () => void, capacity?: number);
|
|
34
|
+
push(event: SessionEvent): void;
|
|
35
|
+
end(): void;
|
|
36
|
+
next(): Promise<IteratorResult<SessionEvent>>;
|
|
37
|
+
return(): Promise<IteratorResult<SessionEvent>>;
|
|
38
|
+
[Symbol.asyncIterator](): this;
|
|
39
|
+
}
|
|
40
|
+
export declare function formatEvent(event: SessionEvent): string | undefined;
|
package/dist/events.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/** Slow consumers fail explicitly. They never stall the agent or grow an unbounded queue. */
|
|
2
|
+
export class EventStream {
|
|
3
|
+
dispose;
|
|
4
|
+
capacity;
|
|
5
|
+
queue = [];
|
|
6
|
+
bytes = 0;
|
|
7
|
+
wake;
|
|
8
|
+
ended = false;
|
|
9
|
+
error;
|
|
10
|
+
constructor(dispose, capacity = 256) {
|
|
11
|
+
this.dispose = dispose;
|
|
12
|
+
this.capacity = capacity;
|
|
13
|
+
}
|
|
14
|
+
push(event) {
|
|
15
|
+
if (this.ended)
|
|
16
|
+
return;
|
|
17
|
+
const size = JSON.stringify(event).length;
|
|
18
|
+
if (this.queue.length >= this.capacity || this.bytes + size > 8_000_000) {
|
|
19
|
+
this.error = new Error('Event consumer fell behind. Read the persisted run log; resubscribe for live events.');
|
|
20
|
+
this.end();
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
this.queue.push(structuredClone(event));
|
|
24
|
+
this.bytes += size;
|
|
25
|
+
this.wake?.();
|
|
26
|
+
}
|
|
27
|
+
end() {
|
|
28
|
+
this.ended = true;
|
|
29
|
+
this.dispose();
|
|
30
|
+
this.wake?.();
|
|
31
|
+
}
|
|
32
|
+
async next() {
|
|
33
|
+
while (!this.queue.length && !this.ended)
|
|
34
|
+
await new Promise((resolve) => {
|
|
35
|
+
this.wake = resolve;
|
|
36
|
+
});
|
|
37
|
+
this.wake = undefined;
|
|
38
|
+
if (this.error) {
|
|
39
|
+
this.queue = [];
|
|
40
|
+
this.bytes = 0;
|
|
41
|
+
throw this.error;
|
|
42
|
+
}
|
|
43
|
+
const event = this.queue.shift();
|
|
44
|
+
if (event) {
|
|
45
|
+
this.bytes -= JSON.stringify(event).length;
|
|
46
|
+
return { value: event, done: false };
|
|
47
|
+
}
|
|
48
|
+
return { value: undefined, done: true };
|
|
49
|
+
}
|
|
50
|
+
async return() {
|
|
51
|
+
this.queue = [];
|
|
52
|
+
this.bytes = 0;
|
|
53
|
+
this.end();
|
|
54
|
+
return { value: undefined, done: true };
|
|
55
|
+
}
|
|
56
|
+
[Symbol.asyncIterator]() {
|
|
57
|
+
return this;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
export function formatEvent(event) {
|
|
61
|
+
const prefix = new Date(event.timestamp).toISOString().slice(11, 19);
|
|
62
|
+
if (event.type === 'run_start')
|
|
63
|
+
return `${prefix} ${event.followUp ? 'Continue' : 'Run'} ${event.runId}`;
|
|
64
|
+
if (event.type === 'paused' || event.type === 'resumed')
|
|
65
|
+
return `${prefix} ${event.type}`;
|
|
66
|
+
if (event.type === 'warning')
|
|
67
|
+
return `${prefix} warning: ${event.message}`;
|
|
68
|
+
if (event.type === 'run_end')
|
|
69
|
+
return `${prefix} ${event.result.status} · ${event.result.steps} turns · ${(event.result.durationMs / 1000).toFixed(1)}s · ~$${event.result.usage.cost.total.toFixed(4)} · ${event.result.workspace}`;
|
|
70
|
+
if (event.type === 'agent_event') {
|
|
71
|
+
const e = event.event;
|
|
72
|
+
if (e.type === 'tool_execution_start')
|
|
73
|
+
return `${prefix} → ${e.toolName}`;
|
|
74
|
+
if (e.type === 'tool_execution_end')
|
|
75
|
+
return `${prefix} ${e.isError ? '✗' : '✓'} ${e.toolName}`;
|
|
76
|
+
}
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentEvent } from '@earendil-works/pi-agent-core';\nimport type { RunResult } from './types.js';\n\nexport type SessionEventData =\n | { type: 'run_start'; task: string; followUp: boolean }\n | { type: 'agent_event'; event: AgentEvent }\n | { type: 'run_end'; result: RunResult<unknown> }\n | { type: 'paused' | 'resumed' }\n | { type: 'warning'; message: string };\nexport type SessionEvent = SessionEventData & {\n sequence: number;\n timestamp: number;\n runId: string;\n};\n\n/** Slow consumers fail explicitly. They never stall the agent or grow an unbounded queue. */\nexport class EventStream implements AsyncIterableIterator<SessionEvent> {\n private queue: SessionEvent[] = [];\n private bytes = 0;\n private wake: (() => void) | undefined;\n private ended = false;\n private error: Error | undefined;\n constructor(\n private readonly dispose: () => void,\n private readonly capacity = 256,\n ) {}\n push(event: SessionEvent) {\n if (this.ended) return;\n const size = JSON.stringify(event).length;\n if (this.queue.length >= this.capacity || this.bytes + size > 8_000_000) {\n this.error = new Error(\n 'Event consumer fell behind. Read the persisted run log; resubscribe for live events.',\n );\n this.end();\n return;\n }\n this.queue.push(structuredClone(event));\n this.bytes += size;\n this.wake?.();\n }\n end() {\n this.ended = true;\n this.dispose();\n this.wake?.();\n }\n async next(): Promise<IteratorResult<SessionEvent>> {\n while (!this.queue.length && !this.ended)\n await new Promise<void>((resolve) => {\n this.wake = resolve;\n });\n this.wake = undefined;\n if (this.error) {\n this.queue = [];\n this.bytes = 0;\n throw this.error;\n }\n const event = this.queue.shift();\n if (event) {\n this.bytes -= JSON.stringify(event).length;\n return { value: event, done: false };\n }\n return { value: undefined, done: true };\n }\n async return(): Promise<IteratorResult<SessionEvent>> {\n this.queue = [];\n this.bytes = 0;\n this.end();\n return { value: undefined, done: true };\n }\n [Symbol.asyncIterator]() {\n return this;\n }\n}\n\nexport function formatEvent(event: SessionEvent): string | undefined {\n const prefix = new Date(event.timestamp).toISOString().slice(11, 19);\n if (event.type === 'run_start')\n return `${prefix} ${event.followUp ? 'Continue' : 'Run'} ${event.runId}`;\n if (event.type === 'paused' || event.type === 'resumed') return `${prefix} ${event.type}`;\n if (event.type === 'warning') return `${prefix} warning: ${event.message}`;\n if (event.type === 'run_end')\n return `${prefix} ${event.result.status} · ${event.result.steps} turns · ${(event.result.durationMs / 1000).toFixed(1)}s · ~$${event.result.usage.cost.total.toFixed(4)} · ${event.result.workspace}`;\n if (event.type === 'agent_event') {\n const e = event.event;\n if (e.type === 'tool_execution_start') return `${prefix} → ${e.toolName}`;\n if (e.type === 'tool_execution_end') return `${prefix} ${e.isError ? '✗' : '✓'} ${e.toolName}`;\n }\n return undefined;\n}\n"]}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/** Browser Use's orange corner animation. Cosmetic, aria-hidden and pointer-transparent. */
|
|
2
|
+
export function actionHighlighter(browser) {
|
|
3
|
+
let generation = 0;
|
|
4
|
+
return async (method, raw, sessionId) => {
|
|
5
|
+
const params = raw;
|
|
6
|
+
if (!sessionId ||
|
|
7
|
+
!((method === 'Input.dispatchMouseEvent' && params.type === 'mouseReleased') ||
|
|
8
|
+
method === 'DOM.focus' ||
|
|
9
|
+
method === 'Input.insertText'))
|
|
10
|
+
return;
|
|
11
|
+
const current = ++generation;
|
|
12
|
+
try {
|
|
13
|
+
let node;
|
|
14
|
+
if (method === 'Input.dispatchMouseEvent') {
|
|
15
|
+
const hit = await browser.send('DOM.getNodeForLocation', {
|
|
16
|
+
x: Math.round(params.x),
|
|
17
|
+
y: Math.round(params.y),
|
|
18
|
+
}, sessionId);
|
|
19
|
+
node = { backendNodeId: hit.backendNodeId };
|
|
20
|
+
}
|
|
21
|
+
else if (method === 'DOM.focus') {
|
|
22
|
+
node =
|
|
23
|
+
params.backendNodeId !== undefined
|
|
24
|
+
? { backendNodeId: params.backendNodeId }
|
|
25
|
+
: params.nodeId !== undefined
|
|
26
|
+
? { nodeId: params.nodeId }
|
|
27
|
+
: params.objectId
|
|
28
|
+
? { objectId: params.objectId }
|
|
29
|
+
: {};
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
const { result } = await browser.send('Runtime.evaluate', {
|
|
33
|
+
expression: 'document.activeElement',
|
|
34
|
+
objectGroup: `bu-pi-highlight-${current}`,
|
|
35
|
+
}, sessionId);
|
|
36
|
+
if (!result.objectId)
|
|
37
|
+
return;
|
|
38
|
+
node = { objectId: result.objectId };
|
|
39
|
+
}
|
|
40
|
+
if (current !== generation)
|
|
41
|
+
return;
|
|
42
|
+
const objectId = node.objectId ?? (await browser.send('DOM.resolveNode', node, sessionId)).object.objectId;
|
|
43
|
+
if (!objectId)
|
|
44
|
+
return;
|
|
45
|
+
try {
|
|
46
|
+
if (current !== generation)
|
|
47
|
+
return;
|
|
48
|
+
await browser.send('Runtime.callFunctionOn', {
|
|
49
|
+
objectId,
|
|
50
|
+
functionDeclaration: drawCorners.toString(),
|
|
51
|
+
}, sessionId);
|
|
52
|
+
}
|
|
53
|
+
finally {
|
|
54
|
+
if (!node.objectId)
|
|
55
|
+
await browser.send('Runtime.releaseObject', { objectId }, sessionId).catch(() => { });
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
// Detached nodes, navigation and unsupported targets must not fail the action.
|
|
60
|
+
}
|
|
61
|
+
finally {
|
|
62
|
+
if (method === 'Input.insertText')
|
|
63
|
+
await browser
|
|
64
|
+
.send('Runtime.releaseObjectGroup', { objectGroup: `bu-pi-highlight-${current}` }, sessionId)
|
|
65
|
+
.catch(() => { });
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
// Geometry, color and timing follow browser_use/browser/session.py highlight_interaction_element.
|
|
70
|
+
function drawCorners() {
|
|
71
|
+
const doc = this.ownerDocument;
|
|
72
|
+
const rect = this.getBoundingClientRect();
|
|
73
|
+
if (!this.isConnected || !rect.width || !rect.height)
|
|
74
|
+
return;
|
|
75
|
+
doc.querySelector('[data-browser-use-interaction-highlight]')?.remove();
|
|
76
|
+
const host = doc.createElement('div');
|
|
77
|
+
host.setAttribute('data-browser-use-interaction-highlight', 'true');
|
|
78
|
+
host.setAttribute('aria-hidden', 'true');
|
|
79
|
+
host.style.cssText = `all:initial;position:absolute;left:${rect.left + doc.defaultView.scrollX}px;top:${rect.top + doc.defaultView.scrollY}px;width:${rect.width}px;height:${rect.height}px;pointer-events:none;z-index:2147483647;opacity:1;transition:opacity .3s;`;
|
|
80
|
+
const root = host.attachShadow({ mode: 'closed' });
|
|
81
|
+
const size = Math.max(8, Math.min(20, Math.min(rect.width, rect.height) * 0.35));
|
|
82
|
+
for (const [vertical, horizontal] of [
|
|
83
|
+
['top', 'left'],
|
|
84
|
+
['top', 'right'],
|
|
85
|
+
['bottom', 'left'],
|
|
86
|
+
['bottom', 'right'],
|
|
87
|
+
]) {
|
|
88
|
+
const corner = doc.createElement('div');
|
|
89
|
+
corner.style.cssText = `position:absolute;width:${size}px;height:${size}px;${vertical}:-10px;${horizontal}:-10px;border-${vertical}:3px solid rgb(255,127,39);border-${horizontal}:3px solid rgb(255,127,39);pointer-events:none;transition:all .15s ease-out;`;
|
|
90
|
+
root.append(corner);
|
|
91
|
+
setTimeout(() => {
|
|
92
|
+
corner.style.setProperty(vertical, '-3px');
|
|
93
|
+
corner.style.setProperty(horizontal, '-3px');
|
|
94
|
+
}, 10);
|
|
95
|
+
}
|
|
96
|
+
doc.documentElement.append(host);
|
|
97
|
+
setTimeout(() => {
|
|
98
|
+
host.style.opacity = '0';
|
|
99
|
+
setTimeout(() => host.remove(), 300);
|
|
100
|
+
}, 1000);
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=highlight.js.map
|