@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
package/dist/index.js
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
AgentEventStream,
|
|
13
13
|
AgentHistoryList,
|
|
14
14
|
BUILTIN_ACTIONS,
|
|
15
|
+
BrowserPostconditionSchema,
|
|
15
16
|
COMPACT_EVERY_N_STEPS,
|
|
16
17
|
COMPACT_TRIGGER_CHARS,
|
|
17
18
|
CaptchaWatchdog,
|
|
@@ -20,6 +21,7 @@ import {
|
|
|
20
21
|
JudgementResultSchema,
|
|
21
22
|
LoopDetector,
|
|
22
23
|
MessageManager,
|
|
24
|
+
PostconditionError,
|
|
23
25
|
Registry,
|
|
24
26
|
StepLoop,
|
|
25
27
|
UsageLedger,
|
|
@@ -57,10 +59,12 @@ import {
|
|
|
57
59
|
stepResult,
|
|
58
60
|
substituteSecrets,
|
|
59
61
|
toTypedAction,
|
|
60
|
-
totp
|
|
61
|
-
|
|
62
|
+
totp,
|
|
63
|
+
verifyPostconditions
|
|
64
|
+
} from "./chunk-LXHBVRFM.js";
|
|
62
65
|
|
|
63
66
|
// src/agent/backend.ts
|
|
67
|
+
import { resolveRunContext, withRunContext } from "@ap3x/agent-core";
|
|
64
68
|
var EMPTY_USAGE = {
|
|
65
69
|
input: 0,
|
|
66
70
|
output: 0,
|
|
@@ -169,14 +173,30 @@ var BrowserAgentBackend = class {
|
|
|
169
173
|
return this.source instanceof Agent ? this.source : new Agent(task, this.source);
|
|
170
174
|
}
|
|
171
175
|
async run(task, opts) {
|
|
176
|
+
const context = resolveRunContext(opts?.context, opts?.signal);
|
|
172
177
|
const taskText = toTaskText(task);
|
|
173
178
|
const agent = this.agentFor(taskText);
|
|
174
179
|
this.active = agent;
|
|
175
180
|
const pump = this.listeners.size > 0 ? this.pumpEvents(agent) : void 0;
|
|
176
181
|
try {
|
|
177
|
-
const history = await
|
|
182
|
+
const history = await withRunContext(
|
|
183
|
+
context,
|
|
184
|
+
() => agent.run({ signal: opts?.signal ?? context.signal })
|
|
185
|
+
);
|
|
178
186
|
await pump;
|
|
179
|
-
|
|
187
|
+
const result = this.toRunResult(
|
|
188
|
+
taskText,
|
|
189
|
+
history,
|
|
190
|
+
(opts?.signal ?? context.signal)?.aborted === true
|
|
191
|
+
);
|
|
192
|
+
const limit = context.controller?.snapshot().limit;
|
|
193
|
+
return {
|
|
194
|
+
...result,
|
|
195
|
+
aggregateUsage: result.usage,
|
|
196
|
+
execution: context.controller?.snapshot(),
|
|
197
|
+
runId: context.runId,
|
|
198
|
+
...limit && limit !== "cancelled" ? { outcome: "partial", reasonCode: "execution_limit" } : {}
|
|
199
|
+
};
|
|
180
200
|
} finally {
|
|
181
201
|
this.active = void 0;
|
|
182
202
|
}
|
|
@@ -381,10 +401,12 @@ import {
|
|
|
381
401
|
var UNIQUE_ATTRIBUTES = ["name", "id", "aria-label"];
|
|
382
402
|
var DIAGNOSTIC_CANDIDATE_LIMIT = 5;
|
|
383
403
|
function findBy(selectorMap, predicate) {
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
404
|
+
const matches = [...selectorMap].filter((entry) => predicate(entry[1]));
|
|
405
|
+
if (matches.length > 1)
|
|
406
|
+
throw new AmbiguousRematchError(
|
|
407
|
+
`Ambiguous browser target: ${matches.slice(0, 5).map((entry) => candidateLabel(entry[1])).join(", ")}`
|
|
408
|
+
);
|
|
409
|
+
return matches[0];
|
|
388
410
|
}
|
|
389
411
|
function candidateLabel(node) {
|
|
390
412
|
const label = node.axNode?.name ?? node.attributes["aria-label"] ?? node.attributes.name ?? node.attributes.id ?? "";
|
|
@@ -397,7 +419,23 @@ function diagnosticFor(recorded, selectorMap) {
|
|
|
397
419
|
const similarText = similar.length > 0 ? `Similar <${tag}> elements present: ${similar.join(", ")}.` : `No <${tag}> elements found on the current page.`;
|
|
398
420
|
return `Could not re-match recorded element <${tag}> "${sought}" (xpath: ${recorded.xpath}). ${similarText}`;
|
|
399
421
|
}
|
|
422
|
+
var AmbiguousRematchError = class extends Error {
|
|
423
|
+
};
|
|
400
424
|
function rematchElement(recorded, selectorMap) {
|
|
425
|
+
try {
|
|
426
|
+
const result = rematchUnique(recorded, selectorMap);
|
|
427
|
+
if (result.level === void 0) return { ...result, reasonCode: "target_not_found" };
|
|
428
|
+
return {
|
|
429
|
+
...result,
|
|
430
|
+
confidence: result.level === MatchLevel.Exact ? "exact" : result.level === MatchLevel.Stable ? "high" : result.level === MatchLevel.Structural ? "low" : "medium"
|
|
431
|
+
};
|
|
432
|
+
} catch (error) {
|
|
433
|
+
if (error instanceof AmbiguousRematchError)
|
|
434
|
+
return { level: void 0, diagnostic: error.message, reasonCode: "ambiguous_target" };
|
|
435
|
+
throw error;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
function rematchUnique(recorded, selectorMap) {
|
|
401
439
|
const exact = findBy(selectorMap, (node) => elementHash(node) === recorded.elementHash);
|
|
402
440
|
if (exact) return { level: MatchLevel.Exact, backendNodeId: exact[0], node: exact[1] };
|
|
403
441
|
const stable = findBy(selectorMap, (node) => stableHash(node) === recorded.stableHash);
|
|
@@ -420,6 +458,7 @@ function rematchElement(recorded, selectorMap) {
|
|
|
420
458
|
if (entry[1].attributes[attr] === wanted && entry[1].nodeName.toLowerCase() === recordedTag)
|
|
421
459
|
matches.push(entry);
|
|
422
460
|
}
|
|
461
|
+
if (matches.length > 1) throw new AmbiguousRematchError(`Ambiguous browser target for ${attr}`);
|
|
423
462
|
if (matches.length === 1) {
|
|
424
463
|
const [backendNodeId, node] = matches[0];
|
|
425
464
|
return { level: MatchLevel.Attribute, backendNodeId, node };
|
|
@@ -430,6 +469,8 @@ function rematchElement(recorded, selectorMap) {
|
|
|
430
469
|
for (const entry of selectorMap) {
|
|
431
470
|
if (parentBranchHash(entry[1]) === recorded.parentBranchHash) structuralMatches.push(entry);
|
|
432
471
|
}
|
|
472
|
+
if (structuralMatches.length > 1)
|
|
473
|
+
throw new AmbiguousRematchError("Ambiguous browser structural target");
|
|
433
474
|
if (structuralMatches.length === 1) {
|
|
434
475
|
const [backendNodeId, node] = structuralMatches[0];
|
|
435
476
|
return { level: MatchLevel.Structural, backendNodeId, node };
|
|
@@ -566,6 +607,7 @@ function substituteVariables(history, detected, values) {
|
|
|
566
607
|
}
|
|
567
608
|
|
|
568
609
|
// src/agent/replay.ts
|
|
610
|
+
import { controlledProviderCall } from "@ap3x/agent-core";
|
|
569
611
|
import { readFile, writeFile } from "fs/promises";
|
|
570
612
|
import {
|
|
571
613
|
complete,
|
|
@@ -663,6 +705,7 @@ var BrowserStateHistorySchema = Type2.Object({
|
|
|
663
705
|
interactedElements: Type2.Optional(Type2.Array(Type2.Union([InteractedElementSchema, Type2.Null()])))
|
|
664
706
|
});
|
|
665
707
|
var AgentHistoryItemSchema = Type2.Object({
|
|
708
|
+
postconditions: Type2.Optional(Type2.Array(BrowserPostconditionSchema)),
|
|
666
709
|
modelOutput: Type2.Optional(
|
|
667
710
|
Type2.Object({
|
|
668
711
|
thinking: Type2.Optional(Type2.String()),
|
|
@@ -748,14 +791,23 @@ async function buildRerunSummary(task, steps, succeeded, total, model, signal, s
|
|
|
748
791
|
].join("\n\n");
|
|
749
792
|
const messages = [{ role: "user", content: prompt, timestamp: Date.now() }];
|
|
750
793
|
try {
|
|
751
|
-
const
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
794
|
+
const options = { ...streamOptions, signal };
|
|
795
|
+
const { object } = await controlledProviderCall(
|
|
796
|
+
model,
|
|
797
|
+
{ messages },
|
|
798
|
+
options,
|
|
799
|
+
() => generateObject(model, messages, RerunSummarySchema, options)
|
|
800
|
+
);
|
|
755
801
|
return { ...object, summarySource: "llm" };
|
|
756
802
|
} catch {
|
|
757
803
|
try {
|
|
758
|
-
const
|
|
804
|
+
const options = { ...streamOptions, signal };
|
|
805
|
+
const response = await controlledProviderCall(
|
|
806
|
+
model,
|
|
807
|
+
{ messages },
|
|
808
|
+
options,
|
|
809
|
+
() => complete(model, { messages }, options)
|
|
810
|
+
);
|
|
759
811
|
const text = response.content.filter((b) => b.type === "text").map((b) => b.text).join("").trim();
|
|
760
812
|
if (text)
|
|
761
813
|
return {
|
|
@@ -906,7 +958,7 @@ async function rerunHistory(history, deps, options = {}) {
|
|
|
906
958
|
continue;
|
|
907
959
|
}
|
|
908
960
|
const identity = stepIdentity(item);
|
|
909
|
-
if (identity && lastSuccessful && identity.actionName === lastSuccessful.actionName && sameElement(identity.element, lastSuccessful.element)) {
|
|
961
|
+
if (identity && deps.registry.get(identity.actionName)?.replaySafe === true && lastSuccessful && identity.actionName === lastSuccessful.actionName && sameElement(identity.element, lastSuccessful.element)) {
|
|
910
962
|
steps.push({ stepNumber, outcome: "skipped-redundant", matchLevels: [], attempts: 0 });
|
|
911
963
|
continue;
|
|
912
964
|
}
|
|
@@ -932,6 +984,12 @@ async function rerunHistory(history, deps, options = {}) {
|
|
|
932
984
|
sleep,
|
|
933
985
|
reopenState
|
|
934
986
|
);
|
|
987
|
+
await verifyPostconditions(
|
|
988
|
+
item.postconditions ?? [],
|
|
989
|
+
deps.driver,
|
|
990
|
+
deps.session,
|
|
991
|
+
attemptSignal
|
|
992
|
+
);
|
|
935
993
|
outcome = { stepNumber, outcome: "replayed", matchLevels, results, attempts: attempt + 1 };
|
|
936
994
|
lastSuccessful = identity;
|
|
937
995
|
const openerCandidate = item.state.interactedElements?.[0];
|
|
@@ -941,7 +999,7 @@ async function rerunHistory(history, deps, options = {}) {
|
|
|
941
999
|
} : void 0;
|
|
942
1000
|
} catch (error) {
|
|
943
1001
|
if (signal?.aborted) throw new DOMException("Aborted", "AbortError");
|
|
944
|
-
const stepError = attemptSignal?.aborted && !(error instanceof ReplayStepError) ? new ReplayStepError(
|
|
1002
|
+
const stepError = error instanceof PostconditionError ? new ReplayStepError(error.message, [], []) : attemptSignal?.aborted && !(error instanceof ReplayStepError) ? new ReplayStepError(
|
|
945
1003
|
`step ${stepNumber} attempt timed out after ${stepTimeoutMs}ms`,
|
|
946
1004
|
[],
|
|
947
1005
|
[]
|
|
@@ -949,7 +1007,11 @@ async function rerunHistory(history, deps, options = {}) {
|
|
|
949
1007
|
if (!(stepError instanceof ReplayStepError)) throw stepError;
|
|
950
1008
|
attempt += 1;
|
|
951
1009
|
log.warn("replay step failed", { step: stepNumber, attempt, error: stepError.message });
|
|
952
|
-
|
|
1010
|
+
const retrySafe = actions.every((raw) => {
|
|
1011
|
+
const parsed = parseAction(raw);
|
|
1012
|
+
return parsed && deps.registry.get(parsed.name)?.replaySafe === true;
|
|
1013
|
+
});
|
|
1014
|
+
if (attempt >= maxRetries || !retrySafe) {
|
|
953
1015
|
lastSuccessful = void 0;
|
|
954
1016
|
const message = `step ${stepNumber} failed after ${attempt} attempt(s): ${stepError.message}`;
|
|
955
1017
|
if (!skipFailures) {
|
|
@@ -991,6 +1053,111 @@ async function loadAndRerun(filePath, deps, options = {}) {
|
|
|
991
1053
|
return { ...report, detectedVariables: detected };
|
|
992
1054
|
}
|
|
993
1055
|
|
|
1056
|
+
// src/agent/workflow-catalog.ts
|
|
1057
|
+
import { resolveRunContext as resolveRunContext2, withRunContext as withRunContext2 } from "@ap3x/agent-core";
|
|
1058
|
+
import { Value as Value2 } from "@sinclair/typebox/value";
|
|
1059
|
+
var BrowserWorkflowCatalog = class {
|
|
1060
|
+
entries = /* @__PURE__ */ new Map();
|
|
1061
|
+
register(workflow) {
|
|
1062
|
+
if (!workflow.id || !workflow.version || this.entries.has(workflow.id))
|
|
1063
|
+
throw new Error("Workflow id/version must be unique and explicit");
|
|
1064
|
+
this.entries.set(workflow.id, workflow);
|
|
1065
|
+
}
|
|
1066
|
+
list() {
|
|
1067
|
+
return [...this.entries.values()].map(({ id, version }) => ({ id, version }));
|
|
1068
|
+
}
|
|
1069
|
+
async run(id, params, deps, options = {}) {
|
|
1070
|
+
const workflow = this.entries.get(id);
|
|
1071
|
+
if (!workflow) throw new Error(`Unknown workflow ${id}`);
|
|
1072
|
+
if (!Value2.Check(workflow.parameters, params)) throw new Error("Invalid workflow parameters");
|
|
1073
|
+
const maximum = options.maxAttempts ?? 1;
|
|
1074
|
+
if (!Number.isInteger(maximum) || maximum < 1) throw new Error("maxAttempts must be positive");
|
|
1075
|
+
const context = resolveRunContext2(options.context, options.signal);
|
|
1076
|
+
const signal = AbortSignal.any(
|
|
1077
|
+
[options.signal, context.signal, context.controller?.signal].filter(
|
|
1078
|
+
(s) => !!s
|
|
1079
|
+
)
|
|
1080
|
+
);
|
|
1081
|
+
return withRunContext2(context, async () => {
|
|
1082
|
+
const steps = [];
|
|
1083
|
+
const definitions = workflow.steps(params);
|
|
1084
|
+
if (definitions.some((step) => !step.postconditions.length))
|
|
1085
|
+
throw new Error("Workflow steps require explicit postconditions");
|
|
1086
|
+
try {
|
|
1087
|
+
for (const [index, step] of definitions.entries()) {
|
|
1088
|
+
if (options.signal?.aborted || context.signal?.aborted)
|
|
1089
|
+
return { id, version: workflow.version, outcome: "cancelled", steps };
|
|
1090
|
+
let record;
|
|
1091
|
+
for (let attempt = 1; attempt <= maximum; attempt++) {
|
|
1092
|
+
const before = await deps.driver.getState({ signal });
|
|
1093
|
+
const secrets = resolveSecretsForUrl(options.sensitiveData ?? {}, before.url);
|
|
1094
|
+
const result = await deps.registry.execute(
|
|
1095
|
+
step.action,
|
|
1096
|
+
step.params,
|
|
1097
|
+
{
|
|
1098
|
+
session: deps.session,
|
|
1099
|
+
driver: deps.driver,
|
|
1100
|
+
pageUrl: before.url,
|
|
1101
|
+
fileSystem: deps.fileSystem,
|
|
1102
|
+
extractionLlm: deps.extractionLlm,
|
|
1103
|
+
availableFilePaths: deps.availableFilePaths ?? [],
|
|
1104
|
+
hasSensitiveData: false,
|
|
1105
|
+
signal
|
|
1106
|
+
},
|
|
1107
|
+
secrets,
|
|
1108
|
+
options.sensitiveData
|
|
1109
|
+
);
|
|
1110
|
+
if (options.signal?.aborted || context.signal?.aborted || context.controller?.signal.aborted)
|
|
1111
|
+
return { id, version: workflow.version, outcome: "cancelled", steps };
|
|
1112
|
+
let reasonCode = result.error ? "action_failed" : void 0;
|
|
1113
|
+
if (!reasonCode)
|
|
1114
|
+
try {
|
|
1115
|
+
await verifyPostconditions(
|
|
1116
|
+
substituteSecrets(step.postconditions, secrets).value,
|
|
1117
|
+
deps.driver,
|
|
1118
|
+
deps.session,
|
|
1119
|
+
signal
|
|
1120
|
+
);
|
|
1121
|
+
} catch (error) {
|
|
1122
|
+
if (options.signal?.aborted || context.signal?.aborted || context.controller?.signal.aborted)
|
|
1123
|
+
return { id, version: workflow.version, outcome: "cancelled", steps };
|
|
1124
|
+
if (!(error instanceof PostconditionError)) throw error;
|
|
1125
|
+
reasonCode = "postcondition_failed";
|
|
1126
|
+
}
|
|
1127
|
+
const after = await deps.driver.getState({ signal });
|
|
1128
|
+
record = {
|
|
1129
|
+
index,
|
|
1130
|
+
action: step.action,
|
|
1131
|
+
attempts: attempt,
|
|
1132
|
+
outcome: reasonCode ? "failed" : "succeeded",
|
|
1133
|
+
reasonCode,
|
|
1134
|
+
result,
|
|
1135
|
+
snapshot: {
|
|
1136
|
+
url: maskOutbound(after.url, options.sensitiveData ?? {}),
|
|
1137
|
+
title: maskOutbound(after.title, options.sensitiveData ?? {}),
|
|
1138
|
+
text: maskOutbound(after.serializedText, options.sensitiveData ?? {})
|
|
1139
|
+
}
|
|
1140
|
+
};
|
|
1141
|
+
if (!reasonCode || step.replaySafe !== true || deps.registry.get(step.action)?.replaySafe !== true)
|
|
1142
|
+
break;
|
|
1143
|
+
}
|
|
1144
|
+
if (record) {
|
|
1145
|
+
steps.push(record);
|
|
1146
|
+
await options.onStep?.(record);
|
|
1147
|
+
if (record.outcome !== "succeeded")
|
|
1148
|
+
return { id, version: workflow.version, outcome: "failed", steps };
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
return { id, version: workflow.version, outcome: "succeeded", steps };
|
|
1152
|
+
} catch (error) {
|
|
1153
|
+
if (options.signal?.aborted || context.signal?.aborted || context.controller?.signal.aborted)
|
|
1154
|
+
return { id, version: workflow.version, outcome: "cancelled", steps };
|
|
1155
|
+
throw error;
|
|
1156
|
+
}
|
|
1157
|
+
});
|
|
1158
|
+
}
|
|
1159
|
+
};
|
|
1160
|
+
|
|
994
1161
|
// src/index.ts
|
|
995
1162
|
var PACKAGE = "@ap3x/browser-agent";
|
|
996
1163
|
var VERSION = "0.1.0";
|
|
@@ -1000,6 +1167,7 @@ export {
|
|
|
1000
1167
|
AgentHistoryList,
|
|
1001
1168
|
BUILTIN_ACTIONS,
|
|
1002
1169
|
BrowserAgentBackend,
|
|
1170
|
+
BrowserWorkflowCatalog,
|
|
1003
1171
|
COMPACT_EVERY_N_STEPS,
|
|
1004
1172
|
COMPACT_TRIGGER_CHARS,
|
|
1005
1173
|
CaptchaWatchdog,
|
|
@@ -1010,6 +1178,7 @@ export {
|
|
|
1010
1178
|
LoopDetector,
|
|
1011
1179
|
MessageManager,
|
|
1012
1180
|
PACKAGE,
|
|
1181
|
+
PostconditionError,
|
|
1013
1182
|
Registry,
|
|
1014
1183
|
StepLoop,
|
|
1015
1184
|
UsageLedger,
|
|
@@ -1066,5 +1235,6 @@ export {
|
|
|
1066
1235
|
toTypedAction,
|
|
1067
1236
|
totp,
|
|
1068
1237
|
transportErrorResponse,
|
|
1069
|
-
truncatedLlmResponse
|
|
1238
|
+
truncatedLlmResponse,
|
|
1239
|
+
verifyPostconditions
|
|
1070
1240
|
};
|
package/dist/mcp/bin.js
CHANGED
package/dist/mcp/client.d.ts
CHANGED
|
@@ -37,7 +37,7 @@ export interface McpStdioConnection {
|
|
|
37
37
|
/**
|
|
38
38
|
* Convenience: spawn a stdio MCP server and return a connected `Client`, ready to
|
|
39
39
|
* hand to {@link importMcpTools}. A connection failure throws
|
|
40
|
-
* `AgentMCPConnectionError` (
|
|
40
|
+
* `AgentMCPConnectionError` (defined in @ap3x/agent-core). For tests, construct a
|
|
41
41
|
* `Client` over an in-memory transport and pass it to `importMcpTools` directly —
|
|
42
42
|
* this helper is only the real-process path.
|
|
43
43
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/tools/actions.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,KAAK,OAAO,EAAQ,MAAM,mBAAmB,CAAC;AAEvD,OAAO,EAAsB,KAAK,gBAAgB,EAAE,QAAQ,EAAgB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/tools/actions.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,KAAK,OAAO,EAAQ,MAAM,mBAAmB,CAAC;AAEvD,OAAO,EAAsB,KAAK,gBAAgB,EAAE,QAAQ,EAAgB,MAAM,YAAY,CAAC;AAsX/F,gDAAgD;AAChD,eAAO,MAAM,eAAe,EAqBZ,aAAa,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC;AAEzD,sDAAsD;AACtD,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAEzD;AAED,+DAA+D;AAC/D,wBAAgB,qBAAqB,IAAI,QAAQ,CAIhD"}
|
package/dist/tools/registry.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type BrowserPostcondition } from "../agent/postconditions";
|
|
1
2
|
import type { BrowserDriver, BrowserSession, CdpTransport } from "@ap3x/browser";
|
|
2
3
|
import { type Static, type TSchema } from "@sinclair/typebox";
|
|
3
4
|
import type { FileSystem } from "../filesystem/file-system";
|
|
@@ -48,6 +49,8 @@ export interface ActionContext {
|
|
|
48
49
|
}
|
|
49
50
|
/** The shape passed to {@link defineAction}. */
|
|
50
51
|
export interface ActionDefinition<S extends TSchema> {
|
|
52
|
+
replaySafe?: boolean;
|
|
53
|
+
postconditions?: readonly BrowserPostcondition[];
|
|
51
54
|
/** Unique action name — the single key in the wire JSON `{ name: params }`. */
|
|
52
55
|
name: string;
|
|
53
56
|
/** One-line description shown to the model. */
|
|
@@ -63,6 +66,8 @@ export interface ActionDefinition<S extends TSchema> {
|
|
|
63
66
|
}
|
|
64
67
|
/** A registered action, type-erased for storage. */
|
|
65
68
|
export interface RegisteredAction {
|
|
69
|
+
replaySafe: boolean;
|
|
70
|
+
postconditions?: readonly BrowserPostcondition[];
|
|
66
71
|
name: string;
|
|
67
72
|
description: string;
|
|
68
73
|
schema: TSchema;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/tools/registry.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/tools/registry.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ap3x/browser-agent",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Browser-driving agent over @ap3x/browser, with an MCP server",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -34,9 +34,9 @@
|
|
|
34
34
|
"test": "vitest run"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@ap3x/agent-core": "0.
|
|
38
|
-
"@ap3x/ai": "0.
|
|
39
|
-
"@ap3x/browser": "0.
|
|
37
|
+
"@ap3x/agent-core": "0.2.0",
|
|
38
|
+
"@ap3x/ai": "0.2.0",
|
|
39
|
+
"@ap3x/browser": "0.2.0",
|
|
40
40
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
41
41
|
"@sinclair/typebox": "^0.34.49",
|
|
42
42
|
"fflate": "^0.8.3",
|