@ddwang/magnitude-core 0.3.1-ddwang.1 → 0.3.1-ddwang.2
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/actions/desktopActions.js +2 -1
- package/dist/actions/index.d.ts +10 -9
- package/dist/actions/memoryActions.d.ts +9 -0
- package/dist/actions/memoryActions.js +34 -0
- package/dist/actions/types.d.ts +5 -1
- package/dist/actions/util.d.ts +2 -1
- package/dist/actions/util.js +6 -23
- package/dist/actions/webActions.d.ts +9 -1
- package/dist/actions/webActions.js +29 -5
- package/dist/actions/webActions.test.d.ts +1 -0
- package/dist/actions/webActions.test.js +43 -0
- package/dist/agent/browserAgent.d.ts +4 -2
- package/dist/agent/browserAgent.js +18 -4
- package/dist/agent/errors.d.ts +14 -0
- package/dist/agent/errors.js +29 -0
- package/dist/agent/index.d.ts +17 -6
- package/dist/agent/index.js +151 -23
- package/dist/ai/baml_client/async_client.d.ts +17 -26
- package/dist/ai/baml_client/async_client.js +175 -43
- package/dist/ai/baml_client/async_request.d.ts +13 -9
- package/dist/ai/baml_client/async_request.js +55 -19
- package/dist/ai/baml_client/index.d.ts +2 -1
- package/dist/ai/baml_client/index.js +6 -5
- package/dist/ai/baml_client/inlinedbaml.js +2 -2
- package/dist/ai/baml_client/parser.js +18 -18
- package/dist/ai/baml_client/sync_client.d.ts +12 -5
- package/dist/ai/baml_client/sync_client.js +64 -22
- package/dist/ai/baml_client/sync_request.d.ts +11 -9
- package/dist/ai/baml_client/sync_request.js +55 -19
- package/dist/ai/baml_client/type_builder.d.ts +2 -0
- package/dist/ai/baml_client/type_builder.js +25 -1
- package/dist/ai/baml_client/watchers.d.ts +32 -0
- package/dist/ai/baml_client/watchers.js +50 -0
- package/dist/ai/baseten.d.ts +4 -0
- package/dist/ai/baseten.js +10 -0
- package/dist/ai/modelHarness.d.ts +9 -9
- package/dist/ai/modelHarness.js +204 -69
- package/dist/ai/modelResponseError.d.ts +4 -0
- package/dist/ai/modelResponseError.js +8 -0
- package/dist/ai/multiModelHarness.d.ts +2 -5
- package/dist/ai/plannerResponse.d.ts +34 -0
- package/dist/ai/plannerResponse.js +96 -0
- package/dist/ai/plannerResponse.test.d.ts +1 -0
- package/dist/ai/plannerResponse.test.js +112 -0
- package/dist/ai/structuredOutput.d.ts +11 -0
- package/dist/ai/structuredOutput.js +94 -0
- package/dist/ai/structuredOutput.test.d.ts +1 -0
- package/dist/ai/structuredOutput.test.js +91 -0
- package/dist/ai/types.d.ts +30 -1
- package/dist/ai/util.js +38 -3
- package/dist/ai/util.test.d.ts +1 -0
- package/dist/ai/util.test.js +95 -0
- package/dist/common/events.d.ts +2 -0
- package/dist/common/operation.d.ts +31 -0
- package/dist/common/operation.js +102 -0
- package/dist/common/operation.test.d.ts +1 -0
- package/dist/common/operation.test.js +53 -0
- package/dist/common/retry.js +7 -2
- package/dist/common/util.js +9 -2
- package/dist/connectors/browserConnector.d.ts +13 -0
- package/dist/connectors/browserConnector.js +167 -4
- package/dist/connectors/index.d.ts +6 -2
- package/dist/index.cjs +1568 -355
- package/dist/index.d.cts +259 -74
- package/dist/index.d.ts +4 -0
- package/dist/index.js +2 -0
- package/dist/index.mjs +1563 -358
- package/dist/memory/agentMemory.d.ts +10 -0
- package/dist/memory/agentMemory.js +60 -14
- package/dist/memory/agentMemory.test.d.ts +1 -0
- package/dist/memory/agentMemory.test.js +150 -0
- package/dist/memory/image.d.ts +2 -0
- package/dist/memory/image.js +24 -35
- package/dist/memory/image.test.d.ts +1 -0
- package/dist/memory/image.test.js +46 -0
- package/dist/memory/notebook.d.ts +58 -0
- package/dist/memory/notebook.js +75 -0
- package/dist/memory/notebook.test.d.ts +1 -0
- package/dist/memory/notebook.test.js +99 -0
- package/dist/memory/rendering/renderJsonParts.test.js +2 -2
- package/dist/memory/serde.js +4 -18
- package/dist/memory/serde.test.d.ts +1 -0
- package/dist/memory/serde.test.js +64 -0
- package/dist/web/browserProvider.d.ts +1 -0
- package/dist/web/browserProvider.js +11 -0
- package/dist/web/browserProvider.test.d.ts +1 -0
- package/dist/web/browserProvider.test.js +44 -0
- package/dist/web/harness.d.ts +7 -0
- package/dist/web/harness.js +80 -19
- package/dist/web/recovery.d.ts +46 -0
- package/dist/web/recovery.js +137 -0
- package/dist/web/recovery.test.d.ts +1 -0
- package/dist/web/recovery.test.js +182 -0
- package/dist/web/stability.js +10 -3
- package/dist/web/types.d.ts +6 -1
- package/dist/web/visualizer/cursor.js +2 -1
- package/dist/web/zodReexport.test.d.ts +1 -0
- package/dist/web/zodReexport.test.js +14 -0
- package/package.json +2 -2
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createAction } from ".";
|
|
2
|
+
import { operationSleep } from '@/common/operation';
|
|
2
3
|
import { z } from "zod";
|
|
3
4
|
import { DesktopConnector } from "@/connectors/desktopConnector";
|
|
4
5
|
// Mouse actions
|
|
@@ -136,7 +137,7 @@ export const desktopWaitAction = createAction({
|
|
|
136
137
|
seconds: z.number().describe("Seconds to wait"),
|
|
137
138
|
}),
|
|
138
139
|
resolver: async ({ input: { seconds }, agent }) => {
|
|
139
|
-
await
|
|
140
|
+
await operationSleep(seconds * 1000);
|
|
140
141
|
},
|
|
141
142
|
render: ({ seconds }) => `◴ wait ${seconds}s`
|
|
142
143
|
});
|
package/dist/actions/index.d.ts
CHANGED
|
@@ -1,24 +1,25 @@
|
|
|
1
|
-
import { Agent } from "@/agent";
|
|
1
|
+
import type { Agent } from "@/agent";
|
|
2
|
+
import type { AgentMemory } from '@/memory/agentMemory';
|
|
2
3
|
import { RenderableContent } from "@/memory/observation";
|
|
3
4
|
import { z, Schema, ZodTypeAny } from "zod";
|
|
5
|
+
import type { OperationOptions } from '@/common/operation';
|
|
6
|
+
export type ActionContext<T> = {
|
|
7
|
+
input: T;
|
|
8
|
+
agent: Agent;
|
|
9
|
+
memory?: AgentMemory;
|
|
10
|
+
} & OperationOptions;
|
|
4
11
|
export interface ActionDefinition<T> {
|
|
5
12
|
name: string;
|
|
6
13
|
description?: string;
|
|
7
14
|
schema: Schema<T>;
|
|
8
|
-
resolver: (
|
|
9
|
-
input: T;
|
|
10
|
-
agent: Agent;
|
|
11
|
-
}) => Promise<void | RenderableContent>;
|
|
15
|
+
resolver: (context: ActionContext<T>) => Promise<void | RenderableContent>;
|
|
12
16
|
render: (action: T) => string;
|
|
13
17
|
}
|
|
14
18
|
export declare function createAction<S extends ZodTypeAny>(action: {
|
|
15
19
|
name: string;
|
|
16
20
|
description?: string;
|
|
17
21
|
schema?: S;
|
|
18
|
-
resolver: (
|
|
19
|
-
input: z.infer<S>;
|
|
20
|
-
agent: Agent;
|
|
21
|
-
}) => Promise<void | RenderableContent>;
|
|
22
|
+
resolver: (context: ActionContext<z.infer<S>>) => Promise<void | RenderableContent>;
|
|
22
23
|
render?: (action: z.infer<S>) => string;
|
|
23
24
|
}): ActionDefinition<z.infer<S>>;
|
|
24
25
|
export type ActionPayload<A extends ActionDefinition<any>> = {
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { createAction } from '.';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { NOTEBOOK_LIMITS, noteUpdateSchema } from '@/memory/notebook';
|
|
4
|
+
export const memoryActions = [
|
|
5
|
+
createAction({
|
|
6
|
+
name: 'memory:note',
|
|
7
|
+
description: 'Add a new record or explicitly correct one existing record before leaving facts needed later. Adds never overwrite. Corrections must match the targeted note\'s current text. Cite supporting observations. This consumes one action without interacting with the browser.',
|
|
8
|
+
schema: noteUpdateSchema,
|
|
9
|
+
resolver: async ({ input, agent, memory }) => {
|
|
10
|
+
try {
|
|
11
|
+
const { operation, expected_text, ...note } = input;
|
|
12
|
+
if (operation === 'add' ? expected_text !== null : expected_text === null) {
|
|
13
|
+
throw new Error('Use expected_text null for add; for correct, copy the targeted note\'s exact current text.');
|
|
14
|
+
}
|
|
15
|
+
(memory ?? agent.memory).remember(note, expected_text ?? undefined);
|
|
16
|
+
return { saved: input.key };
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
return { saved: false, error: String(error), instruction: 'No notes changed. Review the error and notebook. New records need new keys; corrections need an exact current-text match. Preserve existing facts when addressing source or capacity errors.' };
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
render: input => `note: ${input.key}`,
|
|
23
|
+
}),
|
|
24
|
+
createAction({
|
|
25
|
+
name: 'memory:forget',
|
|
26
|
+
description: 'Remove an obsolete task note after consolidating any facts still needed. This does not delete the captured observation history.',
|
|
27
|
+
schema: z.object({ key: z.string().min(1).max(NOTEBOOK_LIMITS.key) }),
|
|
28
|
+
resolver: async ({ input, agent, memory }) => {
|
|
29
|
+
(memory ?? agent.memory).forget(input.key);
|
|
30
|
+
return { forgotten: input.key };
|
|
31
|
+
},
|
|
32
|
+
render: input => `forget note: ${input.key}`,
|
|
33
|
+
}),
|
|
34
|
+
];
|
package/dist/actions/types.d.ts
CHANGED
|
@@ -7,12 +7,16 @@ export interface Action {
|
|
|
7
7
|
variant: string;
|
|
8
8
|
[key: string]: any;
|
|
9
9
|
}
|
|
10
|
-
export type ActionIntent = ClickIntent | TypeIntent | ScrollIntent | SwitchTabIntent;
|
|
10
|
+
export type ActionIntent = ClickIntent | HoverIntent | TypeIntent | ScrollIntent | SwitchTabIntent;
|
|
11
11
|
export type Intent = ActionIntent | CheckIntent;
|
|
12
12
|
export interface ClickIntent {
|
|
13
13
|
variant: 'click';
|
|
14
14
|
target: string;
|
|
15
15
|
}
|
|
16
|
+
export interface HoverIntent {
|
|
17
|
+
variant: 'hover';
|
|
18
|
+
target: string;
|
|
19
|
+
}
|
|
16
20
|
export interface TypeIntent {
|
|
17
21
|
variant: 'type';
|
|
18
22
|
target: string;
|
package/dist/actions/util.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ActionDefinition } from ".";
|
|
2
2
|
import TypeBuilder from "@/ai/baml_client/type_builder";
|
|
3
3
|
import { FieldType } from "@boundaryml/baml/native";
|
|
4
|
-
import { Schema } from "zod";
|
|
4
|
+
import { Schema, ZodSchema } from "zod";
|
|
5
5
|
export interface JsonSchema {
|
|
6
6
|
type?: string;
|
|
7
7
|
title?: string;
|
|
@@ -18,3 +18,4 @@ export interface JsonSchema {
|
|
|
18
18
|
}
|
|
19
19
|
export declare function convertZodToBaml(tb: TypeBuilder, schema: Schema): FieldType;
|
|
20
20
|
export declare function convertActionDefinitionsToBaml<T>(tb: TypeBuilder, actionVocabulary: ActionDefinition<T>[]): FieldType;
|
|
21
|
+
export declare function actionInputSchema<T>({ name, description, schema }: ActionDefinition<T>): ZodSchema<any>;
|
package/dist/actions/util.js
CHANGED
|
@@ -268,29 +268,12 @@ export function convertActionDefinitionsToBaml(tb, actionVocabulary) {
|
|
|
268
268
|
/**
|
|
269
269
|
* Convert action definitions to BAML TypeBuilder union representing any one of the actions
|
|
270
270
|
*/
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
const baseWrapperSchema = z.object({
|
|
278
|
-
variant: description ? z.literal(name).describe(description) : z.literal(name)
|
|
279
|
-
});
|
|
280
|
-
if (schema instanceof ZodObject) {
|
|
281
|
-
// Merge the variant field with the existing object schema
|
|
282
|
-
// The original schema's fields will be at the top level alongside 'variant'.
|
|
283
|
-
wrapperSchema = baseWrapperSchema.merge(schema);
|
|
284
|
-
}
|
|
285
|
-
else {
|
|
286
|
-
wrapperSchema = baseWrapperSchema.extend({
|
|
287
|
-
input: schema,
|
|
288
|
-
});
|
|
289
|
-
}
|
|
290
|
-
//if (description) wrapperSchema = wrapperSchema.describe(description);
|
|
291
|
-
actionTypes.push(convertZodToBaml(tb, wrapperSchema));
|
|
292
|
-
}
|
|
293
|
-
return tb.union(actionTypes);
|
|
271
|
+
return tb.union(actionVocabulary.map(action => convertZodToBaml(tb, actionInputSchema(action))));
|
|
272
|
+
}
|
|
273
|
+
// One wire schema for BAML's prompt and provider-enforced structured output.
|
|
274
|
+
export function actionInputSchema({ name, description, schema }) {
|
|
275
|
+
const wrapper = z.object({ variant: description ? z.literal(name).describe(description) : z.literal(name) });
|
|
276
|
+
return schema instanceof ZodObject ? wrapper.merge(schema) : wrapper.extend({ input: schema });
|
|
294
277
|
}
|
|
295
278
|
//const tb = new TypeBuilder();
|
|
296
279
|
//console.log(convertZodToBaml(tb, z.string()))
|
|
@@ -7,6 +7,10 @@ export declare const mouseDoubleClickAction: ActionDefinition<{
|
|
|
7
7
|
x: number;
|
|
8
8
|
y: number;
|
|
9
9
|
}>;
|
|
10
|
+
export declare const mouseHoverAction: ActionDefinition<{
|
|
11
|
+
x: number;
|
|
12
|
+
y: number;
|
|
13
|
+
}>;
|
|
10
14
|
export declare const mouseRightClickAction: ActionDefinition<{
|
|
11
15
|
x: number;
|
|
12
16
|
y: number;
|
|
@@ -28,6 +32,7 @@ export declare const keyboardEnterAction: ActionDefinition<any>;
|
|
|
28
32
|
export declare const keyboardTabAction: ActionDefinition<any>;
|
|
29
33
|
export declare const keyboardBackspaceAction: ActionDefinition<any>;
|
|
30
34
|
export declare const keyboardSelectAllAction: ActionDefinition<any>;
|
|
35
|
+
export declare const keyboardEscapeAction: ActionDefinition<{}>;
|
|
31
36
|
export declare const scrollCoordAction: ActionDefinition<{
|
|
32
37
|
x: number;
|
|
33
38
|
y: number;
|
|
@@ -54,6 +59,9 @@ export declare const webActions: readonly [ActionDefinition<{
|
|
|
54
59
|
}>, ActionDefinition<{
|
|
55
60
|
x: number;
|
|
56
61
|
y: number;
|
|
62
|
+
}>, ActionDefinition<{
|
|
63
|
+
x: number;
|
|
64
|
+
y: number;
|
|
57
65
|
}>, ActionDefinition<{
|
|
58
66
|
x: number;
|
|
59
67
|
y: number;
|
|
@@ -74,6 +82,6 @@ export declare const webActions: readonly [ActionDefinition<{
|
|
|
74
82
|
url: string;
|
|
75
83
|
}>, ActionDefinition<{
|
|
76
84
|
content: string;
|
|
77
|
-
}>, ActionDefinition<any>, ActionDefinition<any>, ActionDefinition<any>, ActionDefinition<any>, ActionDefinition<{
|
|
85
|
+
}>, ActionDefinition<any>, ActionDefinition<any>, ActionDefinition<any>, ActionDefinition<{}>, ActionDefinition<any>, ActionDefinition<{
|
|
78
86
|
seconds: number;
|
|
79
87
|
}>];
|
|
@@ -28,6 +28,19 @@ export const mouseDoubleClickAction = createAction({
|
|
|
28
28
|
},
|
|
29
29
|
render: ({ x, y }) => `⊙ double click (${x}, ${y})`
|
|
30
30
|
});
|
|
31
|
+
export const mouseHoverAction = createAction({
|
|
32
|
+
name: 'mouse:hover',
|
|
33
|
+
description: "Hover over an element to reveal tooltips, dropdown menus, or hidden content",
|
|
34
|
+
schema: z.object({
|
|
35
|
+
x: z.number().int(),
|
|
36
|
+
y: z.number().int(),
|
|
37
|
+
}),
|
|
38
|
+
resolver: async ({ input: { x, y }, agent }) => {
|
|
39
|
+
const web = agent.require(BrowserConnector);
|
|
40
|
+
await web.getHarness().hover({ x, y });
|
|
41
|
+
},
|
|
42
|
+
render: ({ x, y }) => `◎ hover (${x}, ${y})`
|
|
43
|
+
});
|
|
31
44
|
export const mouseRightClickAction = createAction({
|
|
32
45
|
name: 'mouse:right_click',
|
|
33
46
|
schema: z.object({
|
|
@@ -95,14 +108,23 @@ export const keyboardSelectAllAction = createAction({
|
|
|
95
108
|
},
|
|
96
109
|
render: () => `⬚ select all`
|
|
97
110
|
});
|
|
111
|
+
export const keyboardEscapeAction = createAction({
|
|
112
|
+
name: 'keyboard:escape',
|
|
113
|
+
description: 'Press Escape to dismiss a dismissible dialog, menu, or focused interaction. This does not bypass a subscription or sign-in requirement.',
|
|
114
|
+
schema: z.object({}),
|
|
115
|
+
resolver: async ({ agent }) => {
|
|
116
|
+
await agent.require(BrowserConnector).getHarness().escape();
|
|
117
|
+
},
|
|
118
|
+
render: () => '⎋ press Escape'
|
|
119
|
+
});
|
|
98
120
|
export const scrollCoordAction = createAction({
|
|
99
121
|
name: 'mouse:scroll',
|
|
100
|
-
description: "Hover
|
|
122
|
+
description: "Hover over the area to scroll. Distances are in pixels, not wheel ticks. To browse a full page, use about 500-600 pixels per scroll. Reserve small distances for fine adjustments or small scrollable areas.",
|
|
101
123
|
schema: z.object({
|
|
102
124
|
x: z.number().int(),
|
|
103
125
|
y: z.number().int(),
|
|
104
|
-
deltaX: z.number().int().describe("
|
|
105
|
-
deltaY: z.number().int().describe("
|
|
126
|
+
deltaX: z.number().int().describe("Horizontal distance in pixels: positive scrolls right, negative scrolls left. Use 0 for vertical-only scrolling."),
|
|
127
|
+
deltaY: z.number().int().describe("Vertical distance in pixels: 600 scrolls down, -600 scrolls up. Use about 500-600 to browse a full page; 5 moves only 5 pixels. Use smaller distances for fine adjustments and 0 for horizontal-only scrolling."),
|
|
106
128
|
}),
|
|
107
129
|
resolver: async ({ input: { x, y, deltaX, deltaY }, agent }) => {
|
|
108
130
|
const webConnector = agent.require(BrowserConnector);
|
|
@@ -165,10 +187,10 @@ export const waitAction = createAction({
|
|
|
165
187
|
name: 'wait',
|
|
166
188
|
description: "Actions include smart waiting automatically - so only use this when a significant additional wait is clearly required.",
|
|
167
189
|
schema: z.object({
|
|
168
|
-
seconds: z.number()
|
|
190
|
+
seconds: z.number().finite().nonnegative()
|
|
169
191
|
}),
|
|
170
192
|
resolver: async ({ input: { seconds }, agent }) => {
|
|
171
|
-
await
|
|
193
|
+
await agent.require(BrowserConnector).wait(seconds * 1000);
|
|
172
194
|
},
|
|
173
195
|
render: ({ seconds }) => `◴ wait for ${seconds}s`
|
|
174
196
|
});
|
|
@@ -176,6 +198,7 @@ export const webActions = [
|
|
|
176
198
|
clickCoordAction,
|
|
177
199
|
mouseDoubleClickAction,
|
|
178
200
|
mouseRightClickAction,
|
|
201
|
+
mouseHoverAction,
|
|
179
202
|
scrollCoordAction,
|
|
180
203
|
mouseDragAction,
|
|
181
204
|
newTabAction,
|
|
@@ -185,6 +208,7 @@ export const webActions = [
|
|
|
185
208
|
keyboardEnterAction,
|
|
186
209
|
keyboardTabAction,
|
|
187
210
|
keyboardBackspaceAction,
|
|
211
|
+
keyboardEscapeAction,
|
|
188
212
|
keyboardSelectAllAction,
|
|
189
213
|
waitAction,
|
|
190
214
|
];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { expect, mock, test } from 'bun:test';
|
|
2
|
+
import { zodToJsonSchema } from 'zod-to-json-schema';
|
|
3
|
+
import { keyboardEscapeAction, scrollCoordAction, waitAction, webActions } from './webActions';
|
|
4
|
+
test('Escape is exposed and forwards the Escape command', async () => {
|
|
5
|
+
const escape = mock(async () => { });
|
|
6
|
+
const agent = { require: () => ({ getHarness: () => ({ escape }) }) };
|
|
7
|
+
expect(webActions).toContain(keyboardEscapeAction);
|
|
8
|
+
await keyboardEscapeAction.resolver({ agent, input: {} });
|
|
9
|
+
expect(escape).toHaveBeenCalledTimes(1);
|
|
10
|
+
});
|
|
11
|
+
test('wait validates its duration and uses browser cooldown handling', async () => {
|
|
12
|
+
const wait = mock(async () => { });
|
|
13
|
+
const agent = { require: () => ({ wait }) };
|
|
14
|
+
await waitAction.resolver({ agent, input: { seconds: 2 } });
|
|
15
|
+
expect(wait).toHaveBeenCalledWith(2000);
|
|
16
|
+
expect(waitAction.schema.safeParse({ seconds: -1 }).success).toBe(false);
|
|
17
|
+
expect(waitAction.schema.safeParse({ seconds: Infinity }).success).toBe(false);
|
|
18
|
+
});
|
|
19
|
+
test('scroll scale and precision guidance are included in the action schema', () => {
|
|
20
|
+
const prompt = `${scrollCoordAction.description} ${JSON.stringify(zodToJsonSchema(scrollCoordAction.schema))}`;
|
|
21
|
+
expect(prompt).toContain('not wheel ticks');
|
|
22
|
+
expect(prompt).toContain('500-600');
|
|
23
|
+
expect(prompt).toContain('600 scrolls down, -600 scrolls up');
|
|
24
|
+
expect(prompt).toContain('positive scrolls right, negative scrolls left');
|
|
25
|
+
expect(prompt).toContain('fine adjustments');
|
|
26
|
+
});
|
|
27
|
+
for (const deltas of [
|
|
28
|
+
{ deltaX: 0, deltaY: 5 },
|
|
29
|
+
{ deltaX: 0, deltaY: -5 },
|
|
30
|
+
{ deltaX: 0, deltaY: 600 },
|
|
31
|
+
{ deltaX: 0, deltaY: -600 },
|
|
32
|
+
{ deltaX: 600, deltaY: 0 },
|
|
33
|
+
{ deltaX: -5, deltaY: 0 },
|
|
34
|
+
]) {
|
|
35
|
+
test(`scroll forwards pixel distances unchanged: ${deltas.deltaX}, ${deltas.deltaY}`, async () => {
|
|
36
|
+
const scroll = mock(async () => { });
|
|
37
|
+
const agent = { require: () => ({ getHarness: () => ({ scroll }) }) };
|
|
38
|
+
const input = scrollCoordAction.schema.parse({ x: 120, y: 250, ...deltas });
|
|
39
|
+
await scrollCoordAction.resolver({ agent, input });
|
|
40
|
+
expect(scroll).toHaveBeenCalledTimes(1);
|
|
41
|
+
expect(scroll).toHaveBeenCalledWith({ x: 120, y: 250, ...deltas });
|
|
42
|
+
});
|
|
43
|
+
}
|
|
@@ -4,6 +4,7 @@ import { BrowserConnectorOptions } from "@/connectors/browserConnector";
|
|
|
4
4
|
import { Schema, ZodSchema } from "zod";
|
|
5
5
|
import z from "zod";
|
|
6
6
|
import EventEmitter from "eventemitter3";
|
|
7
|
+
import { type OperationOptions } from '@/common/operation';
|
|
7
8
|
export declare function startBrowserAgent(options?: AgentOptions & BrowserConnectorOptions & {
|
|
8
9
|
narrate?: boolean;
|
|
9
10
|
}): Promise<BrowserAgent>;
|
|
@@ -23,7 +24,8 @@ export declare class BrowserAgent extends Agent {
|
|
|
23
24
|
});
|
|
24
25
|
get page(): Page;
|
|
25
26
|
get context(): BrowserContext;
|
|
26
|
-
nav(url: string): Promise<void>;
|
|
27
|
-
extract<T extends Schema>(instructions: string, schema: T): Promise<z.infer<T>>;
|
|
27
|
+
nav(url: string, options?: OperationOptions): Promise<void>;
|
|
28
|
+
extract<T extends Schema>(instructions: string, schema: T, options?: OperationOptions): Promise<z.infer<T>>;
|
|
29
|
+
private _extract;
|
|
28
30
|
}
|
|
29
31
|
export {};
|
|
@@ -5,6 +5,7 @@ import { narrateBrowserAgent } from "./narrator";
|
|
|
5
5
|
import { partitionHtml, serializeToMarkdown } from 'magnitude-extract';
|
|
6
6
|
import EventEmitter from "eventemitter3";
|
|
7
7
|
import { retry } from "@/common/retry";
|
|
8
|
+
import { checkOperation } from '@/common/operation';
|
|
8
9
|
// export interface StartAgentWithWebOptions {
|
|
9
10
|
// agentBaseOptions?: Partial<AgentOptions>;
|
|
10
11
|
// webConnectorOptions?: BrowserConnectorOptions;
|
|
@@ -29,15 +30,19 @@ export async function startBrowserAgent(options //StartAgentWithWebOptions = {}
|
|
|
29
30
|
return agent;
|
|
30
31
|
}
|
|
31
32
|
async function getFullPageContent(page) {
|
|
33
|
+
checkOperation();
|
|
32
34
|
// 1. Get all iframe element handles
|
|
33
35
|
const iframeHandles = await page.locator('iframe').elementHandles();
|
|
34
36
|
// 2. Iterate through each iframe handle
|
|
35
37
|
for (const iframeHandle of iframeHandles) {
|
|
38
|
+
checkOperation();
|
|
36
39
|
// 3. Get the Frame object for the iframe
|
|
37
40
|
const frame = await iframeHandle.contentFrame();
|
|
41
|
+
checkOperation();
|
|
38
42
|
if (frame) {
|
|
39
43
|
// 4. Get the HTML content of the iframe
|
|
40
44
|
const iframeContent = await frame.content();
|
|
45
|
+
checkOperation();
|
|
41
46
|
// 5. Use evaluate to replace the iframe element with its content.
|
|
42
47
|
// We pass the content as an argument to avoid issues with string escaping.
|
|
43
48
|
await iframeHandle.evaluate((iframeNode, { content }) => {
|
|
@@ -62,6 +67,7 @@ async function getFullPageContent(page) {
|
|
|
62
67
|
}
|
|
63
68
|
}
|
|
64
69
|
// 6. Return the final, modified page content
|
|
70
|
+
checkOperation();
|
|
65
71
|
return page.content();
|
|
66
72
|
}
|
|
67
73
|
export class BrowserAgent extends Agent {
|
|
@@ -80,11 +86,17 @@ export class BrowserAgent extends Agent {
|
|
|
80
86
|
get context() {
|
|
81
87
|
return this.require(BrowserConnector).getHarness().context;
|
|
82
88
|
}
|
|
83
|
-
async nav(url) {
|
|
84
|
-
this.
|
|
85
|
-
|
|
89
|
+
async nav(url, options = {}) {
|
|
90
|
+
return this.runOperation(options, async () => {
|
|
91
|
+
this.browserAgentEvents.emit('nav', url);
|
|
92
|
+
checkOperation();
|
|
93
|
+
await this.require(BrowserConnector).getHarness().navigate(url);
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
async extract(instructions, schema, options = {}) {
|
|
97
|
+
return this.runOperation(options, () => this._extract(instructions, schema));
|
|
86
98
|
}
|
|
87
|
-
async
|
|
99
|
+
async _extract(instructions, schema) {
|
|
88
100
|
this.browserAgentEvents.emit('extractStarted', instructions, schema);
|
|
89
101
|
//const htmlContent = await this.page.content();
|
|
90
102
|
const htmlContent = await retry(async () => await getFullPageContent(this.page), { retries: 5, delay: 200, exponential: true });
|
|
@@ -115,7 +127,9 @@ export class BrowserAgent extends Agent {
|
|
|
115
127
|
// Convert to markdown
|
|
116
128
|
const markdown = serializeToMarkdown(result, markdownOptions);
|
|
117
129
|
const screenshot = await this.require(BrowserConnector).getHarness().screenshot();
|
|
130
|
+
checkOperation();
|
|
118
131
|
const data = await this.models.extract(instructions, schema, screenshot, markdown);
|
|
132
|
+
checkOperation();
|
|
119
133
|
this.browserAgentEvents.emit('extractDone', instructions, data);
|
|
120
134
|
return data;
|
|
121
135
|
}
|
package/dist/agent/errors.d.ts
CHANGED
|
@@ -6,3 +6,17 @@ export declare class AgentError extends Error {
|
|
|
6
6
|
readonly options: Required<AgentErrorOptions>;
|
|
7
7
|
constructor(message: string, options?: AgentErrorOptions);
|
|
8
8
|
}
|
|
9
|
+
export declare class ActionLimitError extends AgentError {
|
|
10
|
+
readonly limit: number;
|
|
11
|
+
constructor(limit: number);
|
|
12
|
+
}
|
|
13
|
+
export declare class OperationCancelledError extends AgentError {
|
|
14
|
+
constructor(reason?: unknown);
|
|
15
|
+
}
|
|
16
|
+
export declare class OperationDeadlineError extends AgentError {
|
|
17
|
+
readonly deadline: number;
|
|
18
|
+
constructor(deadline: number);
|
|
19
|
+
}
|
|
20
|
+
export declare class AgentBusyError extends AgentError {
|
|
21
|
+
constructor();
|
|
22
|
+
}
|
package/dist/agent/errors.js
CHANGED
|
@@ -26,6 +26,35 @@ export class AgentError extends Error {
|
|
|
26
26
|
//this.failure = failure;
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
|
+
export class ActionLimitError extends AgentError {
|
|
30
|
+
limit;
|
|
31
|
+
constructor(limit) {
|
|
32
|
+
super(`Task did not finish within ${limit} actions`, { variant: 'action_limit' });
|
|
33
|
+
this.limit = limit;
|
|
34
|
+
this.name = 'ActionLimitError';
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
export class OperationCancelledError extends AgentError {
|
|
38
|
+
constructor(reason) {
|
|
39
|
+
super('Operation cancelled', { variant: 'cancelled' });
|
|
40
|
+
this.name = 'OperationCancelledError';
|
|
41
|
+
this.cause = reason;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
export class OperationDeadlineError extends AgentError {
|
|
45
|
+
deadline;
|
|
46
|
+
constructor(deadline) {
|
|
47
|
+
super('Operation deadline exceeded', { variant: 'deadline' });
|
|
48
|
+
this.deadline = deadline;
|
|
49
|
+
this.name = 'OperationDeadlineError';
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
export class AgentBusyError extends AgentError {
|
|
53
|
+
constructor() {
|
|
54
|
+
super('Agent has an active operation; await whenIdle() before reusing it', { variant: 'busy' });
|
|
55
|
+
this.name = 'AgentBusyError';
|
|
56
|
+
}
|
|
57
|
+
}
|
|
29
58
|
// // Agent will only throw these types of errors
|
|
30
59
|
// import { ActionIngredient } from "./recipe/types";
|
|
31
60
|
// import { WebAction } from "./web/types";
|
package/dist/agent/index.d.ts
CHANGED
|
@@ -5,7 +5,8 @@ import { AgentEvents } from "@/common/events";
|
|
|
5
5
|
import { AgentConnector } from '@/connectors';
|
|
6
6
|
import { RenderableContent } from '@/memory/observation';
|
|
7
7
|
import { LLMClient } from "@/ai/types";
|
|
8
|
-
import {
|
|
8
|
+
import { type OperationOptions } from '@/common/operation';
|
|
9
|
+
import { AgentMemory, MemoryRenderOptions } from "@/memory";
|
|
9
10
|
import { ActionDefinition } from "@/actions";
|
|
10
11
|
import { MultiModelHarness } from '@/ai/multiModelHarness';
|
|
11
12
|
export interface AgentOptions {
|
|
@@ -14,8 +15,9 @@ export interface AgentOptions {
|
|
|
14
15
|
actions?: ActionDefinition<any>[];
|
|
15
16
|
prompt?: string | null;
|
|
16
17
|
telemetry?: boolean;
|
|
18
|
+
maxActions?: number;
|
|
17
19
|
}
|
|
18
|
-
export interface ActOptions {
|
|
20
|
+
export interface ActOptions extends OperationOptions {
|
|
19
21
|
prompt?: string;
|
|
20
22
|
data?: RenderableContent;
|
|
21
23
|
memory?: AgentMemory;
|
|
@@ -30,20 +32,29 @@ export declare class Agent {
|
|
|
30
32
|
private doneActing;
|
|
31
33
|
private _paused;
|
|
32
34
|
private _pauseResolve;
|
|
35
|
+
private activeOperation?;
|
|
36
|
+
private idle;
|
|
37
|
+
private stopped;
|
|
33
38
|
protected latestTaskMemory: AgentMemory;
|
|
34
39
|
constructor(baseConfig?: Partial<AgentOptions>);
|
|
35
40
|
getConnector<C extends AgentConnector>(connectorClass: new (...args: any[]) => C): C | undefined;
|
|
36
41
|
require<C extends AgentConnector>(connectorClass: new (...args: any[]) => C): C;
|
|
37
42
|
start(): Promise<void>;
|
|
38
43
|
identifyAction(action: Action): ActionDefinition<any>;
|
|
39
|
-
|
|
44
|
+
/** True until underlying work settles, including after a cancelled caller returns. */
|
|
45
|
+
get busy(): boolean;
|
|
46
|
+
whenIdle(): Promise<void>;
|
|
47
|
+
protected runOperation<T>(options: OperationOptions, fn: () => Promise<T>): Promise<T>;
|
|
48
|
+
exec(action: Action, memory?: AgentMemory, options?: OperationOptions): Promise<unknown>;
|
|
49
|
+
private _exec;
|
|
40
50
|
protected _recordConnectorObservations(memory: AgentMemory): Promise<void>;
|
|
41
51
|
get memory(): AgentMemory;
|
|
42
52
|
act(taskOrSteps: string | string[], options?: ActOptions): Promise<void>;
|
|
43
|
-
|
|
53
|
+
private _runAct;
|
|
54
|
+
private _traceAct;
|
|
44
55
|
private _buildContext;
|
|
45
|
-
_act
|
|
46
|
-
query<T extends z.Schema>(query: string, schema: T): Promise<z.infer<T>>;
|
|
56
|
+
private _act;
|
|
57
|
+
query<T extends z.Schema>(query: string, schema: T, options?: MemoryRenderOptions & OperationOptions): Promise<z.infer<T>>;
|
|
47
58
|
queueDone(): Promise<void>;
|
|
48
59
|
private _waitIfPaused;
|
|
49
60
|
pause(): void;
|