@ap3x/browser-agent 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent/agent.d.ts +5 -0
- package/dist/agent/agent.d.ts.map +1 -1
- package/dist/agent/backend.d.ts.map +1 -1
- package/dist/agent/history.d.ts +3 -0
- package/dist/agent/history.d.ts.map +1 -1
- package/dist/agent/judge.d.ts.map +1 -1
- package/dist/agent/postconditions.d.ts +39 -0
- package/dist/agent/postconditions.d.ts.map +1 -0
- package/dist/agent/rematch.d.ts +2 -4
- package/dist/agent/rematch.d.ts.map +1 -1
- package/dist/agent/replay.d.ts +15 -0
- package/dist/agent/replay.d.ts.map +1 -1
- package/dist/agent/step-loop.d.ts +4 -0
- package/dist/agent/step-loop.d.ts.map +1 -1
- package/dist/agent/workflow-catalog.d.ts +52 -0
- package/dist/agent/workflow-catalog.d.ts.map +1 -0
- package/dist/{chunk-UZALZUEE.js → chunk-LXHBVRFM.js} +181 -75
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +187 -17
- package/dist/mcp/bin.js +1 -1
- package/dist/mcp/client.d.ts +1 -1
- package/dist/tools/actions.d.ts.map +1 -1
- package/dist/tools/registry.d.ts +5 -0
- package/dist/tools/registry.d.ts.map +1 -1
- package/package.json +4 -4
|
@@ -9,6 +9,70 @@ function isDoneResult(result) {
|
|
|
9
9
|
return result.isDone === true;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
// src/agent/postconditions.ts
|
|
13
|
+
import { Type } from "@sinclair/typebox";
|
|
14
|
+
var BrowserPostconditionSchema = Type.Union([
|
|
15
|
+
Type.Object(
|
|
16
|
+
{ kind: Type.Literal("url"), equals: Type.String() },
|
|
17
|
+
{ additionalProperties: false }
|
|
18
|
+
),
|
|
19
|
+
Type.Object(
|
|
20
|
+
{
|
|
21
|
+
kind: Type.Literal("page_identity"),
|
|
22
|
+
title: Type.Optional(Type.String()),
|
|
23
|
+
textIncludes: Type.Optional(Type.String())
|
|
24
|
+
},
|
|
25
|
+
{ additionalProperties: false }
|
|
26
|
+
),
|
|
27
|
+
Type.Object(
|
|
28
|
+
{ kind: Type.Literal("visible"), selector: Type.String() },
|
|
29
|
+
{ additionalProperties: false }
|
|
30
|
+
),
|
|
31
|
+
Type.Object(
|
|
32
|
+
{ kind: Type.Literal("selected_value"), selector: Type.String(), value: Type.String() },
|
|
33
|
+
{ additionalProperties: false }
|
|
34
|
+
)
|
|
35
|
+
]);
|
|
36
|
+
var PostconditionError = class extends Error {
|
|
37
|
+
constructor(condition) {
|
|
38
|
+
super(`Browser postcondition failed: ${condition.kind}`);
|
|
39
|
+
this.condition = condition;
|
|
40
|
+
this.name = "PostconditionError";
|
|
41
|
+
}
|
|
42
|
+
condition;
|
|
43
|
+
reasonCode = "postcondition_failed";
|
|
44
|
+
};
|
|
45
|
+
async function verifyPostconditions(conditions, driver, session, signal) {
|
|
46
|
+
if (!conditions.length) return;
|
|
47
|
+
const state = await driver.getState({ signal });
|
|
48
|
+
for (const condition of conditions) {
|
|
49
|
+
if (signal?.aborted) throw new DOMException("Aborted", "AbortError");
|
|
50
|
+
let passed = false;
|
|
51
|
+
switch (condition.kind) {
|
|
52
|
+
case "url":
|
|
53
|
+
passed = state.url === condition.equals;
|
|
54
|
+
break;
|
|
55
|
+
case "page_identity":
|
|
56
|
+
passed = (condition.title !== void 0 || condition.textIncludes !== void 0) && (condition.title === void 0 || state.title === condition.title) && (condition.textIncludes === void 0 || state.serializedText.includes(condition.textIncludes));
|
|
57
|
+
break;
|
|
58
|
+
case "visible":
|
|
59
|
+
passed = await session.evaluate(
|
|
60
|
+
`(()=>{const elements=document.querySelectorAll(${JSON.stringify(condition.selector)});if(elements.length!==1)return false;const e=elements[0];const s=getComputedStyle(e);const r=e.getBoundingClientRect();return s.display!=='none'&&s.visibility!=='hidden'&&r.width>0&&r.height>0;})()`,
|
|
61
|
+
{ signal }
|
|
62
|
+
);
|
|
63
|
+
break;
|
|
64
|
+
case "selected_value":
|
|
65
|
+
passed = await session.evaluate(
|
|
66
|
+
`(()=>{const elements=document.querySelectorAll(${JSON.stringify(condition.selector)});return elements.length===1&&elements[0].value===${JSON.stringify(condition.value)};})()`,
|
|
67
|
+
{ signal }
|
|
68
|
+
);
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
if (signal?.aborted) throw new DOMException("Aborted", "AbortError");
|
|
72
|
+
if (!passed) throw new PostconditionError(condition);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
12
76
|
// src/tools/sensitive.ts
|
|
13
77
|
import { createHmac } from "crypto";
|
|
14
78
|
import { matchUrlWithDomainPattern } from "@ap3x/browser";
|
|
@@ -124,8 +188,9 @@ function totp(seed, options = {}) {
|
|
|
124
188
|
}
|
|
125
189
|
|
|
126
190
|
// src/tools/registry.ts
|
|
191
|
+
import { authorizeTool, currentRunContext, immutableArguments, uuidv7 } from "@ap3x/agent-core";
|
|
127
192
|
import { matchUrlWithDomainPattern as matchUrlWithDomainPattern2 } from "@ap3x/browser";
|
|
128
|
-
import { Type } from "@sinclair/typebox";
|
|
193
|
+
import { Type as Type2 } from "@sinclair/typebox";
|
|
129
194
|
import { Value } from "@sinclair/typebox/value";
|
|
130
195
|
function defineAction(def) {
|
|
131
196
|
return def;
|
|
@@ -150,6 +215,8 @@ var Registry = class _Registry {
|
|
|
150
215
|
throw new Error(`Action "${def.name}" is already registered`);
|
|
151
216
|
}
|
|
152
217
|
this.actions.set(def.name, {
|
|
218
|
+
replaySafe: def.replaySafe ?? false,
|
|
219
|
+
postconditions: def.postconditions,
|
|
153
220
|
name: def.name,
|
|
154
221
|
description: def.description,
|
|
155
222
|
schema: def.schema,
|
|
@@ -192,9 +259,9 @@ var Registry = class _Registry {
|
|
|
192
259
|
const cached = this.unionCache.get(key);
|
|
193
260
|
if (cached) return cached;
|
|
194
261
|
const members = admitted.map(
|
|
195
|
-
(a) =>
|
|
262
|
+
(a) => Type2.Object({ [a.name]: a.schema }, { additionalProperties: false, title: a.name })
|
|
196
263
|
);
|
|
197
|
-
const union = members.length === 0 ?
|
|
264
|
+
const union = members.length === 0 ? Type2.Never() : members.length === 1 ? members[0] : Type2.Union(members);
|
|
198
265
|
this.unionCache.set(key, union);
|
|
199
266
|
return union;
|
|
200
267
|
}
|
|
@@ -242,7 +309,14 @@ var Registry = class _Registry {
|
|
|
242
309
|
});
|
|
243
310
|
}
|
|
244
311
|
try {
|
|
245
|
-
const
|
|
312
|
+
const context = currentRunContext();
|
|
313
|
+
const finalParams = immutableArguments(params);
|
|
314
|
+
await authorizeTool(context, name, uuidv7(), finalParams, ctx.signal);
|
|
315
|
+
context?.controller?.assertActive(ctx.signal);
|
|
316
|
+
context?.controller?.tool();
|
|
317
|
+
const result = await action.execute(finalParams, ctx);
|
|
318
|
+
if (result.error === void 0 && action.postconditions)
|
|
319
|
+
await verifyPostconditions(action.postconditions, ctx.driver, ctx.session, ctx.signal);
|
|
246
320
|
return maskResultSecrets(result, resolved, allSensitiveData);
|
|
247
321
|
} catch (error) {
|
|
248
322
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -363,7 +437,7 @@ async function readExternalFile(path) {
|
|
|
363
437
|
// src/tools/actions.ts
|
|
364
438
|
import { basename, join } from "path";
|
|
365
439
|
import { InteractionError, PAGE_SCROLL_PX, asElementIndex, isPathContained } from "@ap3x/browser";
|
|
366
|
-
import { Type as
|
|
440
|
+
import { Type as Type3 } from "@sinclair/typebox";
|
|
367
441
|
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
368
442
|
function nodeAt(ctx, index) {
|
|
369
443
|
const node = ctx.session.getElementByIndex(index);
|
|
@@ -380,7 +454,7 @@ function nodeAt(ctx, index) {
|
|
|
380
454
|
var navigate = defineAction({
|
|
381
455
|
name: "navigate",
|
|
382
456
|
description: "Navigate the current tab to a URL (opens a new tab when newTab is true).",
|
|
383
|
-
schema:
|
|
457
|
+
schema: Type3.Object({ url: Type3.String(), newTab: Type3.Optional(Type3.Boolean()) }),
|
|
384
458
|
terminatesSequence: true,
|
|
385
459
|
async execute(params, ctx) {
|
|
386
460
|
if (params.newTab) {
|
|
@@ -394,7 +468,7 @@ var navigate = defineAction({
|
|
|
394
468
|
var goBack = defineAction({
|
|
395
469
|
name: "go_back",
|
|
396
470
|
description: "Go back one entry in the browser history.",
|
|
397
|
-
schema:
|
|
471
|
+
schema: Type3.Object({}),
|
|
398
472
|
terminatesSequence: true,
|
|
399
473
|
async execute(_params, ctx) {
|
|
400
474
|
await ctx.session.goBack();
|
|
@@ -404,7 +478,7 @@ var goBack = defineAction({
|
|
|
404
478
|
var click = defineAction({
|
|
405
479
|
name: "click",
|
|
406
480
|
description: "Click an interactive element by its [index].",
|
|
407
|
-
schema:
|
|
481
|
+
schema: Type3.Object({ index: Type3.Integer({ minimum: 1 }) }),
|
|
408
482
|
async execute(params, ctx) {
|
|
409
483
|
const resolved = nodeAt(ctx, params.index);
|
|
410
484
|
if (!resolved.ok) return resolved.result;
|
|
@@ -415,10 +489,10 @@ var click = defineAction({
|
|
|
415
489
|
var inputText = defineAction({
|
|
416
490
|
name: "input_text",
|
|
417
491
|
description: "Type text into an element by its [index]. clear=false appends; text='' clears.",
|
|
418
|
-
schema:
|
|
419
|
-
index:
|
|
420
|
-
text:
|
|
421
|
-
clear:
|
|
492
|
+
schema: Type3.Object({
|
|
493
|
+
index: Type3.Integer({ minimum: 0 }),
|
|
494
|
+
text: Type3.String(),
|
|
495
|
+
clear: Type3.Optional(Type3.Boolean())
|
|
422
496
|
}),
|
|
423
497
|
async execute(params, ctx) {
|
|
424
498
|
const resolved = nodeAt(ctx, params.index);
|
|
@@ -436,10 +510,10 @@ var inputText = defineAction({
|
|
|
436
510
|
var scroll = defineAction({
|
|
437
511
|
name: "scroll",
|
|
438
512
|
description: "Scroll the page (or an element by [index]) up/down by a number of pages.",
|
|
439
|
-
schema:
|
|
440
|
-
down:
|
|
441
|
-
pages:
|
|
442
|
-
index:
|
|
513
|
+
schema: Type3.Object({
|
|
514
|
+
down: Type3.Optional(Type3.Boolean()),
|
|
515
|
+
pages: Type3.Optional(Type3.Number()),
|
|
516
|
+
index: Type3.Optional(Type3.Integer({ minimum: 1 }))
|
|
443
517
|
}),
|
|
444
518
|
async execute(params, ctx) {
|
|
445
519
|
const pages = params.pages ?? 1;
|
|
@@ -459,7 +533,7 @@ var scroll = defineAction({
|
|
|
459
533
|
var scrollToText = defineAction({
|
|
460
534
|
name: "scroll_to_text",
|
|
461
535
|
description: "Scroll to the first occurrence of the given text.",
|
|
462
|
-
schema:
|
|
536
|
+
schema: Type3.Object({ text: Type3.String() }),
|
|
463
537
|
async execute(params, ctx) {
|
|
464
538
|
try {
|
|
465
539
|
await ctx.session.input.scrollToText(params.text, { signal: ctx.signal });
|
|
@@ -475,7 +549,7 @@ var scrollToText = defineAction({
|
|
|
475
549
|
var sendKeys = defineAction({
|
|
476
550
|
name: "send_keys",
|
|
477
551
|
description: "Dispatch raw keyboard keys or a shortcut (e.g. 'Enter', 'Control+a').",
|
|
478
|
-
schema:
|
|
552
|
+
schema: Type3.Object({ keys: Type3.String() }),
|
|
479
553
|
async execute(params, ctx) {
|
|
480
554
|
await ctx.session.input.sendKeys(params.keys, { signal: ctx.signal });
|
|
481
555
|
return stepResult({ longTermMemory: `Sent keys ${params.keys}` });
|
|
@@ -484,7 +558,7 @@ var sendKeys = defineAction({
|
|
|
484
558
|
var selectDropdown = defineAction({
|
|
485
559
|
name: "select_dropdown",
|
|
486
560
|
description: "Select a dropdown option by its exact text, on the element at [index].",
|
|
487
|
-
schema:
|
|
561
|
+
schema: Type3.Object({ index: Type3.Integer({ minimum: 1 }), text: Type3.String() }),
|
|
488
562
|
async execute(params, ctx) {
|
|
489
563
|
const resolved = nodeAt(ctx, params.index);
|
|
490
564
|
if (!resolved.ok) return resolved.result;
|
|
@@ -501,8 +575,9 @@ var selectDropdown = defineAction({
|
|
|
501
575
|
});
|
|
502
576
|
var getDropdownOptions = defineAction({
|
|
503
577
|
name: "get_dropdown_options",
|
|
578
|
+
replaySafe: true,
|
|
504
579
|
description: "List the available options of the dropdown element at [index].",
|
|
505
|
-
schema:
|
|
580
|
+
schema: Type3.Object({ index: Type3.Integer({ minimum: 1 }) }),
|
|
506
581
|
async execute(params, ctx) {
|
|
507
582
|
const resolved = nodeAt(ctx, params.index);
|
|
508
583
|
if (!resolved.ok) return resolved.result;
|
|
@@ -518,7 +593,7 @@ var getDropdownOptions = defineAction({
|
|
|
518
593
|
var switchTab = defineAction({
|
|
519
594
|
name: "switch_tab",
|
|
520
595
|
description: "Focus another tab by its 4-char id.",
|
|
521
|
-
schema:
|
|
596
|
+
schema: Type3.Object({ tabId: Type3.String() }),
|
|
522
597
|
terminatesSequence: true,
|
|
523
598
|
async execute(params, ctx) {
|
|
524
599
|
await ctx.driver.switchTab(params.tabId);
|
|
@@ -528,7 +603,7 @@ var switchTab = defineAction({
|
|
|
528
603
|
var openTab = defineAction({
|
|
529
604
|
name: "open_tab",
|
|
530
605
|
description: "Open a new tab at a URL.",
|
|
531
|
-
schema:
|
|
606
|
+
schema: Type3.Object({ url: Type3.String() }),
|
|
532
607
|
terminatesSequence: true,
|
|
533
608
|
async execute(params, ctx) {
|
|
534
609
|
const tabId = await ctx.session.openTab(params.url);
|
|
@@ -538,7 +613,7 @@ var openTab = defineAction({
|
|
|
538
613
|
var closeTab = defineAction({
|
|
539
614
|
name: "close_tab",
|
|
540
615
|
description: "Close a tab by its 4-char id.",
|
|
541
|
-
schema:
|
|
616
|
+
schema: Type3.Object({ tabId: Type3.String() }),
|
|
542
617
|
async execute(params, ctx) {
|
|
543
618
|
await ctx.driver.closeTab(params.tabId);
|
|
544
619
|
return stepResult({ longTermMemory: `Closed tab ${params.tabId}` });
|
|
@@ -547,7 +622,7 @@ var closeTab = defineAction({
|
|
|
547
622
|
var uploadFile = defineAction({
|
|
548
623
|
name: "upload_file",
|
|
549
624
|
description: "Set a file on the file-input element at [index]. Path must be available.",
|
|
550
|
-
schema:
|
|
625
|
+
schema: Type3.Object({ index: Type3.Integer({ minimum: 0 }), path: Type3.String() }),
|
|
551
626
|
async execute(params, ctx) {
|
|
552
627
|
let uploadPath;
|
|
553
628
|
const base = basename(params.path);
|
|
@@ -569,8 +644,9 @@ var uploadFile = defineAction({
|
|
|
569
644
|
});
|
|
570
645
|
var wait = defineAction({
|
|
571
646
|
name: "wait",
|
|
647
|
+
replaySafe: true,
|
|
572
648
|
description: "Wait for a number of seconds (capped at 30).",
|
|
573
|
-
schema:
|
|
649
|
+
schema: Type3.Object({ seconds: Type3.Optional(Type3.Number()) }),
|
|
574
650
|
async execute(params) {
|
|
575
651
|
const requested = params.seconds ?? 3;
|
|
576
652
|
await sleep(Math.min(Math.max(requested - 1, 0), 30) * 1e3);
|
|
@@ -579,9 +655,10 @@ var wait = defineAction({
|
|
|
579
655
|
});
|
|
580
656
|
var extractContent = defineAction({
|
|
581
657
|
name: "extract_content",
|
|
658
|
+
replaySafe: true,
|
|
582
659
|
description: "Extract the page's readable content, guided by a query.",
|
|
583
|
-
schema:
|
|
584
|
-
query:
|
|
660
|
+
schema: Type3.Object({
|
|
661
|
+
query: Type3.String()
|
|
585
662
|
}),
|
|
586
663
|
async execute(params, ctx) {
|
|
587
664
|
const text = await ctx.driver.extract(params.query, { signal: ctx.signal });
|
|
@@ -599,10 +676,10 @@ ${content}`,
|
|
|
599
676
|
var writeFile = defineAction({
|
|
600
677
|
name: "write_file",
|
|
601
678
|
description: "Write (replacing) a file in the agent workspace.",
|
|
602
|
-
schema:
|
|
603
|
-
fileName:
|
|
604
|
-
content:
|
|
605
|
-
append:
|
|
679
|
+
schema: Type3.Object({
|
|
680
|
+
fileName: Type3.String(),
|
|
681
|
+
content: Type3.String(),
|
|
682
|
+
append: Type3.Optional(Type3.Boolean())
|
|
606
683
|
}),
|
|
607
684
|
async execute(params, ctx) {
|
|
608
685
|
const message = params.append ? await ctx.fileSystem.appendFile(params.fileName, params.content) : await ctx.fileSystem.writeFile(params.fileName, params.content);
|
|
@@ -612,7 +689,7 @@ var writeFile = defineAction({
|
|
|
612
689
|
var appendFile = defineAction({
|
|
613
690
|
name: "append_file",
|
|
614
691
|
description: "Append content to a file in the agent workspace.",
|
|
615
|
-
schema:
|
|
692
|
+
schema: Type3.Object({ fileName: Type3.String(), content: Type3.String() }),
|
|
616
693
|
async execute(params, ctx) {
|
|
617
694
|
const message = await ctx.fileSystem.appendFile(params.fileName, params.content);
|
|
618
695
|
return stepResult({ extractedContent: message, longTermMemory: message });
|
|
@@ -621,7 +698,7 @@ var appendFile = defineAction({
|
|
|
621
698
|
var replaceFile = defineAction({
|
|
622
699
|
name: "replace_file",
|
|
623
700
|
description: "Replace a substring in a workspace file (the todo.md checkbox primitive).",
|
|
624
|
-
schema:
|
|
701
|
+
schema: Type3.Object({ fileName: Type3.String(), oldStr: Type3.String(), newStr: Type3.String() }),
|
|
625
702
|
async execute(params, ctx) {
|
|
626
703
|
const message = await ctx.fileSystem.replaceFileStr(
|
|
627
704
|
params.fileName,
|
|
@@ -633,8 +710,9 @@ var replaceFile = defineAction({
|
|
|
633
710
|
});
|
|
634
711
|
var readFile = defineAction({
|
|
635
712
|
name: "read_file",
|
|
713
|
+
replaySafe: true,
|
|
636
714
|
description: "Read a workspace file, or a whitelisted external file (text, .pdf, or .docx).",
|
|
637
|
-
schema:
|
|
715
|
+
schema: Type3.Object({ fileName: Type3.String() }),
|
|
638
716
|
async execute(params, ctx) {
|
|
639
717
|
const managed = ctx.fileSystem.getFile(params.fileName);
|
|
640
718
|
if (managed !== void 0) {
|
|
@@ -657,10 +735,10 @@ ${content}` });
|
|
|
657
735
|
var done = defineAction({
|
|
658
736
|
name: "done",
|
|
659
737
|
description: "Finish the task. success=true ONLY when fully complete. text must report only observed facts.",
|
|
660
|
-
schema:
|
|
661
|
-
text:
|
|
662
|
-
success:
|
|
663
|
-
filesToDisplay:
|
|
738
|
+
schema: Type3.Object({
|
|
739
|
+
text: Type3.String(),
|
|
740
|
+
success: Type3.Boolean(),
|
|
741
|
+
filesToDisplay: Type3.Optional(Type3.Array(Type3.String()))
|
|
664
742
|
}),
|
|
665
743
|
execute(params, ctx) {
|
|
666
744
|
const attachments = (params.filesToDisplay ?? []).map((name) => ctx.fileSystem.displayFile(name) !== void 0 ? name : void 0).filter((n) => n !== void 0);
|
|
@@ -979,28 +1057,28 @@ function isBinaryExtension(ext) {
|
|
|
979
1057
|
}
|
|
980
1058
|
|
|
981
1059
|
// src/agent/output-schema.ts
|
|
982
|
-
import { Type as
|
|
1060
|
+
import { Type as Type4 } from "@sinclair/typebox";
|
|
983
1061
|
function buildAgentOutputSchema(actionUnion, variant) {
|
|
984
|
-
const action =
|
|
1062
|
+
const action = Type4.Array(actionUnion, { minItems: 1 });
|
|
985
1063
|
if (variant === "flash") {
|
|
986
|
-
return
|
|
987
|
-
{ memory:
|
|
1064
|
+
return Type4.Object(
|
|
1065
|
+
{ memory: Type4.String(), action },
|
|
988
1066
|
{ additionalProperties: false, title: "AgentOutput" }
|
|
989
1067
|
);
|
|
990
1068
|
}
|
|
991
1069
|
const fields = {
|
|
992
|
-
evaluation_previous_goal:
|
|
993
|
-
memory:
|
|
994
|
-
next_goal:
|
|
1070
|
+
evaluation_previous_goal: Type4.String(),
|
|
1071
|
+
memory: Type4.String(),
|
|
1072
|
+
next_goal: Type4.String(),
|
|
995
1073
|
action
|
|
996
1074
|
};
|
|
997
1075
|
if (variant === "thinking") {
|
|
998
|
-
return
|
|
999
|
-
{ thinking:
|
|
1076
|
+
return Type4.Object(
|
|
1077
|
+
{ thinking: Type4.Optional(Type4.String()), ...fields },
|
|
1000
1078
|
{ additionalProperties: false, title: "AgentOutput" }
|
|
1001
1079
|
);
|
|
1002
1080
|
}
|
|
1003
|
-
return
|
|
1081
|
+
return Type4.Object(fields, { additionalProperties: false, title: "AgentOutput" });
|
|
1004
1082
|
}
|
|
1005
1083
|
function parseAction(entry) {
|
|
1006
1084
|
const keys = Object.keys(entry);
|
|
@@ -1682,6 +1760,7 @@ var CaptchaWatchdog = class {
|
|
|
1682
1760
|
};
|
|
1683
1761
|
|
|
1684
1762
|
// src/agent/step-loop.ts
|
|
1763
|
+
import { controlledProviderCall, currentRunContext as currentRunContext2 } from "@ap3x/agent-core";
|
|
1685
1764
|
import {
|
|
1686
1765
|
StructuredOutputError,
|
|
1687
1766
|
generateObject
|
|
@@ -1689,7 +1768,7 @@ import {
|
|
|
1689
1768
|
import {
|
|
1690
1769
|
buildInteractedElement
|
|
1691
1770
|
} from "@ap3x/browser";
|
|
1692
|
-
import { Type as
|
|
1771
|
+
import { Type as Type5 } from "@sinclair/typebox";
|
|
1693
1772
|
function anySignal(...signals) {
|
|
1694
1773
|
const present = signals.filter((s) => s !== void 0);
|
|
1695
1774
|
if (present.length === 0) return void 0;
|
|
@@ -1743,6 +1822,13 @@ var StepLoop = class {
|
|
|
1743
1822
|
this.stopped = true;
|
|
1744
1823
|
this.resume();
|
|
1745
1824
|
}
|
|
1825
|
+
/** Inject a mid-run course-correction: `text` rides into the NEXT step's
|
|
1826
|
+
* messages as a transient nudge (drained per step, like the loop-detector's).
|
|
1827
|
+
* Lets a caller steer a running agent without pausing or restarting it. */
|
|
1828
|
+
steer(text) {
|
|
1829
|
+
const trimmed = text.trim();
|
|
1830
|
+
if (trimmed) this.pendingNudges.push(trimmed);
|
|
1831
|
+
}
|
|
1746
1832
|
get isDone() {
|
|
1747
1833
|
return this.done;
|
|
1748
1834
|
}
|
|
@@ -1886,10 +1972,14 @@ var StepLoop = class {
|
|
|
1886
1972
|
let output;
|
|
1887
1973
|
try {
|
|
1888
1974
|
const llmSignal = anySignal(stepSignal, AbortSignal.timeout(this.deps.limits.llmTimeoutMs));
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1975
|
+
currentRunContext2()?.controller?.turn();
|
|
1976
|
+
const options = { ...this.deps.llmStreamOptions, signal: llmSignal };
|
|
1977
|
+
const { object, usage } = await controlledProviderCall(
|
|
1978
|
+
this.deps.model,
|
|
1979
|
+
{ messages },
|
|
1980
|
+
options,
|
|
1981
|
+
() => generateObject(this.deps.model, messages, schema, options)
|
|
1982
|
+
);
|
|
1893
1983
|
this.deps.ledger.record(this.deps.model.id, usage);
|
|
1894
1984
|
output = object;
|
|
1895
1985
|
} catch (error) {
|
|
@@ -2052,8 +2142,8 @@ var StepLoop = class {
|
|
|
2052
2142
|
/** A single-key union carrying only `done` (forced-termination schema). */
|
|
2053
2143
|
doneOnlyUnion() {
|
|
2054
2144
|
const done2 = this.deps.registry.get("done");
|
|
2055
|
-
const schema = done2?.schema ??
|
|
2056
|
-
return
|
|
2145
|
+
const schema = done2?.schema ?? Type5.Object({ text: Type5.String(), success: Type5.Boolean() });
|
|
2146
|
+
return Type5.Object({ done: schema }, { additionalProperties: false, title: "done" });
|
|
2057
2147
|
}
|
|
2058
2148
|
};
|
|
2059
2149
|
function historyState(state, sensitiveData) {
|
|
@@ -2259,17 +2349,18 @@ function generateRunGif(history, options = {}) {
|
|
|
2259
2349
|
}
|
|
2260
2350
|
|
|
2261
2351
|
// src/agent/judge.ts
|
|
2352
|
+
import { controlledProviderCall as controlledProviderCall2 } from "@ap3x/agent-core";
|
|
2262
2353
|
import {
|
|
2263
2354
|
generateObject as generateObject2
|
|
2264
2355
|
} from "@ap3x/ai";
|
|
2265
2356
|
import { PLACEHOLDER_SCREENSHOT as PLACEHOLDER_SCREENSHOT2 } from "@ap3x/browser";
|
|
2266
|
-
import { Type as
|
|
2267
|
-
var JudgementResultSchema =
|
|
2268
|
-
reasoning:
|
|
2269
|
-
verdict:
|
|
2270
|
-
failureReason:
|
|
2271
|
-
impossibleTask:
|
|
2272
|
-
reachedCaptcha:
|
|
2357
|
+
import { Type as Type6 } from "@sinclair/typebox";
|
|
2358
|
+
var JudgementResultSchema = Type6.Object({
|
|
2359
|
+
reasoning: Type6.String(),
|
|
2360
|
+
verdict: Type6.Boolean(),
|
|
2361
|
+
failureReason: Type6.String(),
|
|
2362
|
+
impossibleTask: Type6.Boolean(),
|
|
2363
|
+
reachedCaptcha: Type6.Boolean()
|
|
2273
2364
|
});
|
|
2274
2365
|
var MAX_TEXT_CHARS = 4e4;
|
|
2275
2366
|
var DEFAULT_MAX_IMAGES = 10;
|
|
@@ -2341,10 +2432,13 @@ async function judgeRun(model, task, history, options = {}) {
|
|
|
2341
2432
|
{ role: "user", content: system, timestamp: Date.now() },
|
|
2342
2433
|
{ role: "user", content: userParts, timestamp: Date.now() }
|
|
2343
2434
|
];
|
|
2344
|
-
const
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2435
|
+
const streamOptions = { ...options.streamOptions, signal: options.signal };
|
|
2436
|
+
const { object, usage } = await controlledProviderCall2(
|
|
2437
|
+
model,
|
|
2438
|
+
{ messages },
|
|
2439
|
+
streamOptions,
|
|
2440
|
+
() => generateObject2(model, messages, JudgementResultSchema, streamOptions)
|
|
2441
|
+
);
|
|
2348
2442
|
return { judgement: object, usage };
|
|
2349
2443
|
}
|
|
2350
2444
|
|
|
@@ -2375,11 +2469,11 @@ import { randomUUID } from "crypto";
|
|
|
2375
2469
|
import { tmpdir } from "os";
|
|
2376
2470
|
import { join as join3 } from "path";
|
|
2377
2471
|
import { BrowserDriver } from "@ap3x/browser";
|
|
2378
|
-
import { Type as
|
|
2472
|
+
import { Type as Type7 } from "@sinclair/typebox";
|
|
2379
2473
|
var screenshotAction = defineAction({
|
|
2380
2474
|
name: "screenshot",
|
|
2381
2475
|
description: "Capture a screenshot of the current page for visual inspection.",
|
|
2382
|
-
schema:
|
|
2476
|
+
schema: Type7.Object({}),
|
|
2383
2477
|
async execute(_params, ctx) {
|
|
2384
2478
|
const data = await ctx.driver.screenshot({ signal: ctx.signal });
|
|
2385
2479
|
return stepResult({
|
|
@@ -2435,6 +2529,7 @@ var Agent = class {
|
|
|
2435
2529
|
stepLoop;
|
|
2436
2530
|
pendingPaused = false;
|
|
2437
2531
|
pendingStopped = false;
|
|
2532
|
+
pendingSteers = [];
|
|
2438
2533
|
/** Set once, after `run()` completes, when `output.generateGif` is on. */
|
|
2439
2534
|
lastGif;
|
|
2440
2535
|
/** Set once, after `run()` completes, when `output.recordHar` is on. */
|
|
@@ -2533,6 +2628,13 @@ var Agent = class {
|
|
|
2533
2628
|
if (this.stepLoop) this.stepLoop.stop();
|
|
2534
2629
|
else this.pendingStopped = true;
|
|
2535
2630
|
}
|
|
2631
|
+
/** Course-correct a running (or not-yet-started) run: `text` is delivered to
|
|
2632
|
+
* the agent as a nudge on its next step. Buffered until the step loop exists
|
|
2633
|
+
* (mirroring `pause`), then flushed in order. */
|
|
2634
|
+
steer(text) {
|
|
2635
|
+
if (this.stepLoop) this.stepLoop.steer(text);
|
|
2636
|
+
else this.pendingSteers.push(text);
|
|
2637
|
+
}
|
|
2536
2638
|
// --- internals -------------------------------------------------------------
|
|
2537
2639
|
/** Clone the caller's (or default) registry and apply the vision filter (E7). */
|
|
2538
2640
|
buildRegistry() {
|
|
@@ -2646,6 +2748,7 @@ var Agent = class {
|
|
|
2646
2748
|
});
|
|
2647
2749
|
if (this.pendingStopped) this.stepLoop.stop();
|
|
2648
2750
|
else if (this.pendingPaused) this.stepLoop.pause();
|
|
2751
|
+
for (const steer of this.pendingSteers.splice(0)) this.stepLoop.steer(steer);
|
|
2649
2752
|
return this.stepLoop;
|
|
2650
2753
|
}
|
|
2651
2754
|
};
|
|
@@ -2672,7 +2775,7 @@ import {
|
|
|
2672
2775
|
CallToolRequestSchema,
|
|
2673
2776
|
ListToolsRequestSchema
|
|
2674
2777
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
2675
|
-
import { Type as
|
|
2778
|
+
import { Type as Type8 } from "@sinclair/typebox";
|
|
2676
2779
|
var ACT_TOOLS = [
|
|
2677
2780
|
{ tool: "browser_navigate", action: "navigate" },
|
|
2678
2781
|
{ tool: "browser_click", action: "click" },
|
|
@@ -2683,12 +2786,12 @@ var ACT_TOOLS = [
|
|
|
2683
2786
|
{ tool: "browser_switch_tab", action: "switch_tab" },
|
|
2684
2787
|
{ tool: "browser_close_tab", action: "close_tab" }
|
|
2685
2788
|
];
|
|
2686
|
-
var GET_STATE_SCHEMA =
|
|
2687
|
-
var SCREENSHOT_SCHEMA =
|
|
2688
|
-
var LIST_TABS_SCHEMA =
|
|
2689
|
-
var RUN_AGENT_SCHEMA =
|
|
2690
|
-
task:
|
|
2691
|
-
max_steps:
|
|
2789
|
+
var GET_STATE_SCHEMA = Type8.Object({ include_screenshot: Type8.Optional(Type8.Boolean()) });
|
|
2790
|
+
var SCREENSHOT_SCHEMA = Type8.Object({ full_page: Type8.Optional(Type8.Boolean()) });
|
|
2791
|
+
var LIST_TABS_SCHEMA = Type8.Object({});
|
|
2792
|
+
var RUN_AGENT_SCHEMA = Type8.Object({
|
|
2793
|
+
task: Type8.String(),
|
|
2794
|
+
max_steps: Type8.Optional(Type8.Integer({ minimum: 1 }))
|
|
2692
2795
|
});
|
|
2693
2796
|
function textResult(text) {
|
|
2694
2797
|
return { content: [{ type: "text", text }] };
|
|
@@ -2857,6 +2960,9 @@ export {
|
|
|
2857
2960
|
stepResult,
|
|
2858
2961
|
doneResult,
|
|
2859
2962
|
isDoneResult,
|
|
2963
|
+
BrowserPostconditionSchema,
|
|
2964
|
+
PostconditionError,
|
|
2965
|
+
verifyPostconditions,
|
|
2860
2966
|
resolveSecretsForUrl,
|
|
2861
2967
|
applicablePlaceholders,
|
|
2862
2968
|
sensitiveDataDescription,
|
package/dist/index.d.ts
CHANGED
|
@@ -34,4 +34,6 @@ export * from "./agent/judge";
|
|
|
34
34
|
export * from "./agent/captcha-watchdog";
|
|
35
35
|
export * from "./agent/video";
|
|
36
36
|
export * from "./testing";
|
|
37
|
+
export { verifyPostconditions, PostconditionError, type BrowserPostcondition, } from "./agent/postconditions";
|
|
38
|
+
export { BrowserWorkflowCatalog, type BrowserWorkflow, type BrowserWorkflowStep, type BrowserWorkflowStepResult, type BrowserWorkflowResult, } from "./agent/workflow-catalog";
|
|
37
39
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,eAAO,MAAM,OAAO,wBAAwB,CAAC;AAC7C,eAAO,MAAM,OAAO,UAAU,CAAC;AAE/B,cAAc,SAAS,CAAC;AACxB,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,0BAA0B,CAAC;AAEzC,cAAc,4BAA4B,CAAC;AAG3C,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AACxC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sBAAsB,CAAC;AACrC,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,cAAc,wBAAwB,CAAC;AACvC,cAAc,OAAO,CAAC;AAGtB,cAAc,iBAAiB,CAAC;AAChC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,gBAAgB,CAAC;AAI/B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAG9B,cAAc,0BAA0B,CAAC;AACzC,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,eAAO,MAAM,OAAO,wBAAwB,CAAC;AAC7C,eAAO,MAAM,OAAO,UAAU,CAAC;AAE/B,cAAc,SAAS,CAAC;AACxB,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,0BAA0B,CAAC;AAEzC,cAAc,4BAA4B,CAAC;AAG3C,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC;AACxC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sBAAsB,CAAC;AACrC,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,cAAc,wBAAwB,CAAC;AACvC,cAAc,OAAO,CAAC;AAGtB,cAAc,iBAAiB,CAAC;AAChC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,gBAAgB,CAAC;AAI/B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAG9B,cAAc,0BAA0B,CAAC;AACzC,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAE1B,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,KAAK,oBAAoB,GAC1B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,sBAAsB,EACtB,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,yBAAyB,EAC9B,KAAK,qBAAqB,GAC3B,MAAM,0BAA0B,CAAC"}
|