UNPKG

donobu

Version:

Create browser automations with an LLM agent and replay them as Playwright scripts.

254 lines 14.2 kB
import type { EnvPick } from 'env-struct'; import type { BrowserContext } from 'playwright'; import type { z } from 'zod/v4'; import type { GptClient } from '../clients/GptClient'; import type { GptClientFactory } from '../clients/GptClientFactory'; import type { GeneratedProject } from '../codegen/CodeGenerator'; import type { env } from '../envVars'; import type { AiQuery } from '../models/AiQuery'; import type { BrowserStateReference } from '../models/BrowserStateFlowReference'; import type { BrowserStorageState } from '../models/BrowserStorageState'; import type { CodeGenerationOptions } from '../models/CodeGenerationOptions'; import type { ControlPanelFactory } from '../models/ControlPanel'; import type { CreateDonobuFlow } from '../models/CreateDonobuFlow'; import type { DonobuAgent } from '../models/DonobuAgentType'; import type { DonobuDeploymentEnvironment } from '../models/DonobuDeploymentEnvironment'; import type { FlowHandle } from '../models/FlowHandle'; import type { FlowMetadata } from '../models/FlowMetadata'; import type { FlowsQuery } from '../models/FlowMetadata'; import type { PaginatedResult } from '../models/PaginatedResult'; import type { ProposedToolCall } from '../models/ProposedToolCall'; import type { RunConfig } from '../models/RunConfig'; import type { RunMode } from '../models/RunMode'; import type { ToolCall } from '../models/ToolCall'; import type { FlowsPersistenceRegistry } from '../persistence/flows/FlowsPersistenceRegistry'; import type { TestsPersistenceRegistry } from '../persistence/tests/TestsPersistenceRegistry'; import type { TargetRuntimePluginRegistry } from '../targets/TargetRuntimePlugin'; import type { Tool } from '../tools/Tool'; import type { FlowLogSnapshot } from '../utils/FlowLogBuffer'; import type { AgentsManager } from './AgentsManager'; import { DonobuFlow } from './DonobuFlow'; import type { EnvDataManager } from './EnvDataManager'; import type { GptConfigsManager } from './GptConfigsManager'; import type { ToolRegistry } from './ToolRegistry'; /** * Response wrapper for `createFlow` calls. */ export type { FlowHandle }; export declare class DonobuFlowsManager { private readonly deploymentEnvironment; private readonly gptClientFactory; private readonly gptConfigsManager; private readonly agentsManager; private readonly flowsPersistenceRegistry; private readonly envDataManager; private readonly controlPanelFactory; private readonly environ; private readonly toolRegistry; private readonly targetRuntimePlugins; private readonly testsPersistenceRegistry; static readonly DEFAULT_MESSAGE_DURATION = 2247; static readonly DEFAULT_MAX_TOOL_CALLS = 50; static readonly DEFAULT_BROWSER_STATE_FILENAME = "browserstate.json"; static readonly FLOW_NAME_MAX_LENGTH = 255; private readonly flowRuntime; private readonly flowCatalog; constructor(deploymentEnvironment: DonobuDeploymentEnvironment, gptClientFactory: GptClientFactory, gptConfigsManager: GptConfigsManager, agentsManager: AgentsManager, flowsPersistenceRegistry: FlowsPersistenceRegistry, envDataManager: EnvDataManager, controlPanelFactory: ControlPanelFactory, environ: EnvPick<typeof env, 'ANTHROPIC_API_KEY' | 'ANTHROPIC_MODEL_NAME' | 'AWS_ACCESS_KEY_ID' | 'AWS_BEDROCK_MODEL_NAME' | 'AWS_SECRET_ACCESS_KEY' | 'BASE64_GPT_CONFIG' | 'BROWSERBASE_API_KEY' | 'BROWSERBASE_PROJECT_ID' | 'DONOBU_API_KEY' | 'GOOGLE_GENERATIVE_AI_API_KEY' | 'GOOGLE_GENERATIVE_AI_MODEL_NAME' | 'OLLAMA_API_URL' | 'OLLAMA_MODEL_NAME' | 'OPENAI_API_KEY' | 'OPENAI_API_MODEL_NAME'>, toolRegistry: ToolRegistry, targetRuntimePlugins: TargetRuntimePluginRegistry, testsPersistenceRegistry: TestsPersistenceRegistry); /** * Create a flow with the given parameters and invoke its `DonobuFlow#run` * method, adding it to list of active flows. * * If `flowParams.testId` is set, the new flow is persisted to the same * layer as the referenced test so the `flow_metadata.test_id` foreign * key holds. Otherwise the primary layer is used. * * @param gptClient If present, will use this as the associated GPT client for * this flow instead of instantiating a new one. If so, the * gptConfigNameOverride field will be ignored. * @param browserContextOverride If present, will use this as the browser * context instead of instantiating a new one. If so, most browser * related parameters are will be ignored. */ createFlow(flowParams: CreateDonobuFlow, gptClient?: GptClient, browserContextOverride?: BrowserContext): Promise<FlowHandle>; getFlowLogs(flowId: string): Promise<FlowLogSnapshot>; renameFlow(flowId: string, name: string | null): Promise<FlowMetadata>; /** * Converts a prior flow's tool calls into a list of tool calls to invoke when * starting a new flow as a rerun (i.e. without agentic decisioning). * * @param priorFlowMetadata The metadata of the flow to prepare as a rerun. * @param options The code generation options to use for the rerun. * * @returns A list of tool calls to invoke when starting the flow. */ getToolCallsForRerun(priorFlowMetadata: FlowMetadata, options: CodeGenerationOptions): Promise<ProposedToolCall[]>; /** * Loads the given flow by ID and returns a `CreateDonobuFlow` object that can be passed to `createFlow` * to execute the flow as a rerun (i.e. without agentic decisioning). * * @param flowId The ID of the flow to prepare as a rerun. * @returns Parameters that can be passed to createFlow to execute the flow as a rerun. */ getFlowAsRerun(flowId: string, options: CodeGenerationOptions): Promise<CreateDonobuFlow>; /** * Takes a RunConfig object, or anything derived from it (FlowMetadata, * TestMetadata), plus some additional parameters, and returns a * CreateDonobuFlow object that can be passed to `createFlow` to execute the * flow. * * @param name The name for the new flow * @param runMode The run mode to be used for the flow * @param config The RunConfig object * @param toolCallsOnStart An ordered series of tool calls to invoke when * starting the flow * * @returns A CreateDonobuFlow object that can be passed to createFlow to * execute the flow. */ getFlowFromConfigAndToolCalls(name: string, runMode: RunMode, config: RunConfig, toolCallsOnStart: ProposedToolCall[]): CreateDonobuFlow; /** Add a proposed tool call the tool call queue for the given flow by ID. */ proposeToolCall(flowId: string, toolName: string, parameters: Record<string, unknown>): Promise<void>; /** * If the application is running in a non-hosted context, returns a direct, * raw, `DonobuFlow` object by ID. If there is no flow in an active state * with the given ID, or the application is running on some far flung server, * then `ActiveFlowNotFoundException` is thrown. Mutations made to the * returned object will be reflected by the active flow, and vice versa. */ getActiveFlow(flowId: string): DonobuFlow; /** * Get flows metadata across multiple persistence layers with pagination and filtering. */ getFlows(query: FlowsQuery): Promise<PaginatedResult<FlowMetadata>>; /** * Returns the metadata for the given flow by ID. If the flow is active, the * returned metadata object is shared with the underlying flow and changes * made to this metadata object will be visible to the flow. If the flow is * not active, a copy of the persisted metadata is returned. */ getFlowById(flowId: string): Promise<FlowMetadata>; /** * Returns the metadata for the given flow by name. */ getFlowByName(flowName: string): Promise<FlowMetadata>; /** Returns all the tool calls made by the given flow by ID. */ getToolCalls(flowId: string): Promise<ToolCall[]>; /** Returns all AI query records for the given flow by ID. */ getAiQueries(flowId: string): Promise<AiQuery[]>; /** * Attempts to delete a flow by ID. If the flow is active, then * `CannotDeleteRunningFlowException` is thrown. If the flow is not active, * then the flow's persisted data is deleted. */ deleteFlowById(flowId: string): Promise<void>; /** * Attempts to cancel a flow by ID. If the flow is active, the flow is ended * with a state of `FAILED`. If the flow is not active, this method has no * effect. */ cancelFlow(flowId: string): Promise<FlowMetadata>; /** Creates a Node.js Microsoft Playwright script to replay the given flow. */ getFlowAsPlaywrightScript(flowId: string, options?: CodeGenerationOptions): Promise<string>; /** * Generates a complete Playwright project structure for multiple flows with dependency management. * Automatically includes any missing dependencies to ensure a complete dependency graph. */ getFlowsAsPlaywrightProject(flowIds: string[], options: CodeGenerationOptions): Promise<GeneratedProject>; /** * Resolves a GPT client using the provided GPT configuration name, falling back * to environment-provided configs (BASE64_GPT_CONFIG, DONOBU_API_KEY, * AWS_BEDROCK_MODEL_NAME, ANTHROPIC_API_KEY, GOOGLE_GENERATIVE_AI_API_KEY, * OPENAI_API_KEY, OLLAMA_MODEL_NAME) and finally the config bound to the * 'flow-runner' agent. * Returns a null client if no configuration source is available. * * Public for testing only. **/ createGptClient(gptConfigName?: string): Promise<{ gptConfigName: string | null; agentName: DonobuAgent | null; gptClient: GptClient | null; }>; /** * Loads the browser state associated with the given flow. Throws * {@link BrowserStateNotFoundException} if it is not found. */ getBrowserStorageState(browserStateRef: BrowserStateReference): Promise<BrowserStorageState>; /** * Picks the flows persistence layer to use when creating a new flow. * * - If `testId` is null/undefined: use the primary flows layer. * - If `testId` is set: look up the test's layer key and use the matching * flows layer. If no flows layer matches the test's key (rare — * asymmetric registry config), fall back to the primary layer; the FK * won't hold but the flow is at least persisted. * - If `testId` is set but no test exists with that ID anywhere: fall * back to the primary layer (the SQLite FK will reject if applicable; * non-DB layers will accept the dangling reference). */ /** * Best-effort check that no flow with the given ID exists in any persistence * layer. Throws {@link FlowIdCollisionException} on hit. Note: this is RACY * — concurrent callers with the same ID can both pass the check. */ private assertFlowIdAvailable; private resolveLayerForFlowCreate; private findTestLayerKey; private isLocallyRunning; } /** * Extracts environment variable names from the given objective and combines * it with the given explicitly allowed variables. * * This function performs two operations: * 1. Extracts environment variable references (in the form `$.env.VARIABLE_NAME`) from the overall objective. * 2. Combines these with any explicitly allowed environment variable names. * * The resulting array contains unique environment variable names without duplicates. * * @param overallObjective - The objective text that may contain environment variable references. * @param explicitlyAllowedEnvVariableNames - Additional environment variable names explicitly allowed. * @returns An array of unique environment variable names that are allowed to be accessed. * * @example * // Returns ["API_KEY", "USER_NAME", "DEBUG_MODE"] * distillAllowedEnvVariableNames( * "Use {{$.env.API_KEY}} to authenticate and greet {{$.env.USER_NAME}}", * ["API_KEY", "DEBUG_MODE"] * ); */ export declare function distillAllowedEnvVariableNames(overallObjective: string | null | undefined, explicitlyAllowedEnvVariableNames: string[] | null | undefined): string[]; /** * Resolves the final set of tools a flow is permitted to use. * * The resolution follows this priority: * 1. If the caller explicitly listed tools, use those (filtered to the target). * 2. Otherwise, fall back to target-appropriate defaults (curated subset for * web, all target-compatible tools for plugin-provided targets). * 3. Tools required by `toolCallsOnStart` are always included. * 4. Custom (user-defined) tools are prepended. * 5. GPT-requiring tools are stripped when no GPT client is available. * 6. Minimal tools (objective bookkeeping) are guaranteed present. * 7. The result is deduplicated and sorted by name. */ /** @internal Exported for testing. */ export declare function setupAllowedTools(flowParams: Pick<CreateDonobuFlow, 'customTools' | 'toolCallsOnStart' | 'allowedTools'>, hasGptClient: boolean, targetType: string, toolRegistry: ToolRegistry): Promise<Tool<z.ZodObject, z.ZodObject>[]>; /** * Convert an *executed* list of {@link ToolCall}s into a list of * {@link ProposedToolCall}s that can be replayed in a fresh session. * * For each call, we look up the {@link Tool} in the given registry and * delegate to its `prepareForRerun` override. Tools that need selector * remapping (e.g. {@link ClickTool}, {@link InputTextTool}, the mobile * interaction tools) each own their own logic; tools with no replay- * specific needs inherit the passthrough default from {@link Tool}. * * When a tool is not registered (stale flow, removed tool) or * `prepareForRerun` throws (e.g. missing selector metadata), the call * is passed through or skipped with an `appLogger.warn` — "best-effort * replay" behavior is preserved. * * @returns A list of {@link ProposedToolCall}s ready for replay. */ export declare function prepareToolCallsForRerun(toolCalls: ToolCall[], options: CodeGenerationOptions, toolRegistry: ToolRegistry): Promise<ProposedToolCall[]>; //# sourceMappingURL=DonobuFlowsManager.d.ts.map