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.
Files changed (145) hide show
  1. package/dist/apis/GptConfigsApi.d.ts +5 -5
  2. package/dist/apis/GptConfigsApi.js +14 -14
  3. package/dist/bindings/PageInteractionTracker.d.ts +1 -1
  4. package/dist/bindings/PageInteractionTracker.js +3 -3
  5. package/dist/bindings/SetDonobuAnnotations.d.ts +1 -1
  6. package/dist/bindings/SetDonobuAnnotations.js +3 -3
  7. package/dist/clients/AnthropicGptClient.d.ts +2 -2
  8. package/dist/clients/AnthropicGptClient.js +77 -77
  9. package/dist/clients/OpenAiGptClient.d.ts +14 -14
  10. package/dist/clients/OpenAiGptClient.js +183 -183
  11. package/dist/esm/apis/GptConfigsApi.d.ts +5 -5
  12. package/dist/esm/apis/GptConfigsApi.js +14 -14
  13. package/dist/esm/bindings/PageInteractionTracker.d.ts +1 -1
  14. package/dist/esm/bindings/PageInteractionTracker.js +3 -3
  15. package/dist/esm/bindings/SetDonobuAnnotations.d.ts +1 -1
  16. package/dist/esm/bindings/SetDonobuAnnotations.js +3 -3
  17. package/dist/esm/clients/AnthropicGptClient.d.ts +2 -2
  18. package/dist/esm/clients/AnthropicGptClient.js +77 -77
  19. package/dist/esm/clients/OpenAiGptClient.d.ts +14 -14
  20. package/dist/esm/clients/OpenAiGptClient.js +183 -183
  21. package/dist/esm/lib/ai/PageAi.js +2 -1
  22. package/dist/esm/lib/page/extendPage.js +2 -1
  23. package/dist/esm/lib/test/utils/TestFileUpdater.d.ts +9 -9
  24. package/dist/esm/lib/test/utils/TestFileUpdater.js +49 -49
  25. package/dist/esm/main.d.ts +2 -0
  26. package/dist/esm/managers/AdminApiController.d.ts +16 -16
  27. package/dist/esm/managers/AdminApiController.js +35 -35
  28. package/dist/esm/managers/DonobuFlow.d.ts +57 -36
  29. package/dist/esm/managers/DonobuFlow.js +489 -564
  30. package/dist/esm/managers/DonobuFlowsManager.js +13 -17
  31. package/dist/esm/managers/FlowDependencyAnalyzer.d.ts +12 -12
  32. package/dist/esm/managers/FlowDependencyAnalyzer.js +77 -77
  33. package/dist/esm/managers/PageInspector.d.ts +38 -38
  34. package/dist/esm/managers/PageInspector.js +745 -745
  35. package/dist/esm/managers/TargetInspector.d.ts +28 -33
  36. package/dist/esm/managers/TestsManager.d.ts +25 -25
  37. package/dist/esm/managers/TestsManager.js +74 -74
  38. package/dist/esm/managers/ToolManager.js +7 -5
  39. package/dist/esm/managers/ToolRegistry.d.ts +5 -1
  40. package/dist/esm/managers/WebTargetInspector.d.ts +9 -5
  41. package/dist/esm/managers/WebTargetInspector.js +45 -47
  42. package/dist/esm/models/AiQuery.d.ts +29 -15
  43. package/dist/esm/models/AiQuery.js +31 -0
  44. package/dist/esm/models/ControlPanel.d.ts +18 -13
  45. package/dist/esm/models/InteractableElement.d.ts +6 -0
  46. package/dist/esm/models/InteractableElement.js +7 -1
  47. package/dist/esm/models/Observation.d.ts +38 -0
  48. package/dist/esm/models/Observation.js +3 -0
  49. package/dist/esm/models/ToolCallContext.d.ts +3 -2
  50. package/dist/esm/persistence/flows/FlowsPersistenceDonobuApi.d.ts +2 -2
  51. package/dist/esm/persistence/flows/FlowsPersistenceDonobuApi.js +19 -18
  52. package/dist/esm/persistence/flows/FlowsPersistenceSqlite.js +2 -1
  53. package/dist/esm/targets/TargetProvider.d.ts +110 -0
  54. package/dist/esm/targets/TargetProvider.js +25 -0
  55. package/dist/esm/targets/TargetRuntime.d.ts +6 -3
  56. package/dist/esm/targets/WebDialogHandler.d.ts +14 -0
  57. package/dist/esm/targets/WebDialogHandler.js +198 -0
  58. package/dist/esm/targets/WebTargetProvider.d.ts +32 -0
  59. package/dist/esm/targets/WebTargetProvider.js +136 -0
  60. package/dist/esm/targets/WebTargetRuntime.d.ts +2 -2
  61. package/dist/esm/targets/WebTargetRuntime.js +2 -1
  62. package/dist/esm/tools/AcknowledgeUserInstruction.d.ts +6 -0
  63. package/dist/esm/tools/AcknowledgeUserInstruction.js +7 -0
  64. package/dist/esm/tools/AssertPageTool.d.ts +1 -1
  65. package/dist/esm/tools/AssertPageTool.js +3 -3
  66. package/dist/esm/tools/DetectBrokenLinksTool.d.ts +2 -2
  67. package/dist/esm/tools/DetectBrokenLinksTool.js +44 -44
  68. package/dist/esm/tools/InputFakerTool.d.ts +4 -4
  69. package/dist/esm/tools/InputFakerTool.js +10 -10
  70. package/dist/esm/tools/InputTextTool.d.ts +4 -4
  71. package/dist/esm/tools/InputTextTool.js +7 -7
  72. package/dist/esm/tools/ReplayableInteraction.d.ts +34 -34
  73. package/dist/esm/tools/ReplayableInteraction.js +245 -245
  74. package/dist/esm/tools/Tool.d.ts +6 -3
  75. package/dist/esm/tools/Tool.js +5 -2
  76. package/dist/esm/utils/BrowserUtils.d.ts +19 -19
  77. package/dist/esm/utils/BrowserUtils.js +57 -57
  78. package/dist/esm/utils/MiscUtils.d.ts +2 -2
  79. package/dist/esm/utils/MiscUtils.js +16 -16
  80. package/dist/esm/utils/PlaywrightUtils.d.ts +1 -1
  81. package/dist/esm/utils/TargetUtils.d.ts +1 -1
  82. package/dist/esm/utils/TargetUtils.js +15 -13
  83. package/dist/lib/ai/PageAi.js +2 -1
  84. package/dist/lib/page/extendPage.js +2 -1
  85. package/dist/lib/test/utils/TestFileUpdater.d.ts +9 -9
  86. package/dist/lib/test/utils/TestFileUpdater.js +49 -49
  87. package/dist/main.d.ts +2 -0
  88. package/dist/managers/AdminApiController.d.ts +16 -16
  89. package/dist/managers/AdminApiController.js +35 -35
  90. package/dist/managers/DonobuFlow.d.ts +57 -36
  91. package/dist/managers/DonobuFlow.js +489 -564
  92. package/dist/managers/DonobuFlowsManager.js +13 -17
  93. package/dist/managers/FlowDependencyAnalyzer.d.ts +12 -12
  94. package/dist/managers/FlowDependencyAnalyzer.js +77 -77
  95. package/dist/managers/PageInspector.d.ts +38 -38
  96. package/dist/managers/PageInspector.js +745 -745
  97. package/dist/managers/TargetInspector.d.ts +28 -33
  98. package/dist/managers/TestsManager.d.ts +25 -25
  99. package/dist/managers/TestsManager.js +74 -74
  100. package/dist/managers/ToolManager.js +7 -5
  101. package/dist/managers/ToolRegistry.d.ts +5 -1
  102. package/dist/managers/WebTargetInspector.d.ts +9 -5
  103. package/dist/managers/WebTargetInspector.js +45 -47
  104. package/dist/models/AiQuery.d.ts +29 -15
  105. package/dist/models/AiQuery.js +31 -0
  106. package/dist/models/ControlPanel.d.ts +18 -13
  107. package/dist/models/InteractableElement.d.ts +6 -0
  108. package/dist/models/InteractableElement.js +7 -1
  109. package/dist/models/Observation.d.ts +38 -0
  110. package/dist/models/Observation.js +3 -0
  111. package/dist/models/ToolCallContext.d.ts +3 -2
  112. package/dist/persistence/flows/FlowsPersistenceDonobuApi.d.ts +2 -2
  113. package/dist/persistence/flows/FlowsPersistenceDonobuApi.js +19 -18
  114. package/dist/persistence/flows/FlowsPersistenceSqlite.js +2 -1
  115. package/dist/targets/TargetProvider.d.ts +110 -0
  116. package/dist/targets/TargetProvider.js +25 -0
  117. package/dist/targets/TargetRuntime.d.ts +6 -3
  118. package/dist/targets/WebDialogHandler.d.ts +14 -0
  119. package/dist/targets/WebDialogHandler.js +198 -0
  120. package/dist/targets/WebTargetProvider.d.ts +32 -0
  121. package/dist/targets/WebTargetProvider.js +136 -0
  122. package/dist/targets/WebTargetRuntime.d.ts +2 -2
  123. package/dist/targets/WebTargetRuntime.js +2 -1
  124. package/dist/tools/AcknowledgeUserInstruction.d.ts +6 -0
  125. package/dist/tools/AcknowledgeUserInstruction.js +7 -0
  126. package/dist/tools/AssertPageTool.d.ts +1 -1
  127. package/dist/tools/AssertPageTool.js +3 -3
  128. package/dist/tools/DetectBrokenLinksTool.d.ts +2 -2
  129. package/dist/tools/DetectBrokenLinksTool.js +44 -44
  130. package/dist/tools/InputFakerTool.d.ts +4 -4
  131. package/dist/tools/InputFakerTool.js +10 -10
  132. package/dist/tools/InputTextTool.d.ts +4 -4
  133. package/dist/tools/InputTextTool.js +7 -7
  134. package/dist/tools/ReplayableInteraction.d.ts +34 -34
  135. package/dist/tools/ReplayableInteraction.js +245 -245
  136. package/dist/tools/Tool.d.ts +6 -3
  137. package/dist/tools/Tool.js +5 -2
  138. package/dist/utils/BrowserUtils.d.ts +19 -19
  139. package/dist/utils/BrowserUtils.js +57 -57
  140. package/dist/utils/MiscUtils.d.ts +2 -2
  141. package/dist/utils/MiscUtils.js +16 -16
  142. package/dist/utils/PlaywrightUtils.d.ts +1 -1
  143. package/dist/utils/TargetUtils.d.ts +1 -1
  144. package/dist/utils/TargetUtils.js +15 -13
  145. 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 `queriedAt`, then progressively filled in as
5
- * screenshots are captured and elements are discovered. The `error` field is
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
- * The ID of the clean (un-annotated) screenshot of the page at query time.
15
- * Null until the screenshot is captured.
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 cleanScreenshotId: string | null;
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
- /** Names of tools loaded in the flow's ToolManager. Surfaced to the UI so
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
- /** The flow's current run mode, so the UI can render and drive the autonomy
36
- * selector (Manual/Supervised/Autonomous). */
37
- runMode?: RunMode;
38
- /** Whether AI-driven modes (Autonomous/Supervised) are available i.e. the
39
- * flow has a GPT client. False for purely manual flows, so the UI can disable
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
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=Observation.js.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
- readonly targetInspector: TargetInspector;
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
- // -- Screenshots ---------------------------------------------------
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
- // -- Video --------------------------------------------------------
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
- // -- Flow files ----------------------------------------------------
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
- // -- Browser state -------------------------------------------------
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
- /** Inspector bound to the live session (browser page, mobile device, etc.). */
26
- readonly inspector: TargetInspector;
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