free-computer-use 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 (135) hide show
  1. package/.env.example +31 -0
  2. package/CHANGELOG.md +19 -0
  3. package/CONTRIBUTING.md +66 -0
  4. package/LICENSE +21 -0
  5. package/README.md +140 -0
  6. package/SECURITY.md +133 -0
  7. package/artifacts/benchmark-public.json +797 -0
  8. package/assets/readme/hero.svg +53 -0
  9. package/assets/readme/incident-demo.gif +0 -0
  10. package/assets/readme/incident-evidence.json +52 -0
  11. package/dist/actions/compiler.d.ts +5 -0
  12. package/dist/actions/compiler.js +16 -0
  13. package/dist/actions/compiler.js.map +1 -0
  14. package/dist/actions/executor.d.ts +38 -0
  15. package/dist/actions/executor.js +305 -0
  16. package/dist/actions/executor.js.map +1 -0
  17. package/dist/actions/policy.d.ts +4 -0
  18. package/dist/actions/policy.js +18 -0
  19. package/dist/actions/policy.js.map +1 -0
  20. package/dist/actions/schema.d.ts +4149 -0
  21. package/dist/actions/schema.js +59 -0
  22. package/dist/actions/schema.js.map +1 -0
  23. package/dist/adapters/generic.d.ts +14 -0
  24. package/dist/adapters/generic.js +33 -0
  25. package/dist/adapters/generic.js.map +1 -0
  26. package/dist/agent/Agent.d.ts +69 -0
  27. package/dist/agent/Agent.js +375 -0
  28. package/dist/agent/Agent.js.map +1 -0
  29. package/dist/agent/Control.d.ts +23 -0
  30. package/dist/agent/Control.js +51 -0
  31. package/dist/agent/Control.js.map +1 -0
  32. package/dist/agent/TokenBudget.d.ts +52 -0
  33. package/dist/agent/TokenBudget.js +47 -0
  34. package/dist/agent/TokenBudget.js.map +1 -0
  35. package/dist/agent/goalCriteria.d.ts +2 -0
  36. package/dist/agent/goalCriteria.js +13 -0
  37. package/dist/agent/goalCriteria.js.map +1 -0
  38. package/dist/browser/Browser.d.ts +72 -0
  39. package/dist/browser/Browser.js +378 -0
  40. package/dist/browser/Browser.js.map +1 -0
  41. package/dist/browser/DomExtractor.d.ts +6 -0
  42. package/dist/browser/DomExtractor.js +134 -0
  43. package/dist/browser/DomExtractor.js.map +1 -0
  44. package/dist/browser/Interaction.d.ts +43 -0
  45. package/dist/browser/Interaction.js +225 -0
  46. package/dist/browser/Interaction.js.map +1 -0
  47. package/dist/browser/NetworkGuardProxy.d.ts +31 -0
  48. package/dist/browser/NetworkGuardProxy.js +331 -0
  49. package/dist/browser/NetworkGuardProxy.js.map +1 -0
  50. package/dist/browser/Observer.d.ts +12 -0
  51. package/dist/browser/Observer.js +31 -0
  52. package/dist/browser/Observer.js.map +1 -0
  53. package/dist/browser/PageCompressor.d.ts +47 -0
  54. package/dist/browser/PageCompressor.js +62 -0
  55. package/dist/browser/PageCompressor.js.map +1 -0
  56. package/dist/browser/SecurityBoundaryError.d.ts +3 -0
  57. package/dist/browser/SecurityBoundaryError.js +4 -0
  58. package/dist/browser/SecurityBoundaryError.js.map +1 -0
  59. package/dist/browser/SelectorEngine.d.ts +18 -0
  60. package/dist/browser/SelectorEngine.js +72 -0
  61. package/dist/browser/SelectorEngine.js.map +1 -0
  62. package/dist/browser/types.d.ts +38 -0
  63. package/dist/browser/types.js +2 -0
  64. package/dist/browser/types.js.map +1 -0
  65. package/dist/cli/index.d.ts +2 -0
  66. package/dist/cli/index.js +284 -0
  67. package/dist/cli/index.js.map +1 -0
  68. package/dist/config.d.ts +11 -0
  69. package/dist/config.js +77 -0
  70. package/dist/config.js.map +1 -0
  71. package/dist/history/TraceStore.d.ts +29 -0
  72. package/dist/history/TraceStore.js +53 -0
  73. package/dist/history/TraceStore.js.map +1 -0
  74. package/dist/index.d.ts +18 -0
  75. package/dist/index.js +16 -0
  76. package/dist/index.js.map +1 -0
  77. package/dist/llm/ClaudeSubscriptionProvider.d.ts +26 -0
  78. package/dist/llm/ClaudeSubscriptionProvider.js +182 -0
  79. package/dist/llm/ClaudeSubscriptionProvider.js.map +1 -0
  80. package/dist/llm/CodexSubscriptionProvider.d.ts +26 -0
  81. package/dist/llm/CodexSubscriptionProvider.js +168 -0
  82. package/dist/llm/CodexSubscriptionProvider.js.map +1 -0
  83. package/dist/llm/FlashProvider.d.ts +27 -0
  84. package/dist/llm/FlashProvider.js +103 -0
  85. package/dist/llm/FlashProvider.js.map +1 -0
  86. package/dist/llm/LLMProvider.d.ts +37 -0
  87. package/dist/llm/LLMProvider.js +2 -0
  88. package/dist/llm/LLMProvider.js.map +1 -0
  89. package/dist/llm/cliEnvironment.d.ts +5 -0
  90. package/dist/llm/cliEnvironment.js +21 -0
  91. package/dist/llm/cliEnvironment.js.map +1 -0
  92. package/dist/llm/prompts.d.ts +4 -0
  93. package/dist/llm/prompts.js +12 -0
  94. package/dist/llm/prompts.js.map +1 -0
  95. package/dist/llm/structuredOutput.d.ts +3 -0
  96. package/dist/llm/structuredOutput.js +58 -0
  97. package/dist/llm/structuredOutput.js.map +1 -0
  98. package/dist/mcp/index.d.ts +13 -0
  99. package/dist/mcp/index.js +243 -0
  100. package/dist/mcp/index.js.map +1 -0
  101. package/dist/profile/ProfileStore.d.ts +7 -0
  102. package/dist/profile/ProfileStore.js +52 -0
  103. package/dist/profile/ProfileStore.js.map +1 -0
  104. package/dist/profile/VariableResolver.d.ts +15 -0
  105. package/dist/profile/VariableResolver.js +50 -0
  106. package/dist/profile/VariableResolver.js.map +1 -0
  107. package/dist/server/index.d.ts +14 -0
  108. package/dist/server/index.js +239 -0
  109. package/dist/server/index.js.map +1 -0
  110. package/dist/ui/app.js +132 -0
  111. package/dist/ui/index.html +29 -0
  112. package/dist/ui/logo.svg +5 -0
  113. package/dist/ui/results.js +59 -0
  114. package/dist/ui/style.css +33 -0
  115. package/dist/verification/Verifier.d.ts +72 -0
  116. package/dist/verification/Verifier.js +87 -0
  117. package/dist/verification/Verifier.js.map +1 -0
  118. package/dist/workflows/WorkflowEngine.d.ts +23 -0
  119. package/dist/workflows/WorkflowEngine.js +52 -0
  120. package/dist/workflows/WorkflowEngine.js.map +1 -0
  121. package/docs/ADOPTION.md +61 -0
  122. package/docs/ARCHITECTURE.md +65 -0
  123. package/docs/BENCHMARKS.md +64 -0
  124. package/docs/IMPLEMENTATION.md +93 -0
  125. package/docs/LOCAL_DATA.md +98 -0
  126. package/docs/LOCAL_VALIDATION.md +87 -0
  127. package/docs/MCP.md +81 -0
  128. package/docs/PROVIDERS.md +150 -0
  129. package/docs/RELEASE_CHECKLIST.md +37 -0
  130. package/docs/REQUIREMENTS.md +39 -0
  131. package/docs/SUPPORT_MATRIX.md +193 -0
  132. package/docs/THREAT_MODEL.md +108 -0
  133. package/docs/USEFUL_EXAMPLES.md +151 -0
  134. package/docs/brand-mark.svg +12 -0
  135. package/package.json +90 -0
@@ -0,0 +1,59 @@
1
+ import { z } from 'zod';
2
+ const text = z.string().min(1).max(2000);
3
+ export const SemanticTargetSchema = z.object({
4
+ role: text.optional(), name: text.optional(), label: text.optional(),
5
+ placeholder: text.optional(), testId: text.optional(), id: text.optional(),
6
+ attributeName: text.optional(), text: text.optional(), css: text.optional(),
7
+ frame: z.number().int().min(0).optional(),
8
+ }).strict().refine(t => Object.keys(t).some(k => k !== 'frame'), 'Empty target');
9
+ export const TargetSchema = z.union([text, SemanticTargetSchema]);
10
+ export const ConditionSchema = z.discriminatedUnion('type', [
11
+ z.object({ type: z.literal('input_value_equals'), target: TargetSchema, value: z.string().max(10000) }).strict(),
12
+ z.object({ type: z.literal('extraction_created'), key: text.optional() }).strict(),
13
+ z.object({ type: z.literal('extraction_contains'), key: text.optional(), value: text }).strict(),
14
+ z.object({ type: z.literal('tab_count'), count: z.number().int().min(1).max(100) }).strict(),
15
+ z.object({ type: z.literal('extraction_count'), key: text.optional(), min: z.number().int().min(1).max(1000), max: z.number().int().min(1).max(1000).optional() }).strict(),
16
+ ...['element_exists', 'element_visible', 'element_not_visible', 'checkbox_checked', 'form_submitted']
17
+ .map(type => z.object({ type: z.literal(type), target: TargetSchema }).strict()),
18
+ ...['url_equals', 'url_contains', 'text_exists', 'text_disappeared', 'title_changed']
19
+ .map(type => z.object({ type: z.literal(type), value: text }).strict()),
20
+ z.object({ type: z.literal('network_response'), value: text, status: z.number().int().min(100).max(599).optional() }).strict(),
21
+ z.object({ type: z.literal('download_created'), value: text.optional() }).strict(),
22
+ z.object({ type: z.literal('page_changed'), value: text }).strict(),
23
+ ]);
24
+ const meta = {
25
+ sensitive: z.boolean().optional(),
26
+ verify: z.array(ConditionSchema).max(12).optional(),
27
+ timeoutMs: z.number().int().min(100).max(30000).optional(),
28
+ };
29
+ export const ActionSchema = z.discriminatedUnion('type', [
30
+ z.object({ type: z.literal('switchTab'), index: z.number().int().min(0).max(100), ...meta }).strict(),
31
+ ...['click', 'doubleClick', 'hover', 'check', 'uncheck', 'submit']
32
+ .map(type => z.object({ type: z.literal(type), target: TargetSchema, ...meta }).strict()),
33
+ ...['fill', 'type', 'select', 'press']
34
+ .map(type => z.object({ type: z.literal(type), target: TargetSchema, value: z.string().max(10000), ...meta }).strict()),
35
+ ...['navigate', 'openTab']
36
+ .map(type => z.object({ type: z.literal(type), url: text, ...meta }).strict()),
37
+ z.object({ type: z.literal('upload'), target: TargetSchema, file: text, ...meta }).strict(),
38
+ z.object({ type: z.literal('download'), target: TargetSchema, filename: text.optional(), ...meta }).strict(),
39
+ z.object({ type: z.literal('extract'), target: TargetSchema.optional(), format: z.enum(['text', 'table', 'links', 'records']).default('text'), key: text.default('result'), match: text.optional(), limit: z.number().int().min(1).max(1000).optional(), fields: z.record(text, z.object({ css: text, attribute: z.enum(['text', 'href', 'src', 'value', 'title']).default('text') }).strict()).optional(), ...meta }).strict(),
40
+ z.object({ type: z.literal('wait'), condition: ConditionSchema, ...meta }).strict(),
41
+ z.object({ type: z.literal('scroll'), target: TargetSchema.optional(), direction: z.enum(['up', 'down']).default('down'), pixels: z.number().int().min(1).max(10000).default(600), ...meta }).strict(),
42
+ ...['closeTab', 'back', 'forward', 'reload']
43
+ .map(type => z.object({ type: z.literal(type), ...meta }).strict()),
44
+ ]);
45
+ export const PlanSchema = z.object({
46
+ goal: text, steps: z.array(text).min(1).max(12),
47
+ actions: z.array(ActionSchema).min(1).max(80),
48
+ completion: z.array(ConditionSchema).min(1).max(12),
49
+ continue: z.boolean().default(false),
50
+ }).strict();
51
+ export const RepairSchema = z.object({
52
+ actions: z.array(ActionSchema).max(20),
53
+ replace: z.number().int().min(0).max(20).default(1),
54
+ completion: z.array(ConditionSchema).min(1).max(12).optional(),
55
+ continue: z.boolean().optional(),
56
+ }).strict().refine(r => r.actions.length > 0 || !!r.completion, 'Repair needs actions or corrected completion conditions');
57
+ export const validateAction = (value) => ActionSchema.parse(value);
58
+ export const validatePlan = (value) => PlanSchema.parse(value);
59
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/actions/schema.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { PageState } from '../browser/types.js';
2
+ import { type Plan } from '../actions/schema.js';
3
+ import type { VariableResolver } from '../profile/VariableResolver.js';
4
+ export interface SiteAdapter {
5
+ name: string;
6
+ matches(url: URL): boolean;
7
+ plan(goal: string, state: PageState, variables: VariableResolver): Plan | undefined;
8
+ }
9
+ export declare function mapForm(state: PageState, variables: VariableResolver): {
10
+ field: import("../browser/types.js").PageElement;
11
+ key: string;
12
+ variable: string;
13
+ }[];
14
+ export declare const genericAdapter: SiteAdapter;
@@ -0,0 +1,33 @@
1
+ import { PlanSchema } from '../actions/schema.js';
2
+ const fieldAliases = { firstName: ['first name', 'given name'], lastName: ['last name', 'surname', 'family name'], email: ['email', 'email address'], phone: ['phone', 'phone number', 'telephone'], country: ['country'], city: ['city'], message: ['message'], experience: ['years of experience', 'experience'], name: ['name', 'full name'], password: ['password'] };
3
+ export function mapForm(state, variables) {
4
+ const fields = state.elements.filter(e => ['input', 'textarea', 'select'].includes(e.tag) && e.type !== 'submit' && !e.disabled);
5
+ return fields.flatMap(field => {
6
+ const label = field.name.toLowerCase().replace(/\*/g, '').trim();
7
+ const key = Object.keys(variables.vault.profile).find(key => key.toLowerCase() === label || (fieldAliases[key] ?? []).includes(label));
8
+ if (key)
9
+ return [{ field, key, variable: `{{profile.${key}}}` }];
10
+ return [];
11
+ });
12
+ }
13
+ export const genericAdapter = {
14
+ name: 'generic-local', matches: () => true,
15
+ plan(goal, state, variables) {
16
+ // Deliberately narrow intent parsing: zero LLM calls for fully specified tasks.
17
+ if (/^(extract|read)( the)? table\.?$/i.test(goal) && state.tables.length === 1)
18
+ return PlanSchema.parse({ goal, steps: ['Extract visible table'], actions: [{ type: 'extract', target: { css: 'table' }, format: 'table', key: 'table' }], completion: [{ type: 'element_visible', target: { css: 'table' } }], continue: false });
19
+ if (/^fill( the)?( contact)? form using( my)? profile\.?$/i.test(goal)) {
20
+ const mappings = mapForm(state, variables);
21
+ const required = state.elements.filter(e => e.required && !e.disabled && !e.hasValue);
22
+ if (!mappings.length || required.some(e => !mappings.some(m => m.field.ref === e.ref)))
23
+ return;
24
+ const forms = new Set(mappings.map(m => m.field.form));
25
+ if (forms.size !== 1)
26
+ return;
27
+ return PlanSchema.parse({ goal, steps: ['Map profile aliases to form labels', 'Fill and verify locally'],
28
+ actions: mappings.map(m => ({ type: m.field.tag === 'select' ? 'select' : 'fill', target: m.field.selectors, value: m.variable })),
29
+ completion: mappings.map(m => ({ type: 'input_value_equals', target: m.field.selectors, value: m.variable })).slice(0, 12), continue: false });
30
+ }
31
+ },
32
+ };
33
+ //# sourceMappingURL=generic.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generic.js","sourceRoot":"","sources":["../../src/adapters/generic.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,69 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import { type Plan, type Condition } from '../actions/schema.js';
3
+ import { Executor } from '../actions/executor.js';
4
+ import { Browser, type BrowserOptions } from '../browser/Browser.js';
5
+ import { Observer } from '../browser/Observer.js';
6
+ import type { PageState } from '../browser/types.js';
7
+ import { Control } from './Control.js';
8
+ import { TokenBudget } from './TokenBudget.js';
9
+ import { VariableResolver, type Vault } from '../profile/VariableResolver.js';
10
+ import { TraceStore, type Trace } from '../history/TraceStore.js';
11
+ import { WorkflowEngine } from '../workflows/WorkflowEngine.js';
12
+ import type { LLMProvider } from '../llm/LLMProvider.js';
13
+ import { type SiteAdapter } from '../adapters/generic.js';
14
+ import type { ConfirmationPolicy } from '../actions/policy.js';
15
+ export interface AgentOptions {
16
+ browser?: BrowserOptions;
17
+ vault?: Vault;
18
+ store: TraceStore;
19
+ provider?: LLMProvider;
20
+ budget?: TokenBudget;
21
+ confirmation?: ConfirmationPolicy;
22
+ downloadDir?: string;
23
+ maxSteps?: number;
24
+ maxRepairs?: number;
25
+ maxRepeatedStates?: number;
26
+ maxNavigationLoops?: number;
27
+ useWorkflows?: boolean;
28
+ adapters?: SiteAdapter[];
29
+ completionCriteria?: Condition[];
30
+ mode?: 'normal' | 'ultra';
31
+ }
32
+ export interface AgentEvent {
33
+ phase: string;
34
+ message: string;
35
+ time: number;
36
+ data?: unknown;
37
+ }
38
+ export declare class Agent extends EventEmitter {
39
+ readonly options: AgentOptions;
40
+ readonly browser: Browser;
41
+ readonly observer: Observer;
42
+ readonly control: Control;
43
+ readonly variables: VariableResolver;
44
+ readonly executor: Executor;
45
+ readonly workflows: WorkflowEngine;
46
+ budget: TokenBudget;
47
+ state?: PageState;
48
+ trace?: Trace;
49
+ events: AgentEvent[];
50
+ active: boolean;
51
+ private cache;
52
+ private permittedSites;
53
+ private watchedContexts;
54
+ constructor(options: AgentOptions);
55
+ private authorizeSite;
56
+ get approvedSites(): string[];
57
+ revokeSite(value: string): void;
58
+ private watchLastPageClose;
59
+ event(phase: string, message: string, data?: unknown): void;
60
+ open(url: string): Promise<PageState>;
61
+ observe(): Promise<PageState>;
62
+ private context;
63
+ run(goal: string, url?: string, providedPlan?: Plan, allowProvider?: boolean): Promise<Trace>;
64
+ private providerCalls;
65
+ private safeTrace;
66
+ replay(trace: Trace, url?: string): Promise<Trace>;
67
+ prepareForNextRun(options?: Partial<Omit<AgentOptions, 'store'>>): Promise<void>;
68
+ close(): Promise<void>;
69
+ }
@@ -0,0 +1,375 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import { randomUUID } from 'node:crypto';
3
+ import { PlanSchema, RepairSchema } from '../actions/schema.js';
4
+ import { Executor } from '../actions/executor.js';
5
+ import { Browser, checkedHttpURL } from '../browser/Browser.js';
6
+ import { SecurityBoundaryError } from '../browser/SecurityBoundaryError.js';
7
+ import { Observer } from '../browser/Observer.js';
8
+ import { diffPages } from '../browser/PageCompressor.js';
9
+ import { Control } from './Control.js';
10
+ import { TokenBudget } from './TokenBudget.js';
11
+ import { VariableResolver } from '../profile/VariableResolver.js';
12
+ import { WorkflowEngine } from '../workflows/WorkflowEngine.js';
13
+ import { genericAdapter } from '../adapters/generic.js';
14
+ import { goalCriteria } from './goalCriteria.js';
15
+ export class Agent extends EventEmitter {
16
+ options;
17
+ browser;
18
+ observer = new Observer();
19
+ control = new Control();
20
+ variables;
21
+ executor;
22
+ workflows;
23
+ budget;
24
+ state;
25
+ trace;
26
+ events = [];
27
+ active = false;
28
+ cache = new Map();
29
+ permittedSites = new Set();
30
+ watchedContexts = new WeakSet();
31
+ constructor(options) {
32
+ super();
33
+ this.options = options;
34
+ this.variables = new VariableResolver(options.vault);
35
+ this.browser = new Browser({ ...options.browser, allowExternal: options.mode === 'ultra' || options.browser?.allowExternal, beforeNavigate: url => this.authorizeSite(url) });
36
+ this.budget = options.budget ?? new TokenBudget();
37
+ this.workflows = new WorkflowEngine(options.store);
38
+ this.executor = new Executor(this.browser, this.observer, this.variables, this.control, { confirmation: options.mode === 'ultra' ? 'never' : options.confirmation, downloadDir: options.downloadDir });
39
+ this.control.on('approval', data => this.event('HUMAN', 'Human confirmation required', data));
40
+ this.control.on('change', () => { if (this.control.stopped)
41
+ this.options.provider?.cancel?.(); });
42
+ }
43
+ async authorizeSite(value) {
44
+ const origin = new URL(value).origin;
45
+ const blocked = this.browser.options.blockedOrigins ??= [];
46
+ if (!blocked.includes(origin) && (this.options.mode === 'ultra' || this.permittedSites.has(origin))) {
47
+ this.permittedSites.add(origin);
48
+ return;
49
+ }
50
+ await this.control.confirm(`Allow browser access to ${origin}?`, { type: 'siteAccess', origin, scope: 'This browser session: inspect pages and perform the requested task', mode: 'normal' });
51
+ this.permittedSites.add(origin);
52
+ this.browser.options.blockedOrigins = blocked.filter(item => item !== origin);
53
+ const origins = this.browser.options.allowedOrigins ??= [];
54
+ if (!origins.includes(origin))
55
+ origins.push(origin);
56
+ this.event('PERMISSION', `Website approved: ${origin}`);
57
+ }
58
+ get approvedSites() { return [...this.permittedSites].sort(); }
59
+ revokeSite(value) {
60
+ const origin = checkedHttpURL(value).origin;
61
+ if (!this.permittedSites.delete(origin))
62
+ throw new Error('Website is not currently approved');
63
+ this.browser.options.allowedOrigins = (this.browser.options.allowedOrigins ?? []).filter(item => item !== origin);
64
+ const blocked = this.browser.options.blockedOrigins ??= [];
65
+ if (!blocked.includes(origin))
66
+ blocked.push(origin);
67
+ this.event('PERMISSION', `Website access revoked: ${origin}`);
68
+ if (this.active && this.browser.page && !this.browser.page.isClosed() && new URL(this.browser.page.url()).origin === origin)
69
+ this.control.stop();
70
+ }
71
+ watchLastPageClose() {
72
+ const context = this.browser.context;
73
+ if (this.watchedContexts.has(context))
74
+ return;
75
+ this.watchedContexts.add(context);
76
+ const watch = (page) => page.once('close', () => {
77
+ if (!this.active || this.control.stopped || page !== this.browser.page)
78
+ return;
79
+ this.control.stop();
80
+ });
81
+ context.pages().forEach(watch);
82
+ context.on('page', watch);
83
+ }
84
+ event(phase, message, data) {
85
+ const event = { phase, message: this.variables.redact(message), time: Date.now(), data: data === undefined ? undefined : JSON.parse(this.variables.redact(JSON.stringify(data))) };
86
+ this.events.push(event);
87
+ if (this.events.length > 500)
88
+ this.events.shift();
89
+ this.emit('event', event);
90
+ }
91
+ async open(url) { if (!this.browser.context)
92
+ await this.browser.launch(); await this.browser.navigate(url); return this.observe(); }
93
+ async observe() {
94
+ const state = await this.observer.inspect(this.browser.page);
95
+ this.state = state;
96
+ this.cache.set(state.hash, state);
97
+ if (this.cache.size > 30)
98
+ this.cache.delete(this.cache.keys().next().value);
99
+ const compressed = this.observer.compressor.compress(state);
100
+ this.event('OBSERVE', `DOM ${state.htmlBytes} bytes → ${compressed.bytes} bytes`, { url: state.url, title: state.title, hash: state.hash, reduction: compressed.reduction });
101
+ return state;
102
+ }
103
+ context(goal, state, completed, previous) {
104
+ const remaining = this.budget.limits.maxInputTokens === null ? Infinity : this.budget.limits.maxInputTokens - this.budget.input - this.budget.pendingInput;
105
+ const maxChars = Math.min(this.budget.tight ? 3000 : 9000, Math.max(1200, remaining - 9000));
106
+ const full = this.observer.compressor.compress(state, { goal, maxChars });
107
+ let page = full.text;
108
+ if (previous) {
109
+ const diff = JSON.stringify(diffPages(previous, state));
110
+ if (diff.length < page.length)
111
+ page = `PAGE DIFF\n${diff}`;
112
+ }
113
+ const structured = this.browser.extractions.filter(e => e.value !== null && typeof e.value === 'object').slice(-16).map(e => ({ key: e.key, preview: JSON.stringify(e.value).slice(0, 1400) }));
114
+ const priorText = this.browser.extractions.filter(e => typeof e.value === 'string').slice(-16).map(e => ({ key: e.key, preview: e.value.slice(-1800) }));
115
+ page += '\nOPEN TABS ' + JSON.stringify(this.browser.context.pages().map((p, index) => ({ index, url: p.url, active: p === this.browser.page }))) + '\nEXTRACTED EVIDENCE FROM PRIOR PAGES ' + this.variables.redact(JSON.stringify([...structured, ...priorText]));
116
+ return { goal: this.variables.redact(goal), page: this.variables.redact(page), aliases: this.variables.aliases(), completed: completed.slice(-12), allowedOrigins: this.browser.options.allowedOrigins ?? [], phase: 'current batch', trustedCompletionCriteria: [...this.options.completionCriteria ?? [], ...goalCriteria(goal)] };
117
+ }
118
+ async run(goal, url, providedPlan, allowProvider = true) {
119
+ if (this.active)
120
+ throw new Error('An agent task is already running');
121
+ if (this.control.stopped)
122
+ throw new Error('Create a new agent after stopping a task');
123
+ if (url)
124
+ checkedHttpURL(url, this.browser.page?.url());
125
+ this.active = true;
126
+ const startedAt = Date.now();
127
+ const callStart = this.providerCalls().length;
128
+ const provider = allowProvider ? this.options.provider : undefined;
129
+ const usageStart = this.budget.snapshot();
130
+ let initial, repairs = 0, cacheHits = 0, planCalls = 0;
131
+ const trace = { version: 1, id: `run-${new Date().toISOString().replace(/[:.]/g, '-')}-${randomUUID().slice(0, 6)}`, goal: this.variables.redact(goal), url: this.variables.redact(url ?? this.browser.page?.url() ?? ''), status: 'running', startedAt, durationMs: 0, plans: [], actions: [], completion: [], calls: [], metrics: {} };
132
+ this.trace = trace;
133
+ this.options.store.save(trace);
134
+ const repeated = new Map(), navigations = new Map(), completed = [];
135
+ let revision = this.control.revision, completionReplans = 0;
136
+ try {
137
+ if (!this.browser.context)
138
+ await this.browser.launch();
139
+ this.watchLastPageClose();
140
+ this.browser.extractions.length = 0;
141
+ this.browser.downloads.length = 0;
142
+ this.browser.formReceipts.length = 0;
143
+ if (url)
144
+ await this.browser.navigate(url);
145
+ initial = await this.observe();
146
+ trace.url = this.variables.redact(initial.url);
147
+ if (initial.warnings.some(w => w.includes('Human authentication'))) {
148
+ this.control.pause();
149
+ this.event('HUMAN', 'Take control to complete authentication/security checks, then resume');
150
+ await this.control.checkpoint();
151
+ initial = await this.observe();
152
+ revision = this.control.revision;
153
+ }
154
+ const learned = this.options.useWorkflows !== false && !providedPlan ? this.workflows.match(goal, initial) : undefined;
155
+ let plan = providedPlan ?? learned?.plan;
156
+ if (learned) {
157
+ cacheHits++;
158
+ this.event('CACHE', `Reusing learned workflow ${learned.id}`);
159
+ }
160
+ if (!plan)
161
+ for (const adapter of this.options.adapters ?? [genericAdapter]) {
162
+ if (adapter.matches(new URL(initial.url))) {
163
+ plan = adapter.plan(goal, initial, this.variables);
164
+ if (plan) {
165
+ this.event('LOCAL', `Deterministic strategy: ${adapter.name}`);
166
+ break;
167
+ }
168
+ }
169
+ }
170
+ let previous;
171
+ while (true) {
172
+ await this.control.checkpoint();
173
+ if (!plan) {
174
+ if (!provider)
175
+ throw new Error('No matching local strategy/workflow; configure an LLM provider');
176
+ this.event('PLAN', 'Requesting one action batch');
177
+ planCalls++;
178
+ plan = await provider.plan(this.context(goal, this.state, completed, previous));
179
+ }
180
+ const batchState = this.state;
181
+ plan = PlanSchema.parse(plan);
182
+ trace.plans.push(plan);
183
+ this.event('PLAN', 'Validated plan', plan);
184
+ this.trace = this.safeTrace(trace);
185
+ this.options.store.save(this.trace);
186
+ let actions = [...plan.actions];
187
+ let index = 0;
188
+ while (index < actions.length) {
189
+ await this.control.checkpoint();
190
+ if (revision !== this.control.revision) {
191
+ await this.observe();
192
+ revision = this.control.revision;
193
+ }
194
+ if (this.control.replacement) {
195
+ plan = this.control.replacement;
196
+ this.control.replacement = undefined;
197
+ actions = [...plan.actions];
198
+ index = 0;
199
+ trace.plans.push(plan);
200
+ await this.observe();
201
+ this.event('HUMAN', 'Using edited plan', plan);
202
+ }
203
+ if (trace.actions.length >= (this.options.maxSteps ?? 120))
204
+ throw new Error('Browser action limit reached');
205
+ const before = this.state;
206
+ const action = actions[index];
207
+ if (this.options.mode !== 'ultra' && /\{\{(?:profile|files)\./.test(JSON.stringify(action)) && !/\b(profile|personal details|my details|credentials|resume|cv|local file)\b/i.test(goal))
208
+ throw new Error('The user goal does not authorize access to local profile/file aliases');
209
+ const key = before.hash + JSON.stringify(action);
210
+ const count = (repeated.get(key) ?? 0) + 1;
211
+ repeated.set(key, count);
212
+ if (count > (this.options.maxRepeatedStates ?? 3))
213
+ throw new Error('Repeated state/action loop detected');
214
+ this.event('EXECUTE', `${action.type}${'target' in action ? ' ' + JSON.stringify(action.target) : ''}`, { index: index + 1, total: actions.length });
215
+ const result = await this.executor.run(action);
216
+ trace.actions.push(result);
217
+ this.trace = this.safeTrace(trace);
218
+ this.options.store.save(this.trace);
219
+ const after = await this.observe();
220
+ if (before.url !== after.url) {
221
+ const loops = (navigations.get(after.url) ?? 0) + 1;
222
+ navigations.set(after.url, loops);
223
+ if (loops > (this.options.maxNavigationLoops ?? 3))
224
+ throw new Error('Navigation loop detected');
225
+ }
226
+ if (result.success) {
227
+ const descriptor = 'target' in result.action && typeof result.action.target === 'object' ? result.action.target : undefined;
228
+ completed.push(this.variables.redact(JSON.stringify({ type: action.type, ...('url' in result.action ? { url: result.action.url } : {}), ...(descriptor ? { target: { role: descriptor.role, name: descriptor.name ?? descriptor.label ?? descriptor.id ?? descriptor.css } } : {}), ...('key' in result.action ? { key: result.action.key } : {}) })));
229
+ index++;
230
+ this.event('VERIFY', 'Action completed locally', { action: action.type, durationMs: result.durationMs, strategy: result.strategy });
231
+ continue;
232
+ }
233
+ if (this.control.stopped || /rejected by human|stopped by human/.test(result.error ?? ''))
234
+ throw new Error(result.error);
235
+ if (result.uncertain) {
236
+ await this.control.confirm('The previous action may already have happened. Approve a repair only after checking the browser.', result.action);
237
+ await this.observe();
238
+ }
239
+ if (!provider || repairs >= (this.options.maxRepairs ?? 8))
240
+ throw new Error(result.error ?? 'Repair limit reached');
241
+ repairs++;
242
+ this.event('REPAIR', 'Repairing only the failed portion', { failedAction: result.action, error: result.error });
243
+ const context = this.context(goal, after, completed, before);
244
+ if (repairs > 1)
245
+ context.page += '\nACCESSIBILITY\n' + this.variables.redact(await this.observer.accessibility(this.browser.page));
246
+ if (repairs > 2) {
247
+ const scope = await this.browser.page.locator('form').count() === 1 ? 'form' : await this.browser.page.locator('main').count() === 1 ? 'main' : 'body';
248
+ context.page += '\nTARGETED HTML\n' + this.variables.redact(await this.observer.fragment(this.browser.page, scope)).slice(0, 3000);
249
+ }
250
+ const repaired = RepairSchema.parse(await provider.repair({ ...context, failedAction: result.action, error: result.error ?? 'Action failed', remaining: actions.slice(index, index + 12) }));
251
+ if (repaired.replace < 1 || !repaired.actions.length || repaired.replace > actions.length - index)
252
+ throw new Error('Repair attempted to replace actions outside the pending batch');
253
+ if (repaired.completion)
254
+ plan.completion = repaired.completion;
255
+ if (repaired.continue !== undefined)
256
+ plan.continue = repaired.continue;
257
+ actions.splice(index, repaired.replace, ...repaired.actions);
258
+ }
259
+ const criteria = () => [...plan.completion, ...(!plan.continue ? [...this.options.completionCriteria ?? [], ...goalCriteria(goal)] : [])];
260
+ let verification = await this.executor.verifier.check(criteria(), 4000, startedAt);
261
+ this.event('VERIFY', verification.success ? 'Batch completion verified' : 'Completion conditions failed', verification);
262
+ if (!verification.success) {
263
+ if (provider && completionReplans < 3 && /\b(download|export)\b/i.test(goal) && verification.failed.some(item => item.type === 'download_created') && !actions.some(item => item.type === 'download') && actions.some(item => item.type === 'click' && typeof item.target === 'object' && /save|export/i.test(item.target.name ?? ''))) {
264
+ completionReplans++;
265
+ this.event('PLAN', 'Download still missing; observing controls revealed after the last action');
266
+ previous = batchState;
267
+ await this.observe();
268
+ plan = undefined;
269
+ continue;
270
+ }
271
+ if (!provider || repairs >= (this.options.maxRepairs ?? 8))
272
+ throw new Error('Task completion could not be verified');
273
+ repairs++;
274
+ const after = await this.observe();
275
+ this.event('REPAIR', 'Repairing failed completion conditions');
276
+ const repaired = RepairSchema.parse(await provider.repair({ ...this.context(goal, after, completed), failedAction: { type: 'verification' }, error: 'Completion conditions failed; user-specified criteria cannot be weakened or removed', remaining: [], failedConditions: criteria() }));
277
+ if (repaired.completion)
278
+ plan.completion = repaired.completion;
279
+ if (repaired.continue !== undefined)
280
+ plan.continue = repaired.continue;
281
+ if (repaired.actions.length) {
282
+ plan = { ...plan, actions: repaired.actions };
283
+ continue;
284
+ }
285
+ verification = await this.executor.verifier.check(criteria(), 3000, startedAt);
286
+ if (!verification.success && repaired.continue) {
287
+ previous = batchState;
288
+ await this.observe();
289
+ plan = undefined;
290
+ continue;
291
+ }
292
+ if (!verification.success)
293
+ throw new Error('Repaired task completion could not be verified');
294
+ }
295
+ if (plan.continue) {
296
+ previous = batchState;
297
+ await this.observe();
298
+ plan = undefined;
299
+ continue;
300
+ }
301
+ trace.completion = criteria().map(c => this.executor.semanticCondition(c));
302
+ trace.status = 'completed';
303
+ break;
304
+ }
305
+ }
306
+ catch (error) {
307
+ trace.status = this.control.stopped ? 'stopped' : 'failed';
308
+ if (error instanceof SecurityBoundaryError)
309
+ trace.failureKind = 'security';
310
+ trace.error = this.variables.redact(error instanceof Error ? error.message : 'Task failed');
311
+ this.control.stop();
312
+ this.event(trace.failureKind === 'security' ? 'BLOCKED' : 'ERROR', trace.error);
313
+ }
314
+ finally {
315
+ trace.durationMs = Date.now() - startedAt;
316
+ trace.calls = this.providerCalls().slice(callStart);
317
+ const usage = this.budget.snapshot(trace.actions.filter(a => a.success).length);
318
+ const actions = trace.actions.filter(a => a.success).length, calls = usage.llmCalls - usageStart.llmCalls;
319
+ trace.metrics = { durationMs: trace.durationMs, browserActions: actions, failedActions: trace.actions.filter(a => !a.success).length, llmCalls: calls, inputTokens: usage.inputTokens - usageStart.inputTokens, outputTokens: usage.outputTokens - usageStart.outputTokens,
320
+ estimatedCostUSD: usage.estimatedCostUSD === null ? null : usage.estimatedCostUSD - (usageStart.estimatedCostUSD ?? 0), actionsPerLLMCall: calls ? actions / calls : null, tokensPerAction: actions ? ((usage.inputTokens - usageStart.inputTokens) + (usage.outputTokens - usageStart.outputTokens)) / actions : null,
321
+ repairs, workflowCacheHits: cacheHits, pageCacheEntries: this.cache.size, planBatches: planCalls, compressionReduction: initial ? this.observer.compressor.compress(initial).reduction : null, selectorSuccessRate: trace.actions.filter(a => a.strategy).length ? trace.actions.filter(a => a.strategy && a.success).length / trace.actions.filter(a => a.strategy).length : null,
322
+ usageEstimated: trace.calls.some(c => c.usage.estimated), provider: this.options.provider?.name ?? 'none', mode: this.options.mode ?? 'normal', approvedSites: [...this.permittedSites] };
323
+ const safe = this.safeTrace(trace);
324
+ this.trace = safe;
325
+ this.options.store.save(safe);
326
+ this.active = false;
327
+ if (safe.status === 'completed' && initial) {
328
+ try {
329
+ this.workflows.learn(safe, initial);
330
+ }
331
+ catch {
332
+ this.event('CACHE', 'Task completed, but workflow could not be saved');
333
+ }
334
+ }
335
+ this.event(safe.status === 'completed' ? 'DONE' : 'STOP', `Task ${safe.status}`, safe.metrics);
336
+ }
337
+ return this.trace;
338
+ }
339
+ providerCalls() { return this.options.provider?.calls ?? []; }
340
+ safeTrace(trace) { return JSON.parse(this.variables.redact(JSON.stringify(trace))); }
341
+ async replay(trace, url) {
342
+ if (trace.status !== 'completed')
343
+ throw new Error('Only completed traces can be replayed; failed runs may contain incomplete side effects');
344
+ const plan = PlanSchema.parse({ goal: trace.goal, steps: ['Replay successful semantic actions'], actions: trace.actions.filter(a => a.success).map(a => a.action), completion: trace.completion, continue: false });
345
+ return this.run(trace.goal, url ?? trace.url, plan, false);
346
+ }
347
+ async prepareForNextRun(options = {}) {
348
+ if (this.active || this.control.pending)
349
+ throw new Error('Cannot prepare an active browser task for another run');
350
+ Object.assign(this.options, options);
351
+ this.control.reset();
352
+ if (Object.hasOwn(options, 'vault'))
353
+ this.variables.vault = options.vault ?? { profile: {}, files: {} };
354
+ if (options.budget)
355
+ this.budget = options.budget;
356
+ Object.assign(this.browser.options, options.browser);
357
+ this.browser.options.allowedOrigins = [...(options.browser?.allowedOrigins ?? [])];
358
+ this.browser.options.blockedOrigins = [...(options.browser?.blockedOrigins ?? [])];
359
+ this.browser.options.allowExternal = this.options.mode === 'ultra' || options.browser?.allowExternal === true;
360
+ this.executor.options.confirmation = this.options.mode === 'ultra' ? 'never' : this.options.confirmation;
361
+ this.executor.options.downloadDir = this.options.downloadDir;
362
+ this.state = undefined;
363
+ this.trace = undefined;
364
+ this.events = [];
365
+ this.cache.clear();
366
+ this.permittedSites.clear();
367
+ this.browser.downloads.length = 0;
368
+ this.browser.extractions.length = 0;
369
+ this.browser.responses.length = 0;
370
+ this.browser.formReceipts.length = 0;
371
+ await this.browser.prepareForNextRun();
372
+ }
373
+ async close() { this.control.stop(); await this.browser.close(); }
374
+ }
375
+ //# sourceMappingURL=Agent.js.map