donobu 5.55.0 → 5.57.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/apis/GptConfigsApi.d.ts +5 -5
- package/dist/apis/GptConfigsApi.js +14 -14
- package/dist/bindings/PageInteractionTracker.d.ts +1 -1
- package/dist/bindings/PageInteractionTracker.js +3 -3
- package/dist/bindings/SetDonobuAnnotations.d.ts +1 -1
- package/dist/bindings/SetDonobuAnnotations.js +3 -3
- package/dist/clients/AnthropicGptClient.d.ts +2 -2
- package/dist/clients/AnthropicGptClient.js +77 -77
- package/dist/clients/OpenAiGptClient.d.ts +14 -14
- package/dist/clients/OpenAiGptClient.js +183 -183
- package/dist/esm/apis/GptConfigsApi.d.ts +5 -5
- package/dist/esm/apis/GptConfigsApi.js +14 -14
- package/dist/esm/bindings/PageInteractionTracker.d.ts +1 -1
- package/dist/esm/bindings/PageInteractionTracker.js +3 -3
- package/dist/esm/bindings/SetDonobuAnnotations.d.ts +1 -1
- package/dist/esm/bindings/SetDonobuAnnotations.js +3 -3
- package/dist/esm/clients/AnthropicGptClient.d.ts +2 -2
- package/dist/esm/clients/AnthropicGptClient.js +77 -77
- package/dist/esm/clients/OpenAiGptClient.d.ts +14 -14
- package/dist/esm/clients/OpenAiGptClient.js +183 -183
- package/dist/esm/lib/ai/PageAi.js +2 -1
- package/dist/esm/lib/page/extendPage.js +2 -1
- package/dist/esm/lib/test/utils/TestFileUpdater.d.ts +9 -9
- package/dist/esm/lib/test/utils/TestFileUpdater.js +49 -49
- package/dist/esm/main.d.ts +2 -0
- package/dist/esm/managers/AdminApiController.d.ts +16 -16
- package/dist/esm/managers/AdminApiController.js +35 -35
- package/dist/esm/managers/DonobuFlow.d.ts +57 -36
- package/dist/esm/managers/DonobuFlow.js +489 -564
- package/dist/esm/managers/DonobuFlowsManager.js +13 -17
- package/dist/esm/managers/FlowDependencyAnalyzer.d.ts +12 -12
- package/dist/esm/managers/FlowDependencyAnalyzer.js +77 -77
- package/dist/esm/managers/PageInspector.d.ts +38 -38
- package/dist/esm/managers/PageInspector.js +745 -745
- package/dist/esm/managers/TargetInspector.d.ts +28 -33
- package/dist/esm/managers/TestsManager.d.ts +25 -25
- package/dist/esm/managers/TestsManager.js +74 -74
- package/dist/esm/managers/ToolManager.js +7 -5
- package/dist/esm/managers/ToolRegistry.d.ts +5 -1
- package/dist/esm/managers/WebTargetInspector.d.ts +9 -5
- package/dist/esm/managers/WebTargetInspector.js +45 -47
- package/dist/esm/models/AiQuery.d.ts +29 -15
- package/dist/esm/models/AiQuery.js +31 -0
- package/dist/esm/models/ControlPanel.d.ts +18 -13
- package/dist/esm/models/InteractableElement.d.ts +6 -0
- package/dist/esm/models/InteractableElement.js +7 -1
- package/dist/esm/models/Observation.d.ts +38 -0
- package/dist/esm/models/Observation.js +3 -0
- package/dist/esm/models/ToolCallContext.d.ts +3 -2
- package/dist/esm/persistence/flows/FlowsPersistenceDonobuApi.d.ts +2 -2
- package/dist/esm/persistence/flows/FlowsPersistenceDonobuApi.js +19 -18
- package/dist/esm/persistence/flows/FlowsPersistenceSqlite.js +2 -1
- package/dist/esm/targets/TargetProvider.d.ts +110 -0
- package/dist/esm/targets/TargetProvider.js +25 -0
- package/dist/esm/targets/TargetRuntime.d.ts +6 -3
- package/dist/esm/targets/WebDialogHandler.d.ts +14 -0
- package/dist/esm/targets/WebDialogHandler.js +198 -0
- package/dist/esm/targets/WebTargetProvider.d.ts +32 -0
- package/dist/esm/targets/WebTargetProvider.js +136 -0
- package/dist/esm/targets/WebTargetRuntime.d.ts +2 -2
- package/dist/esm/targets/WebTargetRuntime.js +2 -1
- package/dist/esm/tools/AcknowledgeUserInstruction.d.ts +6 -0
- package/dist/esm/tools/AcknowledgeUserInstruction.js +7 -0
- package/dist/esm/tools/AssertPageTool.d.ts +1 -1
- package/dist/esm/tools/AssertPageTool.js +3 -3
- package/dist/esm/tools/DetectBrokenLinksTool.d.ts +2 -2
- package/dist/esm/tools/DetectBrokenLinksTool.js +44 -44
- package/dist/esm/tools/InputFakerTool.d.ts +4 -4
- package/dist/esm/tools/InputFakerTool.js +10 -10
- package/dist/esm/tools/InputTextTool.d.ts +4 -4
- package/dist/esm/tools/InputTextTool.js +7 -7
- package/dist/esm/tools/ReplayableInteraction.d.ts +34 -34
- package/dist/esm/tools/ReplayableInteraction.js +245 -245
- package/dist/esm/tools/Tool.d.ts +6 -3
- package/dist/esm/tools/Tool.js +5 -2
- package/dist/esm/utils/BrowserUtils.d.ts +19 -19
- package/dist/esm/utils/BrowserUtils.js +57 -57
- package/dist/esm/utils/MiscUtils.d.ts +2 -2
- package/dist/esm/utils/MiscUtils.js +16 -16
- package/dist/esm/utils/PlaywrightUtils.d.ts +1 -1
- package/dist/esm/utils/TargetUtils.d.ts +1 -1
- package/dist/esm/utils/TargetUtils.js +15 -13
- package/dist/lib/ai/PageAi.js +2 -1
- package/dist/lib/page/extendPage.js +2 -1
- package/dist/lib/test/utils/TestFileUpdater.d.ts +9 -9
- package/dist/lib/test/utils/TestFileUpdater.js +49 -49
- package/dist/main.d.ts +2 -0
- package/dist/managers/AdminApiController.d.ts +16 -16
- package/dist/managers/AdminApiController.js +35 -35
- package/dist/managers/DonobuFlow.d.ts +57 -36
- package/dist/managers/DonobuFlow.js +489 -564
- package/dist/managers/DonobuFlowsManager.js +13 -17
- package/dist/managers/FlowDependencyAnalyzer.d.ts +12 -12
- package/dist/managers/FlowDependencyAnalyzer.js +77 -77
- package/dist/managers/PageInspector.d.ts +38 -38
- package/dist/managers/PageInspector.js +745 -745
- package/dist/managers/TargetInspector.d.ts +28 -33
- package/dist/managers/TestsManager.d.ts +25 -25
- package/dist/managers/TestsManager.js +74 -74
- package/dist/managers/ToolManager.js +7 -5
- package/dist/managers/ToolRegistry.d.ts +5 -1
- package/dist/managers/WebTargetInspector.d.ts +9 -5
- package/dist/managers/WebTargetInspector.js +45 -47
- package/dist/models/AiQuery.d.ts +29 -15
- package/dist/models/AiQuery.js +31 -0
- package/dist/models/ControlPanel.d.ts +18 -13
- package/dist/models/InteractableElement.d.ts +6 -0
- package/dist/models/InteractableElement.js +7 -1
- package/dist/models/Observation.d.ts +38 -0
- package/dist/models/Observation.js +3 -0
- package/dist/models/ToolCallContext.d.ts +3 -2
- package/dist/persistence/flows/FlowsPersistenceDonobuApi.d.ts +2 -2
- package/dist/persistence/flows/FlowsPersistenceDonobuApi.js +19 -18
- package/dist/persistence/flows/FlowsPersistenceSqlite.js +2 -1
- package/dist/targets/TargetProvider.d.ts +110 -0
- package/dist/targets/TargetProvider.js +25 -0
- package/dist/targets/TargetRuntime.d.ts +6 -3
- package/dist/targets/WebDialogHandler.d.ts +14 -0
- package/dist/targets/WebDialogHandler.js +198 -0
- package/dist/targets/WebTargetProvider.d.ts +32 -0
- package/dist/targets/WebTargetProvider.js +136 -0
- package/dist/targets/WebTargetRuntime.d.ts +2 -2
- package/dist/targets/WebTargetRuntime.js +2 -1
- package/dist/tools/AcknowledgeUserInstruction.d.ts +6 -0
- package/dist/tools/AcknowledgeUserInstruction.js +7 -0
- package/dist/tools/AssertPageTool.d.ts +1 -1
- package/dist/tools/AssertPageTool.js +3 -3
- package/dist/tools/DetectBrokenLinksTool.d.ts +2 -2
- package/dist/tools/DetectBrokenLinksTool.js +44 -44
- package/dist/tools/InputFakerTool.d.ts +4 -4
- package/dist/tools/InputFakerTool.js +10 -10
- package/dist/tools/InputTextTool.d.ts +4 -4
- package/dist/tools/InputTextTool.js +7 -7
- package/dist/tools/ReplayableInteraction.d.ts +34 -34
- package/dist/tools/ReplayableInteraction.js +245 -245
- package/dist/tools/Tool.d.ts +6 -3
- package/dist/tools/Tool.js +5 -2
- package/dist/utils/BrowserUtils.d.ts +19 -19
- package/dist/utils/BrowserUtils.js +57 -57
- package/dist/utils/MiscUtils.d.ts +2 -2
- package/dist/utils/MiscUtils.js +16 -16
- package/dist/utils/PlaywrightUtils.d.ts +1 -1
- package/dist/utils/TargetUtils.d.ts +1 -1
- package/dist/utils/TargetUtils.js +15 -13
- package/package.json +2 -1
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { InteractableElement } from './InteractableElement';
|
|
2
|
+
import type { ObservationRecord } from './Observation';
|
|
2
3
|
/**
|
|
3
4
|
* Represents a single AI decision cycle within a flow. Created at the start of
|
|
4
|
-
* a query cycle with just `id` and `
|
|
5
|
-
*
|
|
5
|
+
* a query cycle with just `id` and `startedAt`, then progressively filled in as
|
|
6
|
+
* the attached providers produce their observations. The `error` field is
|
|
6
7
|
* populated only if the query fails.
|
|
7
8
|
*/
|
|
8
9
|
export type AiQuery = {
|
|
@@ -11,20 +12,10 @@ export type AiQuery = {
|
|
|
11
12
|
*/
|
|
12
13
|
readonly id: string;
|
|
13
14
|
/**
|
|
14
|
-
*
|
|
15
|
-
*
|
|
15
|
+
* What each observing provider (0..N) perceived this cycle — the screenshots
|
|
16
|
+
* and elements the AI saw when it made its decision. One record per provider.
|
|
16
17
|
*/
|
|
17
|
-
readonly
|
|
18
|
-
/**
|
|
19
|
-
* The ID of the annotated screenshot (with numbered element badges) sent to the AI.
|
|
20
|
-
* Null until the screenshot is captured.
|
|
21
|
-
*/
|
|
22
|
-
readonly annotatedScreenshotId: string | null;
|
|
23
|
-
/**
|
|
24
|
-
* The interactable elements that were identified and sent to the AI.
|
|
25
|
-
* Null until element discovery completes.
|
|
26
|
-
*/
|
|
27
|
-
readonly interactableElements: InteractableElement[] | null;
|
|
18
|
+
readonly observations: ObservationRecord[];
|
|
28
19
|
/**
|
|
29
20
|
* If the AI query failed, the error message. Null on success.
|
|
30
21
|
*/
|
|
@@ -39,4 +30,27 @@ export type AiQuery = {
|
|
|
39
30
|
*/
|
|
40
31
|
readonly completedAt: number | null;
|
|
41
32
|
};
|
|
33
|
+
/**
|
|
34
|
+
* The raw shape a persisted query may take when read back from storage. Flows
|
|
35
|
+
* persisted before the observations refactor stored the web screenshot/element
|
|
36
|
+
* data flat on the query and have no `observations` array. Read paths normalize
|
|
37
|
+
* these into a canonical {@link AiQuery} via {@link normalizeAiQuery}, so the
|
|
38
|
+
* rest of the system (and the API) only ever sees the `observations` shape.
|
|
39
|
+
*/
|
|
40
|
+
export type PersistedAiQuery = Omit<AiQuery, 'observations'> & {
|
|
41
|
+
readonly observations?: ObservationRecord[];
|
|
42
|
+
/** @deprecated Legacy pre-`observations` field. */
|
|
43
|
+
readonly cleanScreenshotId?: string | null;
|
|
44
|
+
/** @deprecated Legacy pre-`observations` field. */
|
|
45
|
+
readonly annotatedScreenshotId?: string | null;
|
|
46
|
+
/** @deprecated Legacy pre-`observations` field. */
|
|
47
|
+
readonly interactableElements?: InteractableElement[] | null;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Lift a persisted query into the canonical `observations` shape. Idempotent:
|
|
51
|
+
* queries that already carry `observations` are returned (re-wrapped to drop
|
|
52
|
+
* any legacy fields). Legacy queries — which always carried the web
|
|
53
|
+
* screenshot/element slots — become a single {@link WebObservationRecord}.
|
|
54
|
+
*/
|
|
55
|
+
export declare function normalizeAiQuery(query: PersistedAiQuery): AiQuery;
|
|
42
56
|
//# sourceMappingURL=AiQuery.d.ts.map
|
|
@@ -1,3 +1,34 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.normalizeAiQuery = normalizeAiQuery;
|
|
4
|
+
/**
|
|
5
|
+
* Lift a persisted query into the canonical `observations` shape. Idempotent:
|
|
6
|
+
* queries that already carry `observations` are returned (re-wrapped to drop
|
|
7
|
+
* any legacy fields). Legacy queries — which always carried the web
|
|
8
|
+
* screenshot/element slots — become a single {@link WebObservationRecord}.
|
|
9
|
+
*/
|
|
10
|
+
function normalizeAiQuery(query) {
|
|
11
|
+
const base = {
|
|
12
|
+
id: query.id,
|
|
13
|
+
error: query.error,
|
|
14
|
+
startedAt: query.startedAt,
|
|
15
|
+
completedAt: query.completedAt,
|
|
16
|
+
};
|
|
17
|
+
if (query.observations) {
|
|
18
|
+
return { ...base, observations: query.observations };
|
|
19
|
+
}
|
|
20
|
+
const hasLegacyWebSlots = query.cleanScreenshotId !== undefined ||
|
|
21
|
+
query.annotatedScreenshotId !== undefined ||
|
|
22
|
+
query.interactableElements !== undefined;
|
|
23
|
+
if (!hasLegacyWebSlots) {
|
|
24
|
+
return { ...base, observations: [] };
|
|
25
|
+
}
|
|
26
|
+
const record = {
|
|
27
|
+
type: 'web',
|
|
28
|
+
cleanScreenshotId: query.cleanScreenshotId ?? null,
|
|
29
|
+
annotatedScreenshotId: query.annotatedScreenshotId ?? null,
|
|
30
|
+
interactableElements: query.interactableElements ?? null,
|
|
31
|
+
};
|
|
32
|
+
return { ...base, observations: [record] };
|
|
33
|
+
}
|
|
3
34
|
//# sourceMappingURL=AiQuery.js.map
|
|
@@ -21,24 +21,29 @@ export type UserAction = {
|
|
|
21
21
|
type: 'SET_RUN_MODE';
|
|
22
22
|
runMode: RunMode;
|
|
23
23
|
approvePending?: boolean;
|
|
24
|
+
} | {
|
|
25
|
+
type: 'STEP';
|
|
26
|
+
instruction?: string;
|
|
27
|
+
} | {
|
|
28
|
+
type: 'RUN';
|
|
29
|
+
instruction?: string;
|
|
24
30
|
};
|
|
25
31
|
export type ControlPanelDataUpdate = {
|
|
26
32
|
state: State;
|
|
33
|
+
runMode?: RunMode;
|
|
34
|
+
/** The flow's overall objective; the panel treats a non-empty value (or a
|
|
35
|
+
* typed instruction) as a "goal", which gates ⏩ Fast-forward and ▶ Play. */
|
|
36
|
+
overallObjective?: string | null;
|
|
37
|
+
/** The tools the flow can actually run (resolved from the ToolManager). */
|
|
38
|
+
allowedTools?: string[] | null;
|
|
27
39
|
headline?: string;
|
|
28
|
-
/**
|
|
29
|
-
* the control panel can offer only tools the flow can actually run. */
|
|
30
|
-
availableToolNames?: string[];
|
|
31
|
-
/** In SUPERVISED mode, the AI-proposed tool call(s) currently awaiting the
|
|
32
|
-
* user's approval. Surfaced to the UI so the user can see what they are
|
|
33
|
-
* approving or rejecting. Empty/undefined when nothing is pending. */
|
|
40
|
+
/** AI-proposed tool call(s) awaiting approval (SUPERVISED). */
|
|
34
41
|
pendingToolCalls?: ProposedToolCall[];
|
|
35
|
-
/**
|
|
36
|
-
*
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
* those options on the autonomy selector. */
|
|
41
|
-
canUseAi?: boolean;
|
|
42
|
+
/** Whether the flow has a GPT client (AI available at all). Not cleanly a
|
|
43
|
+
* FlowMetadata field — a client can come from env/default config, not just a
|
|
44
|
+
* named gptConfig — so it's surfaced explicitly. Drives whether the compose
|
|
45
|
+
* surface and the ▶/⏩ transport are offered at all. */
|
|
46
|
+
hasGptClient?: boolean;
|
|
42
47
|
};
|
|
43
48
|
export interface ControlPanel {
|
|
44
49
|
/** Cheap, idempotent render update. */
|
|
@@ -19,5 +19,11 @@ export declare const InteractableElementSchema: z.ZodObject<{
|
|
|
19
19
|
}>>;
|
|
20
20
|
}, z.core.$strip>;
|
|
21
21
|
export type InteractableElement = z.infer<typeof InteractableElementSchema>;
|
|
22
|
+
/**
|
|
23
|
+
* Marker line preceding the JSON element list in a perception user message.
|
|
24
|
+
* The history optimizer locates it to trim the element list from stale turns,
|
|
25
|
+
* so the producer (web observer) and consumer (history optimizer) share it.
|
|
26
|
+
*/
|
|
27
|
+
export declare const INTERACTABLE_ELEMENTS_MESSAGE_MARKER = "JSON mapping of annotation to interactable element...";
|
|
22
28
|
export declare function interactableElementsToPrettyJson(elements: InteractableElement[]): string;
|
|
23
29
|
//# sourceMappingURL=InteractableElement.d.ts.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.InteractableElementSchema = exports.ScrollDirectionEnum = void 0;
|
|
3
|
+
exports.INTERACTABLE_ELEMENTS_MESSAGE_MARKER = exports.InteractableElementSchema = exports.ScrollDirectionEnum = void 0;
|
|
4
4
|
exports.interactableElementsToPrettyJson = interactableElementsToPrettyJson;
|
|
5
5
|
const v4_1 = require("zod/v4");
|
|
6
6
|
exports.ScrollDirectionEnum = v4_1.z.enum(['UP', 'DOWN', 'LEFT', 'RIGHT']);
|
|
@@ -14,6 +14,12 @@ exports.InteractableElementSchema = v4_1.z.object({
|
|
|
14
14
|
htmlSnippet: v4_1.z.string().describe('A short HTML snippet of the element.'),
|
|
15
15
|
scrollable: exports.ScrollDirectionEnum.array().describe('Live scroll directions available on the element (empty = no scrolling possible).'),
|
|
16
16
|
});
|
|
17
|
+
/**
|
|
18
|
+
* Marker line preceding the JSON element list in a perception user message.
|
|
19
|
+
* The history optimizer locates it to trim the element list from stale turns,
|
|
20
|
+
* so the producer (web observer) and consumer (history optimizer) share it.
|
|
21
|
+
*/
|
|
22
|
+
exports.INTERACTABLE_ELEMENTS_MESSAGE_MARKER = 'JSON mapping of annotation to interactable element...';
|
|
17
23
|
function interactableElementsToPrettyJson(elements) {
|
|
18
24
|
// Create an object maintaining insertion order.
|
|
19
25
|
const result = {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { UserMessageItem } from './GptMessage';
|
|
2
|
+
import type { InteractableElement } from './InteractableElement';
|
|
3
|
+
/**
|
|
4
|
+
* The persisted record of what one provider observed in a turn. Open by design
|
|
5
|
+
* — it carries only a `type` discriminant so each target (including plugin
|
|
6
|
+
* targets) can define its own record shape. Read more by narrowing on `type`.
|
|
7
|
+
*/
|
|
8
|
+
export interface ObservationRecord {
|
|
9
|
+
readonly type: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Observation record for targets perceived as screenshots (e.g. web, mobile).
|
|
13
|
+
* Narrow an {@link ObservationRecord} to this shape (e.g. via
|
|
14
|
+
* `'cleanScreenshotId' in record`) to render its screenshots and elements.
|
|
15
|
+
*/
|
|
16
|
+
export interface ScreenshotObservationRecord extends ObservationRecord {
|
|
17
|
+
readonly cleanScreenshotId: string | null;
|
|
18
|
+
readonly annotatedScreenshotId: string | null;
|
|
19
|
+
readonly interactableElements: InteractableElement[] | null;
|
|
20
|
+
}
|
|
21
|
+
/** The web target's per-turn observation record. */
|
|
22
|
+
export interface WebObservationRecord extends ScreenshotObservationRecord {
|
|
23
|
+
readonly type: 'web';
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* A single observing provider's contribution to one AI decision cycle.
|
|
27
|
+
*
|
|
28
|
+
* - {@link llmContent} is injected verbatim into the turn's user message (for
|
|
29
|
+
* web: the clean screenshot, the annotated screenshot, then the element-list
|
|
30
|
+
* text — in that order).
|
|
31
|
+
* - {@link record} is the provider-specific payload persisted on the
|
|
32
|
+
* {@link AiQuery} for later display/debugging.
|
|
33
|
+
*/
|
|
34
|
+
export type Observation = {
|
|
35
|
+
readonly llmContent: UserMessageItem[];
|
|
36
|
+
readonly record: ObservationRecord;
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=Observation.d.ts.map
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { GptClient } from '../clients/GptClient';
|
|
2
2
|
import type { DonobuFlowsManager } from '../managers/DonobuFlowsManager';
|
|
3
3
|
import type { InteractionVisualizer } from '../managers/InteractionVisualizer';
|
|
4
|
-
import type { TargetInspector } from '../managers/TargetInspector';
|
|
5
4
|
import type { ControlPanel } from '../models/ControlPanel';
|
|
6
5
|
import type { FlowsPersistence } from '../persistence/flows/FlowsPersistence';
|
|
6
|
+
import type { TargetProvider } from '../targets/TargetProvider';
|
|
7
7
|
import type { FlowMetadata } from './FlowMetadata';
|
|
8
8
|
import type { ProposedToolCall } from './ProposedToolCall';
|
|
9
9
|
import type { ToolCall } from './ToolCall';
|
|
@@ -13,7 +13,8 @@ import type { ToolCall } from './ToolCall';
|
|
|
13
13
|
export type ToolCallContext = {
|
|
14
14
|
readonly flowsManager: DonobuFlowsManager;
|
|
15
15
|
readonly envData: Record<string, string>;
|
|
16
|
-
|
|
16
|
+
/** The target the tool can act on, or `null` for a targetless flow. */
|
|
17
|
+
readonly provider: TargetProvider | null;
|
|
17
18
|
readonly controlPanel: ControlPanel;
|
|
18
19
|
readonly persistence: FlowsPersistence;
|
|
19
20
|
readonly gptClient: GptClient | null;
|
|
@@ -39,8 +39,6 @@ export declare class FlowsPersistenceDonobuApi implements FlowsPersistence {
|
|
|
39
39
|
* polls instead.
|
|
40
40
|
*/
|
|
41
41
|
constructor(baseUrl: string, apiKey: string, fileCache: FileUploadCache, notifyUpload?: () => void);
|
|
42
|
-
private request;
|
|
43
|
-
private jsonRequest;
|
|
44
42
|
setFlowMetadata(flowMetadata: FlowMetadata): Promise<void>;
|
|
45
43
|
getFlowMetadataById(flowId: string): Promise<FlowMetadata>;
|
|
46
44
|
getFlowMetadataByName(flowName: string): Promise<FlowMetadata>;
|
|
@@ -72,6 +70,8 @@ export declare class FlowsPersistenceDonobuApi implements FlowsPersistence {
|
|
|
72
70
|
setFlowFile(flowId: string, fileId: string, fileBytes: Buffer): Promise<void>;
|
|
73
71
|
setBrowserState(flowId: string, browserState: BrowserStorageState): Promise<void>;
|
|
74
72
|
getBrowserState(flowId: string): Promise<BrowserStorageState | null>;
|
|
73
|
+
private request;
|
|
74
|
+
private jsonRequest;
|
|
75
75
|
}
|
|
76
76
|
export interface CreateDonobuFlowsPersistenceOptions {
|
|
77
77
|
readonly baseUrl: string;
|
|
@@ -8,6 +8,7 @@ exports.createDonobuFlowsPersistence = createDonobuFlowsPersistence;
|
|
|
8
8
|
exports.startDonobuParentUploader = startDonobuParentUploader;
|
|
9
9
|
const path_1 = __importDefault(require("path"));
|
|
10
10
|
const FlowNotFoundException_1 = require("../../exceptions/FlowNotFoundException");
|
|
11
|
+
const AiQuery_1 = require("../../models/AiQuery");
|
|
11
12
|
const BrowserStorageState_1 = require("../../models/BrowserStorageState");
|
|
12
13
|
const MiscUtils_1 = require("../../utils/MiscUtils");
|
|
13
14
|
const FileUploadCache_1 = require("../files/FileUploadCache");
|
|
@@ -50,17 +51,6 @@ class FlowsPersistenceDonobuApi {
|
|
|
50
51
|
this.notifyUpload = notifyUpload;
|
|
51
52
|
}
|
|
52
53
|
// -- helpers --------------------------------------------------------
|
|
53
|
-
async request(path, init) {
|
|
54
|
-
return donobuApiFetch(this.baseUrl, this.apiKey, path, init);
|
|
55
|
-
}
|
|
56
|
-
async jsonRequest(path, method, body) {
|
|
57
|
-
return this.request(path, {
|
|
58
|
-
method,
|
|
59
|
-
headers: { 'Content-Type': 'application/json' },
|
|
60
|
-
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
// -- Flow metadata -------------------------------------------------
|
|
64
54
|
async setFlowMetadata(flowMetadata) {
|
|
65
55
|
const response = await this.jsonRequest(`/v1/flows/${encodeURIComponent(flowMetadata.id)}/metadata`, 'PUT', {
|
|
66
56
|
id: flowMetadata.id,
|
|
@@ -86,6 +76,7 @@ class FlowsPersistenceDonobuApi {
|
|
|
86
76
|
const body = (await response.json());
|
|
87
77
|
return body.record;
|
|
88
78
|
}
|
|
79
|
+
// -- Flow metadata -------------------------------------------------
|
|
89
80
|
async getFlowMetadataByName(flowName) {
|
|
90
81
|
const params = new URLSearchParams({ name: flowName, limit: '1' });
|
|
91
82
|
const response = await this.jsonRequest(`/v1/flows?${params.toString()}`, 'GET');
|
|
@@ -161,7 +152,6 @@ class FlowsPersistenceDonobuApi {
|
|
|
161
152
|
// worker iteration to release the claim cleanly (see processOne).
|
|
162
153
|
await this.fileCache.deleteFlow(flowId);
|
|
163
154
|
}
|
|
164
|
-
// -- Tool calls ----------------------------------------------------
|
|
165
155
|
async setToolCall(flowId, toolCall) {
|
|
166
156
|
const response = await this.jsonRequest(`/v1/flows/${encodeURIComponent(flowId)}/tool-calls/${encodeURIComponent(toolCall.id)}`, 'PUT', { record: toolCall });
|
|
167
157
|
if (!response.ok) {
|
|
@@ -179,13 +169,13 @@ class FlowsPersistenceDonobuApi {
|
|
|
179
169
|
const body = (await response.json());
|
|
180
170
|
return body.items;
|
|
181
171
|
}
|
|
172
|
+
// -- Tool calls ----------------------------------------------------
|
|
182
173
|
async deleteToolCall(flowId, toolCallId) {
|
|
183
174
|
const response = await this.jsonRequest(`/v1/flows/${encodeURIComponent(flowId)}/tool-calls/${encodeURIComponent(toolCallId)}`, 'DELETE');
|
|
184
175
|
if (!response.ok) {
|
|
185
176
|
throw new Error(`Failed to delete tool call: ${response.status} ${response.statusText}`);
|
|
186
177
|
}
|
|
187
178
|
}
|
|
188
|
-
// -- AI Queries ----------------------------------------------------
|
|
189
179
|
async setAiQuery(flowId, aiQuery) {
|
|
190
180
|
const response = await this.jsonRequest(`/v1/flows/${encodeURIComponent(flowId)}/ai-queries/${encodeURIComponent(aiQuery.id)}`, 'PUT', { record: aiQuery });
|
|
191
181
|
if (!response.ok) {
|
|
@@ -201,9 +191,9 @@ class FlowsPersistenceDonobuApi {
|
|
|
201
191
|
throw new Error(`Failed to get AI queries: ${response.status} ${response.statusText}`);
|
|
202
192
|
}
|
|
203
193
|
const body = (await response.json());
|
|
204
|
-
return body.items;
|
|
194
|
+
return body.items.map(AiQuery_1.normalizeAiQuery);
|
|
205
195
|
}
|
|
206
|
-
// --
|
|
196
|
+
// -- AI Queries ----------------------------------------------------
|
|
207
197
|
async saveScreenShot(flowId, bytes) {
|
|
208
198
|
const imageType = MiscUtils_1.MiscUtils.detectImageType(bytes);
|
|
209
199
|
const fileId = `${new Date().toISOString()}.screenshot.${imageType}`;
|
|
@@ -213,7 +203,7 @@ class FlowsPersistenceDonobuApi {
|
|
|
213
203
|
async getScreenShot(flowId, screenShotId) {
|
|
214
204
|
return this.getFlowFile(flowId, screenShotId);
|
|
215
205
|
}
|
|
216
|
-
// --
|
|
206
|
+
// -- Screenshots ---------------------------------------------------
|
|
217
207
|
async setVideo(flowId, bytes) {
|
|
218
208
|
await this.setFlowFile(flowId, VIDEO_FILE_ID, bytes);
|
|
219
209
|
}
|
|
@@ -234,7 +224,7 @@ class FlowsPersistenceDonobuApi {
|
|
|
234
224
|
startOffset,
|
|
235
225
|
};
|
|
236
226
|
}
|
|
237
|
-
// --
|
|
227
|
+
// -- Video --------------------------------------------------------
|
|
238
228
|
/**
|
|
239
229
|
* Returns bytes for a flow file. Tries the local cache first (instant
|
|
240
230
|
* playback for files this machine recently uploaded; warm cache for
|
|
@@ -274,7 +264,7 @@ class FlowsPersistenceDonobuApi {
|
|
|
274
264
|
await this.fileCache.writePending(flowId, fileId, fileBytes);
|
|
275
265
|
this.notifyUpload();
|
|
276
266
|
}
|
|
277
|
-
// --
|
|
267
|
+
// -- Flow files ----------------------------------------------------
|
|
278
268
|
async setBrowserState(flowId, browserState) {
|
|
279
269
|
const response = await this.jsonRequest(`/v1/flows/${encodeURIComponent(flowId)}/browser-state`, 'PUT', { record: browserState });
|
|
280
270
|
if (!response.ok) {
|
|
@@ -295,6 +285,17 @@ class FlowsPersistenceDonobuApi {
|
|
|
295
285
|
}
|
|
296
286
|
return BrowserStorageState_1.BrowserStorageStateSchema.parse(body.record);
|
|
297
287
|
}
|
|
288
|
+
// -- Browser state -------------------------------------------------
|
|
289
|
+
async request(path, init) {
|
|
290
|
+
return donobuApiFetch(this.baseUrl, this.apiKey, path, init);
|
|
291
|
+
}
|
|
292
|
+
async jsonRequest(path, method, body) {
|
|
293
|
+
return this.request(path, {
|
|
294
|
+
method,
|
|
295
|
+
headers: { 'Content-Type': 'application/json' },
|
|
296
|
+
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
297
|
+
});
|
|
298
|
+
}
|
|
298
299
|
}
|
|
299
300
|
exports.FlowsPersistenceDonobuApi = FlowsPersistenceDonobuApi;
|
|
300
301
|
// ---------------------------------------------------------------------------
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.FlowsPersistenceSqlite = void 0;
|
|
4
4
|
const crypto_1 = require("crypto");
|
|
5
5
|
const FlowNotFoundException_1 = require("../../exceptions/FlowNotFoundException");
|
|
6
|
+
const AiQuery_1 = require("../../models/AiQuery");
|
|
6
7
|
const BrowserStorageState_1 = require("../../models/BrowserStorageState");
|
|
7
8
|
const MiscUtils_1 = require("../../utils/MiscUtils");
|
|
8
9
|
const normalizeFlowMetadata_1 = require("../normalizeFlowMetadata");
|
|
@@ -215,7 +216,7 @@ class FlowsPersistenceSqlite {
|
|
|
215
216
|
await this.getFlowMetadataById(flowId);
|
|
216
217
|
const stmt = this.db.prepare('SELECT ai_query FROM ai_queries WHERE flow_id = ? ORDER BY started_at');
|
|
217
218
|
const rows = stmt.all(flowId);
|
|
218
|
-
return rows.map((row) => JSON.parse(row.ai_query));
|
|
219
|
+
return rows.map((row) => (0, AiQuery_1.normalizeAiQuery)(JSON.parse(row.ai_query)));
|
|
219
220
|
}
|
|
220
221
|
async setVideo(flowId, bytes) {
|
|
221
222
|
// Ensure flow exists.
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import type { TargetInitCallbacks } from '../managers/TargetInspector';
|
|
2
|
+
import type { Observation } from '../models/Observation';
|
|
3
|
+
import type { FlowsPersistence } from '../persistence/flows/FlowsPersistence';
|
|
4
|
+
/**
|
|
5
|
+
* A target is the external thing a flow drives to accomplish its objective —
|
|
6
|
+
* today, a web browser. Each thing a target can do is modeled as a separate
|
|
7
|
+
* optional capability role, and a provider implements only the roles it has.
|
|
8
|
+
* The engine can then ask for one capability and skip providers that lack it,
|
|
9
|
+
* instead of every target stubbing out methods it cannot support. A flow drives
|
|
10
|
+
* a list of providers (0..N), so a single flow can span multiple targets.
|
|
11
|
+
*
|
|
12
|
+
* The roles:
|
|
13
|
+
* - {@link ObserverCapability} — produces the per-turn perception sent to the LLM
|
|
14
|
+
* - {@link ActionCapability} — the handle that tools act through
|
|
15
|
+
* - {@link LifecycleCapability} — connection, recovery, initialization, session state
|
|
16
|
+
* - {@link PromptSectionCapability} — the provider's slice of the system prompt
|
|
17
|
+
*/
|
|
18
|
+
export interface TargetProvider {
|
|
19
|
+
/** Present iff this provider produces a per-turn observation (PUSH). */
|
|
20
|
+
readonly observer?: ObserverCapability;
|
|
21
|
+
/** Present iff this provider participates in lifecycle/recovery/session. */
|
|
22
|
+
readonly lifecycle?: LifecycleCapability;
|
|
23
|
+
/**
|
|
24
|
+
* This target's slice of the system prompt: the paragraph telling the AI what
|
|
25
|
+
* it will perceive of this target and how it acts on it. Present iff the
|
|
26
|
+
* provider contributes one. The engine owns the surrounding skeleton
|
|
27
|
+
* (references, env-vars, objective, guardrails) and labels each section when
|
|
28
|
+
* more than one provider contributes.
|
|
29
|
+
*/
|
|
30
|
+
readonly systemPromptSection?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Present iff this provider is reachable by tools. The engine never invokes
|
|
33
|
+
* this directly; tools narrow it by `type` to reach the concrete handle.
|
|
34
|
+
*/
|
|
35
|
+
readonly action?: ActionCapability;
|
|
36
|
+
}
|
|
37
|
+
/** Collaborators the engine hands an observer so it can persist its own record. */
|
|
38
|
+
export interface ObservationContext {
|
|
39
|
+
readonly persistence: FlowsPersistence;
|
|
40
|
+
readonly flowId: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Produces the perception added to each turn's user message so the LLM can
|
|
44
|
+
* decide what to do next. The provider runs whatever perception sequence it
|
|
45
|
+
* needs and persists its own artifacts (e.g. screenshots), returning both the
|
|
46
|
+
* content for the LLM and a record of what it observed.
|
|
47
|
+
*/
|
|
48
|
+
export interface ObserverCapability {
|
|
49
|
+
/** Assert the underlying target is reachable; throw otherwise. */
|
|
50
|
+
ensureObservable(): void;
|
|
51
|
+
/** Capture this turn's observation. */
|
|
52
|
+
observe(ctx: ObservationContext): Promise<Observation>;
|
|
53
|
+
/**
|
|
54
|
+
* Capture a one-off snapshot outside the normal turn cadence. Omit on
|
|
55
|
+
* providers without a visual snapshot; returns `null` when nothing is
|
|
56
|
+
* capturable right now.
|
|
57
|
+
*/
|
|
58
|
+
captureSnapshot?(): Promise<Buffer | null>;
|
|
59
|
+
}
|
|
60
|
+
/** Connection lifecycle, recovery, initialization, and session persistence. */
|
|
61
|
+
export interface LifecycleCapability {
|
|
62
|
+
initialize(callbacks: TargetInitCallbacks): Promise<void>;
|
|
63
|
+
/** Whether the underlying target connection is alive. */
|
|
64
|
+
readonly connected: boolean;
|
|
65
|
+
/** Whether a thrown error means this provider's target is closed. */
|
|
66
|
+
isClosedError(error: unknown): boolean;
|
|
67
|
+
/** Throw if the target exists but is no longer alive (e.g. page closed). */
|
|
68
|
+
checkAliveOrThrow(): void;
|
|
69
|
+
/** Attempt recovery after the target is closed. */
|
|
70
|
+
handleClosed(): Promise<{
|
|
71
|
+
recovered: true;
|
|
72
|
+
} | {
|
|
73
|
+
recovered: false;
|
|
74
|
+
reason: string;
|
|
75
|
+
}>;
|
|
76
|
+
/** Persist platform-specific session state (e.g. browser storage). */
|
|
77
|
+
persistSessionState(persistence: FlowsPersistence, flowId: string): Promise<void>;
|
|
78
|
+
/** Current location identifier recorded on tool calls (e.g. page URL). */
|
|
79
|
+
getCurrentLocation(): string;
|
|
80
|
+
/** Show the interaction cursor. Optional — omit on platforms without one. */
|
|
81
|
+
showInteractionCursor?(): Promise<void>;
|
|
82
|
+
/** Hide the interaction cursor. Optional — omit on platforms without one. */
|
|
83
|
+
hideInteractionCursor?(): Promise<void>;
|
|
84
|
+
/**
|
|
85
|
+
* Force-interrupt any in-flight operation against this target so a cancelled
|
|
86
|
+
* flow's run loop unblocks at once instead of waiting for the current call to
|
|
87
|
+
* return. This only interrupts — it does not release the target's resources.
|
|
88
|
+
* Optional — targets with nothing to interrupt omit it.
|
|
89
|
+
*/
|
|
90
|
+
interrupt?(): Promise<void>;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* The handle tools act through. The base carries only the discriminant;
|
|
94
|
+
* concrete providers extend it with their own handle (e.g. web adds its
|
|
95
|
+
* {@link WebTarget} and inspector).
|
|
96
|
+
*/
|
|
97
|
+
export interface ActionCapability {
|
|
98
|
+
readonly type: string;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Location identifier for tool-call records — the target's location, or
|
|
102
|
+
* `'about:blank'` when there is no target.
|
|
103
|
+
*/
|
|
104
|
+
export declare function currentLocation(provider: TargetProvider | null): string;
|
|
105
|
+
/**
|
|
106
|
+
* Capture a one-off visual snapshot. Returns `null` when there is no observer
|
|
107
|
+
* or it cannot produce a snapshot right now (e.g. a flow with no visual target).
|
|
108
|
+
*/
|
|
109
|
+
export declare function captureSnapshot(provider: TargetProvider | null): Promise<Buffer | null>;
|
|
110
|
+
//# sourceMappingURL=TargetProvider.d.ts.map
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.currentLocation = currentLocation;
|
|
4
|
+
exports.captureSnapshot = captureSnapshot;
|
|
5
|
+
/* ------------------------------------------------------------------ */
|
|
6
|
+
/* Shared provider reads */
|
|
7
|
+
/* */
|
|
8
|
+
/* Used by both the flow engine and the tool layer so the fallback */
|
|
9
|
+
/* semantics live in one place. */
|
|
10
|
+
/* ------------------------------------------------------------------ */
|
|
11
|
+
/**
|
|
12
|
+
* Location identifier for tool-call records — the target's location, or
|
|
13
|
+
* `'about:blank'` when there is no target.
|
|
14
|
+
*/
|
|
15
|
+
function currentLocation(provider) {
|
|
16
|
+
return provider?.lifecycle?.getCurrentLocation() ?? 'about:blank';
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Capture a one-off visual snapshot. Returns `null` when there is no observer
|
|
20
|
+
* or it cannot produce a snapshot right now (e.g. a flow with no visual target).
|
|
21
|
+
*/
|
|
22
|
+
async function captureSnapshot(provider) {
|
|
23
|
+
return (await provider?.observer?.captureSnapshot?.()) ?? null;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=TargetProvider.js.map
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type { TargetInspector } from '../managers/TargetInspector';
|
|
2
1
|
import type { ControlPanel } from '../models/ControlPanel';
|
|
3
2
|
import type { CreateDonobuFlow } from '../models/CreateDonobuFlow';
|
|
4
3
|
import type { FlowMetadata } from '../models/FlowMetadata';
|
|
5
4
|
import type { ProposedToolCall } from '../models/ProposedToolCall';
|
|
5
|
+
import type { TargetProvider } from './TargetProvider';
|
|
6
6
|
/**
|
|
7
7
|
* Encapsulates target-specific lifecycle and configuration for a single flow.
|
|
8
8
|
*
|
|
@@ -22,8 +22,11 @@ import type { ProposedToolCall } from '../models/ProposedToolCall';
|
|
|
22
22
|
export interface TargetRuntime {
|
|
23
23
|
/** Target type identifier for tool filtering (e.g. `'web'`, `'mobile'`). */
|
|
24
24
|
readonly targetType: string;
|
|
25
|
-
/**
|
|
26
|
-
|
|
25
|
+
/**
|
|
26
|
+
* The target the flow drives, or `null` for a targetless flow. The web
|
|
27
|
+
* runtime supplies one. This is the seam the engine and tools consume.
|
|
28
|
+
*/
|
|
29
|
+
readonly provider: TargetProvider | null;
|
|
27
30
|
/** Control panel for this flow. {@link NoOpControlPanel} if unsupported. */
|
|
28
31
|
readonly controlPanel: ControlPanel;
|
|
29
32
|
/**
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Dialog } from 'playwright';
|
|
2
|
+
import type { DialogHost } from '../managers/TargetInspector';
|
|
3
|
+
/**
|
|
4
|
+
* Builds the Playwright dialog handler for a web target — the callback that
|
|
5
|
+
* decides how to answer a browser alert/confirm/prompt. It reaches the flow
|
|
6
|
+
* engine only through the narrow {@link DialogHost} shim, which keeps this web
|
|
7
|
+
* concern out of the engine itself.
|
|
8
|
+
*
|
|
9
|
+
* The returned handler is registered on the browser context and runs as an
|
|
10
|
+
* async event callback, so it must never leak an exception (that would crash
|
|
11
|
+
* the process) — everything is wrapped in a try/catch that logs.
|
|
12
|
+
*/
|
|
13
|
+
export declare function createWebDialogHandler(host: DialogHost): (dialog: Dialog) => Promise<void>;
|
|
14
|
+
//# sourceMappingURL=WebDialogHandler.d.ts.map
|