donobu 2.48.1 → 2.49.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/ToolsApi.d.ts.map +1 -1
- package/dist/apis/ToolsApi.js +26 -2
- package/dist/apis/ToolsApi.js.map +1 -1
- package/dist/assets/generated/version +1 -1
- package/dist/esm/apis/ToolsApi.d.ts.map +1 -1
- package/dist/esm/apis/ToolsApi.js +26 -2
- package/dist/esm/apis/ToolsApi.js.map +1 -1
- package/dist/esm/assets/generated/version +1 -1
- package/dist/esm/lib/PageAi.d.ts.map +1 -1
- package/dist/esm/lib/PageAi.js +10 -11
- package/dist/esm/lib/PageAi.js.map +1 -1
- package/dist/esm/lib/testExtension.js +1 -1
- package/dist/esm/lib/testExtension.js.map +1 -1
- package/dist/esm/lib/utils/triageTestFailure.d.ts.map +1 -1
- package/dist/esm/lib/utils/triageTestFailure.js +4 -4
- package/dist/esm/lib/utils/triageTestFailure.js.map +1 -1
- package/dist/esm/managers/DonobuFlowsManager.d.ts +25 -59
- package/dist/esm/managers/DonobuFlowsManager.d.ts.map +1 -1
- package/dist/esm/managers/DonobuFlowsManager.js +322 -301
- package/dist/esm/managers/DonobuFlowsManager.js.map +1 -1
- package/dist/esm/managers/DonobuStack.js +1 -1
- package/dist/esm/managers/DonobuStack.js.map +1 -1
- package/dist/esm/managers/GptConfigsManager.js +36 -3
- package/dist/esm/managers/GptConfigsManager.js.map +1 -1
- package/dist/esm/managers/ToolManager.d.ts +2 -0
- package/dist/esm/managers/ToolManager.d.ts.map +1 -1
- package/dist/esm/managers/ToolManager.js +9 -5
- package/dist/esm/managers/ToolManager.js.map +1 -1
- package/dist/esm/persistence/DonobuSqliteDb.d.ts +2 -3
- package/dist/esm/persistence/DonobuSqliteDb.d.ts.map +1 -1
- package/dist/esm/persistence/DonobuSqliteDb.js +37 -6
- package/dist/esm/persistence/DonobuSqliteDb.js.map +1 -1
- package/dist/esm/persistence/env/EnvPersistenceFactoryImpl.d.ts.map +1 -1
- package/dist/esm/persistence/env/EnvPersistenceFactoryImpl.js +1 -1
- package/dist/esm/persistence/env/EnvPersistenceFactoryImpl.js.map +1 -1
- package/dist/esm/persistence/flows/FlowsPersistenceFactoryImpl.d.ts.map +1 -1
- package/dist/esm/persistence/flows/FlowsPersistenceFactoryImpl.js +2 -2
- package/dist/esm/persistence/flows/FlowsPersistenceFactoryImpl.js.map +1 -1
- package/dist/esm/persistence/flows/FlowsPersistenceSqlite.d.ts.map +1 -1
- package/dist/esm/persistence/flows/FlowsPersistenceSqlite.js +21 -16
- package/dist/esm/persistence/flows/FlowsPersistenceSqlite.js.map +1 -1
- package/dist/esm/tools/AssertPageTextTool.js +1 -1
- package/dist/esm/tools/AssertPageTextTool.js.map +1 -1
- package/dist/esm/utils/BrowserUtils.d.ts +1 -0
- package/dist/esm/utils/BrowserUtils.d.ts.map +1 -1
- package/dist/esm/utils/BrowserUtils.js +2 -5
- package/dist/esm/utils/BrowserUtils.js.map +1 -1
- package/dist/lib/PageAi.d.ts.map +1 -1
- package/dist/lib/PageAi.js +10 -11
- package/dist/lib/PageAi.js.map +1 -1
- package/dist/lib/testExtension.js +1 -1
- package/dist/lib/testExtension.js.map +1 -1
- package/dist/lib/utils/triageTestFailure.d.ts.map +1 -1
- package/dist/lib/utils/triageTestFailure.js +4 -4
- package/dist/lib/utils/triageTestFailure.js.map +1 -1
- package/dist/managers/DonobuFlowsManager.d.ts +25 -59
- package/dist/managers/DonobuFlowsManager.d.ts.map +1 -1
- package/dist/managers/DonobuFlowsManager.js +322 -301
- package/dist/managers/DonobuFlowsManager.js.map +1 -1
- package/dist/managers/DonobuStack.js +1 -1
- package/dist/managers/DonobuStack.js.map +1 -1
- package/dist/managers/GptConfigsManager.js +36 -3
- package/dist/managers/GptConfigsManager.js.map +1 -1
- package/dist/managers/ToolManager.d.ts +2 -0
- package/dist/managers/ToolManager.d.ts.map +1 -1
- package/dist/managers/ToolManager.js +9 -5
- package/dist/managers/ToolManager.js.map +1 -1
- package/dist/persistence/DonobuSqliteDb.d.ts +2 -3
- package/dist/persistence/DonobuSqliteDb.d.ts.map +1 -1
- package/dist/persistence/DonobuSqliteDb.js +37 -6
- package/dist/persistence/DonobuSqliteDb.js.map +1 -1
- package/dist/persistence/env/EnvPersistenceFactoryImpl.d.ts.map +1 -1
- package/dist/persistence/env/EnvPersistenceFactoryImpl.js +1 -1
- package/dist/persistence/env/EnvPersistenceFactoryImpl.js.map +1 -1
- package/dist/persistence/flows/FlowsPersistenceFactoryImpl.d.ts.map +1 -1
- package/dist/persistence/flows/FlowsPersistenceFactoryImpl.js +2 -2
- package/dist/persistence/flows/FlowsPersistenceFactoryImpl.js.map +1 -1
- package/dist/persistence/flows/FlowsPersistenceSqlite.d.ts.map +1 -1
- package/dist/persistence/flows/FlowsPersistenceSqlite.js +21 -16
- package/dist/persistence/flows/FlowsPersistenceSqlite.js.map +1 -1
- package/dist/tools/AssertPageTextTool.js +1 -1
- package/dist/tools/AssertPageTextTool.js.map +1 -1
- package/dist/utils/BrowserUtils.d.ts +1 -0
- package/dist/utils/BrowserUtils.d.ts.map +1 -1
- package/dist/utils/BrowserUtils.js +2 -5
- package/dist/utils/BrowserUtils.js.map +1 -1
- package/package.json +1 -1
|
@@ -34,6 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.DonobuFlowsManager = void 0;
|
|
37
|
+
exports.distillAllowedEnvVariableNames = distillAllowedEnvVariableNames;
|
|
37
38
|
const BrowserUtils_1 = require("../utils/BrowserUtils");
|
|
38
39
|
const DonobuFlow_1 = require("./DonobuFlow");
|
|
39
40
|
const GoToWebpageTool_1 = require("../tools/GoToWebpageTool");
|
|
@@ -46,7 +47,7 @@ const UnknownToolException_1 = require("../exceptions/UnknownToolException");
|
|
|
46
47
|
const CannotDeleteRunningFlowException_1 = require("../exceptions/CannotDeleteRunningFlowException");
|
|
47
48
|
const FlowNotFoundException_1 = require("../exceptions/FlowNotFoundException");
|
|
48
49
|
const ToolRequiresGptException_1 = require("../exceptions/ToolRequiresGptException");
|
|
49
|
-
const fs = __importStar(require("fs"));
|
|
50
|
+
const fs = __importStar(require("fs/promises"));
|
|
50
51
|
const path = __importStar(require("path"));
|
|
51
52
|
const os_1 = require("os");
|
|
52
53
|
const BrowserStateNotFoundException_1 = require("../exceptions/BrowserStateNotFoundException");
|
|
@@ -94,19 +95,19 @@ class DonobuFlowsManager {
|
|
|
94
95
|
: await this.createGptClient(flowParams.gptConfigNameOverride ?? null);
|
|
95
96
|
const initialRunMode = flowParams.initialRunMode ??
|
|
96
97
|
(gptClientData.gptClient ? 'AUTONOMOUS' : 'INSTRUCT');
|
|
97
|
-
const browserConfig = flowParams.browser ?? this.
|
|
98
|
+
const browserConfig = flowParams.browser ?? getDefaultBrowserConfig(this.environ);
|
|
98
99
|
if (browserConfig.using.type === 'device' &&
|
|
99
100
|
!BrowserUtils_1.BrowserUtils.getSupportedDevices().has(browserConfig.using.deviceName ?? '')) {
|
|
100
101
|
throw new InvalidParamValueException_1.InvalidParamValueException('deviceName', browserConfig.using.deviceName);
|
|
101
102
|
}
|
|
102
|
-
await
|
|
103
|
+
await validateFlowParams(flowParams, gptClientData.gptClient, initialRunMode);
|
|
103
104
|
const isControlPanelEnabled = !(browserConfig.using.type === 'device'
|
|
104
105
|
? browserConfig.using.headless
|
|
105
106
|
: false) &&
|
|
106
107
|
(flowParams.isControlPanelEnabled ?? true);
|
|
107
|
-
const allowedTools = await
|
|
108
|
+
const allowedTools = await setupAllowedTools(flowParams, gptClientData !== null);
|
|
108
109
|
const toolManager = new ToolManager_1.ToolManager(allowedTools);
|
|
109
|
-
const toolCallsOnStart =
|
|
110
|
+
const toolCallsOnStart = prepareInitialToolCalls(flowParams);
|
|
110
111
|
const messageDuration = flowParams.defaultMessageDuration ??
|
|
111
112
|
DonobuFlowsManager.DEFAULT_MESSAGE_DURATION;
|
|
112
113
|
const interactionVisualizer = new InteractionVisualizer_1.InteractionVisualizer(messageDuration);
|
|
@@ -119,7 +120,7 @@ class DonobuFlowsManager {
|
|
|
119
120
|
if (maxToolCalls !== null && maxToolCalls < 0) {
|
|
120
121
|
throw new InvalidParamValueException_1.InvalidParamValueException('maxToolCalls', String(flowParams.maxToolCalls));
|
|
121
122
|
}
|
|
122
|
-
const allowedEnvVarsByName =
|
|
123
|
+
const allowedEnvVarsByName = distillAllowedEnvVariableNames(flowParams.overallObjective, flowParams.envVars);
|
|
123
124
|
const flowMetadata = {
|
|
124
125
|
id: flowId,
|
|
125
126
|
createdWithDonobuVersion: MiscUtils_1.MiscUtils.DONOBU_VERSION,
|
|
@@ -149,7 +150,7 @@ class DonobuFlowsManager {
|
|
|
149
150
|
};
|
|
150
151
|
const tempVideoDir = flowMetadata.videoDisabled
|
|
151
152
|
? undefined
|
|
152
|
-
:
|
|
153
|
+
: await createTempDirectoryForFlow(flowMetadata.id);
|
|
153
154
|
try {
|
|
154
155
|
const flowsPersistence = await this.flowsPersistenceFactory.createPersistenceLayer();
|
|
155
156
|
const envData = await this.buildEnvData(flowMetadata.envVars ?? []);
|
|
@@ -189,12 +190,12 @@ class DonobuFlowsManager {
|
|
|
189
190
|
}
|
|
190
191
|
if (tempVideoDir) {
|
|
191
192
|
try {
|
|
192
|
-
await
|
|
193
|
+
await setFlowVideo(donobuFlow.metadata.id, tempVideoDir, flowsPersistence);
|
|
193
194
|
}
|
|
194
195
|
catch (error) {
|
|
195
196
|
Logger_1.appLogger.error('Failed to save flow video:', error);
|
|
196
197
|
}
|
|
197
|
-
|
|
198
|
+
await removeTempDirectoryForFlow(donobuFlow.metadata.id);
|
|
198
199
|
}
|
|
199
200
|
});
|
|
200
201
|
return flowHandle;
|
|
@@ -205,13 +206,13 @@ class DonobuFlowsManager {
|
|
|
205
206
|
}
|
|
206
207
|
}
|
|
207
208
|
catch (error) {
|
|
208
|
-
|
|
209
|
+
await removeTempDirectoryForFlow(flowMetadata.id);
|
|
209
210
|
throw error;
|
|
210
211
|
}
|
|
211
212
|
});
|
|
212
213
|
}
|
|
213
214
|
async renameFlow(flowId, name) {
|
|
214
|
-
|
|
215
|
+
validateFlowName(name);
|
|
215
216
|
const activeFlowHandle = this.isLocallyRunning()
|
|
216
217
|
? this.activeFlows.get(flowId)
|
|
217
218
|
: null;
|
|
@@ -304,7 +305,7 @@ class DonobuFlowsManager {
|
|
|
304
305
|
*/
|
|
305
306
|
async getFlows(query) {
|
|
306
307
|
// Parse the composite page token or create initial state.
|
|
307
|
-
const paginationState =
|
|
308
|
+
const paginationState = parseCompositePageToken(query.pageToken);
|
|
308
309
|
const requestedLimit = Math.min(Math.max(1, query.limit || 100), 100);
|
|
309
310
|
// Results container.
|
|
310
311
|
const combinedResults = [];
|
|
@@ -364,7 +365,7 @@ class DonobuFlowsManager {
|
|
|
364
365
|
return {
|
|
365
366
|
items: cleanResults,
|
|
366
367
|
nextPageToken: hasMore
|
|
367
|
-
?
|
|
368
|
+
? createCompositePageToken(paginationState)
|
|
368
369
|
: undefined,
|
|
369
370
|
};
|
|
370
371
|
}
|
|
@@ -666,257 +667,48 @@ class DonobuFlowsManager {
|
|
|
666
667
|
return result;
|
|
667
668
|
}
|
|
668
669
|
/**
|
|
669
|
-
*
|
|
670
|
-
* BROWSERBASE_PROJECT_ID and BROWSERBASE_API_KEY environment variables are
|
|
671
|
-
* present, otherwise, returns back a basic config that uses local Chromium.
|
|
672
|
-
*/
|
|
673
|
-
getDefaultBrowserConfig() {
|
|
674
|
-
const browserBaseProjectId = this.environ.data.BROWSERBASE_PROJECT_ID;
|
|
675
|
-
if (browserBaseProjectId && this.environ.data.BROWSERBASE_API_KEY) {
|
|
676
|
-
return {
|
|
677
|
-
initialState: undefined,
|
|
678
|
-
persistState: false,
|
|
679
|
-
using: {
|
|
680
|
-
type: 'browserBase',
|
|
681
|
-
sessionArgs: {
|
|
682
|
-
projectId: browserBaseProjectId,
|
|
683
|
-
browserSettings: {
|
|
684
|
-
advancedStealth: false, // Advanced Stealth is only available on BrowserBase enterprise plans.
|
|
685
|
-
},
|
|
686
|
-
keepAlive: false,
|
|
687
|
-
proxies: false,
|
|
688
|
-
},
|
|
689
|
-
},
|
|
690
|
-
};
|
|
691
|
-
}
|
|
692
|
-
else {
|
|
693
|
-
return {
|
|
694
|
-
initialState: undefined,
|
|
695
|
-
persistState: false,
|
|
696
|
-
using: {
|
|
697
|
-
type: 'device',
|
|
698
|
-
deviceName: 'Desktop Chromium',
|
|
699
|
-
headless: false,
|
|
700
|
-
},
|
|
701
|
-
};
|
|
702
|
-
}
|
|
703
|
-
}
|
|
704
|
-
/**
|
|
705
|
-
* Extracts environment variable names from the given objective and combines
|
|
706
|
-
* it with the given explicitly allowed variables.
|
|
707
|
-
*
|
|
708
|
-
* This function performs two operations:
|
|
709
|
-
* 1. Extracts environment variable references (in the form `$.env.VARIABLE_NAME`) from the overall objective.
|
|
710
|
-
* 2. Combines these with any explicitly allowed environment variable names.
|
|
711
|
-
*
|
|
712
|
-
* The resulting array contains unique environment variable names without duplicates.
|
|
713
|
-
*
|
|
714
|
-
* @param overallObjective - The objective text that may contain environment variable references.
|
|
715
|
-
* @param explicitlyAllowedEnvVariableNames - Additional environment variable names explicitly allowed.
|
|
716
|
-
* @returns An array of unique environment variable names that are allowed to be accessed.
|
|
717
|
-
*
|
|
718
|
-
* @example
|
|
719
|
-
* // Returns ["API_KEY", "USER_NAME", "DEBUG_MODE"]
|
|
720
|
-
* distillAllowedEnvVariableNames(
|
|
721
|
-
* "Use {{$.env.API_KEY}} to authenticate and greet {{$.env.USER_NAME}}",
|
|
722
|
-
* ["API_KEY", "DEBUG_MODE"]
|
|
723
|
-
* );
|
|
670
|
+
* Extracts dependencies for a single flow by analyzing its browser.initialState
|
|
724
671
|
*/
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
return exp.startsWith('$.env.');
|
|
730
|
-
})
|
|
731
|
-
.map((exp) => {
|
|
732
|
-
return exp.substring('$.env.'.length);
|
|
733
|
-
})
|
|
734
|
-
: [];
|
|
735
|
-
// Concatonate that with the explicitly requested environment variables.
|
|
736
|
-
allowedEnvVarsByName = Array.from(new Set(allowedEnvVarsByName.concat(explicitlyAllowedEnvVariableNames ?? [])));
|
|
737
|
-
return allowedEnvVarsByName;
|
|
738
|
-
}
|
|
739
|
-
validateFlowName(flowName) {
|
|
740
|
-
if (flowName && flowName.length > 255) {
|
|
741
|
-
throw new InvalidParamValueException_1.InvalidParamValueException('name', flowName, 'the value cannot be longer than 255 characters');
|
|
742
|
-
}
|
|
743
|
-
}
|
|
744
|
-
async validateFlowParams(flowParams, gptClient, initialRunMode) {
|
|
745
|
-
const validTargetWebsiteProtocols = ['https:', 'http:'];
|
|
746
|
-
const validCallbackUrlProtocols = ['https:', 'http:'];
|
|
747
|
-
const parsedTargetWebsite = DonobuFlowsManager.parseUrl(flowParams.targetWebsite);
|
|
748
|
-
const parsedCallbackUrl = DonobuFlowsManager.parseUrl(flowParams.callbackUrl);
|
|
749
|
-
if (parsedTargetWebsite &&
|
|
750
|
-
!validTargetWebsiteProtocols.some((protocol) => protocol === parsedTargetWebsite.protocol)) {
|
|
751
|
-
throw new InvalidParamValueException_1.InvalidParamValueException('targetWebsite', flowParams.targetWebsite, 'the URL must start with a supported protocol (example: "https://")');
|
|
752
|
-
}
|
|
753
|
-
else if (flowParams.targetWebsite && !parsedTargetWebsite) {
|
|
754
|
-
throw new InvalidParamValueException_1.InvalidParamValueException('targetWebsite', flowParams.targetWebsite, 'the URL is malformed');
|
|
755
|
-
}
|
|
756
|
-
if (parsedCallbackUrl &&
|
|
757
|
-
!validCallbackUrlProtocols.some((protocol) => protocol === parsedCallbackUrl.protocol)) {
|
|
758
|
-
throw new InvalidParamValueException_1.InvalidParamValueException('callbackUrl', flowParams.callbackUrl, 'the URL must start with a supported protocol (example: "https://")');
|
|
759
|
-
}
|
|
760
|
-
else if (flowParams.callbackUrl && !parsedCallbackUrl) {
|
|
761
|
-
throw new InvalidParamValueException_1.InvalidParamValueException('callbackUrl', flowParams.callbackUrl, 'the URL is malformed');
|
|
672
|
+
async extractFlowDependencies(flow, nameToIdMap) {
|
|
673
|
+
const initialState = flow.browser?.initialState;
|
|
674
|
+
if (!initialState) {
|
|
675
|
+
return [];
|
|
762
676
|
}
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
677
|
+
switch (initialState.type) {
|
|
678
|
+
case 'id':
|
|
679
|
+
// Direct flow ID reference
|
|
680
|
+
try {
|
|
681
|
+
await this.getFlowById(initialState.value);
|
|
682
|
+
return [initialState.value];
|
|
768
683
|
}
|
|
769
|
-
|
|
770
|
-
|
|
684
|
+
catch (_error) {
|
|
685
|
+
Logger_1.appLogger.warn(`Flow dependency not found: flow with ID "${initialState.value}" does not exist`);
|
|
686
|
+
return [];
|
|
771
687
|
}
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
688
|
+
case 'name':
|
|
689
|
+
// Flow name reference - resolve to ID
|
|
690
|
+
const flowId = nameToIdMap.get(initialState.value);
|
|
691
|
+
if (flowId) {
|
|
692
|
+
return [flowId];
|
|
693
|
+
}
|
|
694
|
+
// If not in our current map, try to find it by querying all flows
|
|
695
|
+
try {
|
|
696
|
+
const dependentFlow = await this.getFlowByName(initialState.value);
|
|
697
|
+
nameToIdMap.set(initialState.value, dependentFlow.id);
|
|
698
|
+
return [dependentFlow.id];
|
|
699
|
+
}
|
|
700
|
+
catch (_error) {
|
|
701
|
+
Logger_1.appLogger.warn(`Flow dependency not found: flow with name "${initialState.value}" does not exist`);
|
|
702
|
+
return [];
|
|
703
|
+
}
|
|
704
|
+
case 'json':
|
|
705
|
+
// Direct JSON state - no dependencies
|
|
706
|
+
return [];
|
|
777
707
|
default:
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
if (!gptClient) {
|
|
781
|
-
await this.checkIfAnyToolsRequireGpt(flowParams.allowedTools ?? null, flowParams.toolCallsOnStart ?? null);
|
|
782
|
-
}
|
|
783
|
-
}
|
|
784
|
-
async setupAllowedTools(flowParams, hasGptClient) {
|
|
785
|
-
const customTools = flowParams.customTools?.map((tool) => new CustomToolRunnerTool_1.CustomToolRunnerTool(tool)) ??
|
|
786
|
-
[];
|
|
787
|
-
const toolsNeededOnStart = flowParams.toolCallsOnStart?.map((t) => t.name) ?? [];
|
|
788
|
-
let prepackagedTools;
|
|
789
|
-
if (flowParams.allowedTools?.length) {
|
|
790
|
-
const allowedTools = [...toolsNeededOnStart, ...flowParams.allowedTools];
|
|
791
|
-
// The user has specified a list of tools to use.
|
|
792
|
-
prepackagedTools = (await ToolManager_1.ToolManager.allTools()).filter((tool) => allowedTools.includes(tool.name));
|
|
793
|
-
}
|
|
794
|
-
else {
|
|
795
|
-
// The user has not specified a list of tools to use, so use the default.
|
|
796
|
-
const defaultTools = await ToolManager_1.ToolManager.defaultTools();
|
|
797
|
-
const allowedTools = [
|
|
798
|
-
...toolsNeededOnStart,
|
|
799
|
-
...defaultTools.map((t) => t.name),
|
|
800
|
-
];
|
|
801
|
-
prepackagedTools = (await ToolManager_1.ToolManager.allTools()).filter((tool) => allowedTools.includes(tool.name));
|
|
802
|
-
}
|
|
803
|
-
// If there is no GPT client, only include tools that do not require it.
|
|
804
|
-
const prepackagedToolsWithGptFiltered = prepackagedTools.filter((tool) => {
|
|
805
|
-
return hasGptClient || !tool.requiresGpt;
|
|
806
|
-
});
|
|
807
|
-
return [...customTools, ...prepackagedToolsWithGptFiltered];
|
|
808
|
-
}
|
|
809
|
-
prepareInitialToolCalls(flowParams) {
|
|
810
|
-
if (!flowParams.toolCallsOnStart?.length && flowParams.targetWebsite) {
|
|
811
|
-
return [
|
|
812
|
-
{
|
|
813
|
-
name: GoToWebpageTool_1.GoToWebpageTool.NAME,
|
|
814
|
-
parameters: {
|
|
815
|
-
rationale: 'Initializing web navigation.',
|
|
816
|
-
url: flowParams.targetWebsite.toString(),
|
|
817
|
-
},
|
|
818
|
-
},
|
|
819
|
-
];
|
|
820
|
-
}
|
|
821
|
-
if (flowParams.toolCallsOnStart) {
|
|
822
|
-
return flowParams.toolCallsOnStart;
|
|
823
|
-
}
|
|
824
|
-
else {
|
|
825
|
-
return [];
|
|
826
|
-
}
|
|
827
|
-
}
|
|
828
|
-
/**
|
|
829
|
-
* This method creates a temporary directory for the flow with the given ID,
|
|
830
|
-
* returning the path to the directory.
|
|
831
|
-
*/
|
|
832
|
-
createTempDirectoryForFlow(flowId) {
|
|
833
|
-
const tempDir = path.join((0, os_1.tmpdir)(), flowId);
|
|
834
|
-
fs.mkdirSync(tempDir);
|
|
835
|
-
return tempDir;
|
|
836
|
-
}
|
|
837
|
-
removeTempDirectoryForFlow(flowId) {
|
|
838
|
-
try {
|
|
839
|
-
const tempDir = path.join((0, os_1.tmpdir)(), flowId);
|
|
840
|
-
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
841
|
-
}
|
|
842
|
-
catch (error) {
|
|
843
|
-
Logger_1.appLogger.error('Failed to remove temporary directory:', error);
|
|
844
|
-
}
|
|
845
|
-
}
|
|
846
|
-
/**
|
|
847
|
-
* Searches the given directory for the largest video file and sets it as the
|
|
848
|
-
* flow's video. This should be called after the flow has completed.
|
|
849
|
-
*/
|
|
850
|
-
async setFlowVideo(flowId, flowTempDir, flowsPersistence) {
|
|
851
|
-
const files = fs
|
|
852
|
-
.readdirSync(flowTempDir)
|
|
853
|
-
.filter((file) => file.endsWith('.webm'))
|
|
854
|
-
.map((file) => path.join(flowTempDir, file));
|
|
855
|
-
const videoPath = files.length
|
|
856
|
-
? files.reduce((a, b) => fs.statSync(a).size > fs.statSync(b).size ? a : b)
|
|
857
|
-
: null;
|
|
858
|
-
if (videoPath) {
|
|
859
|
-
const videoBytes = fs.readFileSync(videoPath);
|
|
860
|
-
await flowsPersistence.setVideo(flowId, videoBytes);
|
|
861
|
-
}
|
|
862
|
-
}
|
|
863
|
-
isLocallyRunning() {
|
|
864
|
-
return this.deploymentEnvironment === 'LOCAL';
|
|
865
|
-
}
|
|
866
|
-
async checkIfAnyToolsRequireGpt(requestedTools, toolCallsOnStart) {
|
|
867
|
-
const toolMap = new Map((await ToolManager_1.ToolManager.allTools()).map((tool) => [tool.name, tool]));
|
|
868
|
-
const requestedToolsRequiringGpt = [...(requestedTools ?? [])].filter((name) => toolMap.get(name)?.requiresGpt);
|
|
869
|
-
if (requestedToolsRequiringGpt.length) {
|
|
870
|
-
throw new ToolRequiresGptException_1.ToolRequiresGptException(requestedToolsRequiringGpt[0]);
|
|
871
|
-
}
|
|
872
|
-
const toolCallsRequiringGpt = toolCallsOnStart?.filter((call) => toolMap.get(call.name)?.requiresGpt);
|
|
873
|
-
if (toolCallsRequiringGpt?.length) {
|
|
874
|
-
throw new ToolRequiresGptException_1.ToolRequiresGptException(toolCallsRequiringGpt[0].name);
|
|
875
|
-
}
|
|
876
|
-
}
|
|
877
|
-
/**
|
|
878
|
-
* Parses the given argument as a URL, returning null on failure.
|
|
879
|
-
*/
|
|
880
|
-
static parseUrl(url) {
|
|
881
|
-
if (!url) {
|
|
882
|
-
return null;
|
|
883
|
-
}
|
|
884
|
-
try {
|
|
885
|
-
return new URL(url);
|
|
886
|
-
}
|
|
887
|
-
catch (_) {
|
|
888
|
-
return null;
|
|
889
|
-
}
|
|
890
|
-
}
|
|
891
|
-
/**
|
|
892
|
-
* Parse a composite page token into pagination state
|
|
893
|
-
*/
|
|
894
|
-
parseCompositePageToken(token) {
|
|
895
|
-
if (!token) {
|
|
896
|
-
return {
|
|
897
|
-
sourceTokens: {},
|
|
898
|
-
exhaustedSources: [],
|
|
899
|
-
cursorTimestamp: null,
|
|
900
|
-
};
|
|
901
|
-
}
|
|
902
|
-
try {
|
|
903
|
-
return JSON.parse(Buffer.from(token, 'base64').toString('utf8'));
|
|
904
|
-
}
|
|
905
|
-
catch (_error) {
|
|
906
|
-
// If token parsing fails, start fresh
|
|
907
|
-
return {
|
|
908
|
-
sourceTokens: {},
|
|
909
|
-
exhaustedSources: [],
|
|
910
|
-
cursorTimestamp: null,
|
|
911
|
-
};
|
|
708
|
+
Logger_1.appLogger.warn(`Unknown browser state reference type: ${initialState.type}`);
|
|
709
|
+
return [];
|
|
912
710
|
}
|
|
913
711
|
}
|
|
914
|
-
/**
|
|
915
|
-
* Create a composite page token from pagination state
|
|
916
|
-
*/
|
|
917
|
-
createCompositePageToken(state) {
|
|
918
|
-
return Buffer.from(JSON.stringify(state)).toString('base64');
|
|
919
|
-
}
|
|
920
712
|
/**
|
|
921
713
|
* Resolves the complete set of flow IDs including all transitive dependencies.
|
|
922
714
|
* Uses breadth-first search to discover all dependencies recursively.
|
|
@@ -954,54 +746,11 @@ class DonobuFlowsManager {
|
|
|
954
746
|
}
|
|
955
747
|
catch (_error) {
|
|
956
748
|
// If a flow doesn't exist, skip it but continue processing
|
|
957
|
-
|
|
749
|
+
Logger_1.appLogger.warn(`Flow ${currentFlowId} not found, skipping dependency resolution for this flow`);
|
|
958
750
|
}
|
|
959
751
|
}
|
|
960
752
|
return Array.from(resolvedFlowIds);
|
|
961
753
|
}
|
|
962
|
-
/**
|
|
963
|
-
* Extracts dependencies for a single flow by analyzing its browser.initialState
|
|
964
|
-
*/
|
|
965
|
-
async extractFlowDependencies(flow, nameToIdMap) {
|
|
966
|
-
const initialState = flow.browser?.initialState;
|
|
967
|
-
if (!initialState) {
|
|
968
|
-
return [];
|
|
969
|
-
}
|
|
970
|
-
switch (initialState.type) {
|
|
971
|
-
case 'id':
|
|
972
|
-
// Direct flow ID reference
|
|
973
|
-
try {
|
|
974
|
-
await this.getFlowById(initialState.value);
|
|
975
|
-
return [initialState.value];
|
|
976
|
-
}
|
|
977
|
-
catch (_error) {
|
|
978
|
-
console.warn(`Flow dependency not found: flow with ID "${initialState.value}" does not exist`);
|
|
979
|
-
return [];
|
|
980
|
-
}
|
|
981
|
-
case 'name':
|
|
982
|
-
// Flow name reference - resolve to ID
|
|
983
|
-
const flowId = nameToIdMap.get(initialState.value);
|
|
984
|
-
if (flowId) {
|
|
985
|
-
return [flowId];
|
|
986
|
-
}
|
|
987
|
-
// If not in our current map, try to find it by querying all flows
|
|
988
|
-
try {
|
|
989
|
-
const dependentFlow = await this.getFlowByName(initialState.value);
|
|
990
|
-
nameToIdMap.set(initialState.value, dependentFlow.id);
|
|
991
|
-
return [dependentFlow.id];
|
|
992
|
-
}
|
|
993
|
-
catch (_error) {
|
|
994
|
-
console.warn(`Flow dependency not found: flow with name "${initialState.value}" does not exist`);
|
|
995
|
-
return [];
|
|
996
|
-
}
|
|
997
|
-
case 'json':
|
|
998
|
-
// Direct JSON state - no dependencies
|
|
999
|
-
return [];
|
|
1000
|
-
default:
|
|
1001
|
-
console.warn(`Unknown browser state reference type: ${initialState.type}`);
|
|
1002
|
-
return [];
|
|
1003
|
-
}
|
|
1004
|
-
}
|
|
1005
754
|
/**
|
|
1006
755
|
* Determines if a new flow ID should replace an existing flow ID in the name mapping.
|
|
1007
756
|
*/
|
|
@@ -1016,9 +765,281 @@ class DonobuFlowsManager {
|
|
|
1016
765
|
return true;
|
|
1017
766
|
}
|
|
1018
767
|
}
|
|
768
|
+
isLocallyRunning() {
|
|
769
|
+
return this.deploymentEnvironment === 'LOCAL';
|
|
770
|
+
}
|
|
1019
771
|
}
|
|
1020
772
|
exports.DonobuFlowsManager = DonobuFlowsManager;
|
|
1021
773
|
DonobuFlowsManager.DEFAULT_MESSAGE_DURATION = 2247;
|
|
1022
774
|
DonobuFlowsManager.DEFAULT_MAX_TOOL_CALLS = 50;
|
|
1023
775
|
DonobuFlowsManager.DEFAULT_BROWSER_STATE_FILENAME = 'browserstate.json';
|
|
776
|
+
/**
|
|
777
|
+
* Extracts environment variable names from the given objective and combines
|
|
778
|
+
* it with the given explicitly allowed variables.
|
|
779
|
+
*
|
|
780
|
+
* This function performs two operations:
|
|
781
|
+
* 1. Extracts environment variable references (in the form `$.env.VARIABLE_NAME`) from the overall objective.
|
|
782
|
+
* 2. Combines these with any explicitly allowed environment variable names.
|
|
783
|
+
*
|
|
784
|
+
* The resulting array contains unique environment variable names without duplicates.
|
|
785
|
+
*
|
|
786
|
+
* @param overallObjective - The objective text that may contain environment variable references.
|
|
787
|
+
* @param explicitlyAllowedEnvVariableNames - Additional environment variable names explicitly allowed.
|
|
788
|
+
* @returns An array of unique environment variable names that are allowed to be accessed.
|
|
789
|
+
*
|
|
790
|
+
* @example
|
|
791
|
+
* // Returns ["API_KEY", "USER_NAME", "DEBUG_MODE"]
|
|
792
|
+
* distillAllowedEnvVariableNames(
|
|
793
|
+
* "Use {{$.env.API_KEY}} to authenticate and greet {{$.env.USER_NAME}}",
|
|
794
|
+
* ["API_KEY", "DEBUG_MODE"]
|
|
795
|
+
* );
|
|
796
|
+
*/
|
|
797
|
+
function distillAllowedEnvVariableNames(overallObjective, explicitlyAllowedEnvVariableNames) {
|
|
798
|
+
let allowedEnvVarsByName = overallObjective
|
|
799
|
+
? (0, TemplateInterpolator_1.extractInterpolationExpressions)(overallObjective)
|
|
800
|
+
.filter((exp) => {
|
|
801
|
+
return exp.startsWith('$.env.');
|
|
802
|
+
})
|
|
803
|
+
.map((exp) => {
|
|
804
|
+
return exp.substring('$.env.'.length);
|
|
805
|
+
})
|
|
806
|
+
: [];
|
|
807
|
+
// Concatonate that with the explicitly requested environment variables.
|
|
808
|
+
allowedEnvVarsByName = Array.from(new Set(allowedEnvVarsByName.concat(explicitlyAllowedEnvVariableNames ?? [])));
|
|
809
|
+
return allowedEnvVarsByName;
|
|
810
|
+
}
|
|
811
|
+
/**
|
|
812
|
+
* Returns a browser config that points to BrowserBase if the
|
|
813
|
+
* BROWSERBASE_PROJECT_ID and BROWSERBASE_API_KEY environment variables are
|
|
814
|
+
* present, otherwise, returns back a basic config that uses local Chromium.
|
|
815
|
+
*/
|
|
816
|
+
function getDefaultBrowserConfig(environ) {
|
|
817
|
+
const browserBaseProjectId = environ.data.BROWSERBASE_PROJECT_ID;
|
|
818
|
+
if (browserBaseProjectId && environ.data.BROWSERBASE_API_KEY) {
|
|
819
|
+
return {
|
|
820
|
+
initialState: undefined,
|
|
821
|
+
persistState: false,
|
|
822
|
+
using: {
|
|
823
|
+
type: 'browserBase',
|
|
824
|
+
sessionArgs: {
|
|
825
|
+
projectId: browserBaseProjectId,
|
|
826
|
+
browserSettings: {
|
|
827
|
+
advancedStealth: false, // Advanced Stealth is only available on BrowserBase enterprise plans.
|
|
828
|
+
},
|
|
829
|
+
keepAlive: false,
|
|
830
|
+
proxies: false,
|
|
831
|
+
},
|
|
832
|
+
},
|
|
833
|
+
};
|
|
834
|
+
}
|
|
835
|
+
else {
|
|
836
|
+
return {
|
|
837
|
+
initialState: undefined,
|
|
838
|
+
persistState: false,
|
|
839
|
+
using: {
|
|
840
|
+
type: 'device',
|
|
841
|
+
deviceName: 'Desktop Chromium',
|
|
842
|
+
headless: false,
|
|
843
|
+
},
|
|
844
|
+
};
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
/**
|
|
848
|
+
* Parses the given argument as a URL, returning null on failure.
|
|
849
|
+
*/
|
|
850
|
+
function parseUrl(url) {
|
|
851
|
+
if (!url) {
|
|
852
|
+
return null;
|
|
853
|
+
}
|
|
854
|
+
try {
|
|
855
|
+
return new URL(url);
|
|
856
|
+
}
|
|
857
|
+
catch (_) {
|
|
858
|
+
return null;
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
/**
|
|
862
|
+
* Create a composite page token from pagination state
|
|
863
|
+
*/
|
|
864
|
+
function createCompositePageToken(state) {
|
|
865
|
+
return Buffer.from(JSON.stringify(state)).toString('base64');
|
|
866
|
+
}
|
|
867
|
+
function validateFlowName(flowName) {
|
|
868
|
+
if (flowName && flowName.length > 255) {
|
|
869
|
+
throw new InvalidParamValueException_1.InvalidParamValueException('name', flowName, 'the value cannot be longer than 255 characters');
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
async function validateFlowParams(flowParams, gptClient, initialRunMode) {
|
|
873
|
+
const validTargetWebsiteProtocols = ['https:', 'http:'];
|
|
874
|
+
const validCallbackUrlProtocols = ['https:', 'http:'];
|
|
875
|
+
const parsedTargetWebsite = parseUrl(flowParams.targetWebsite);
|
|
876
|
+
const parsedCallbackUrl = parseUrl(flowParams.callbackUrl);
|
|
877
|
+
if (parsedTargetWebsite &&
|
|
878
|
+
!validTargetWebsiteProtocols.some((protocol) => protocol === parsedTargetWebsite.protocol)) {
|
|
879
|
+
throw new InvalidParamValueException_1.InvalidParamValueException('targetWebsite', flowParams.targetWebsite, 'the URL must start with a supported protocol (example: "https://")');
|
|
880
|
+
}
|
|
881
|
+
else if (flowParams.targetWebsite && !parsedTargetWebsite) {
|
|
882
|
+
throw new InvalidParamValueException_1.InvalidParamValueException('targetWebsite', flowParams.targetWebsite, 'the URL is malformed');
|
|
883
|
+
}
|
|
884
|
+
if (parsedCallbackUrl &&
|
|
885
|
+
!validCallbackUrlProtocols.some((protocol) => protocol === parsedCallbackUrl.protocol)) {
|
|
886
|
+
throw new InvalidParamValueException_1.InvalidParamValueException('callbackUrl', flowParams.callbackUrl, 'the URL must start with a supported protocol (example: "https://")');
|
|
887
|
+
}
|
|
888
|
+
else if (flowParams.callbackUrl && !parsedCallbackUrl) {
|
|
889
|
+
throw new InvalidParamValueException_1.InvalidParamValueException('callbackUrl', flowParams.callbackUrl, 'the URL is malformed');
|
|
890
|
+
}
|
|
891
|
+
validateFlowName(flowParams.name);
|
|
892
|
+
switch (initialRunMode) {
|
|
893
|
+
case 'AUTONOMOUS':
|
|
894
|
+
if ((flowParams.overallObjective?.trim().length ?? 0) === 0) {
|
|
895
|
+
throw new InvalidParamValueException_1.InvalidParamValueException('overallObjective', flowParams.overallObjective, `'initialRunMode' has a value of '${initialRunMode}'`);
|
|
896
|
+
}
|
|
897
|
+
if (!gptClient) {
|
|
898
|
+
throw new InvalidParamValueException_1.InvalidParamValueException('initialRunMode', initialRunMode, `no GPT client is available`);
|
|
899
|
+
}
|
|
900
|
+
break;
|
|
901
|
+
case 'INSTRUCT':
|
|
902
|
+
break;
|
|
903
|
+
case 'DETERMINISTIC':
|
|
904
|
+
break;
|
|
905
|
+
default:
|
|
906
|
+
throw new InvalidParamValueException_1.InvalidParamValueException('initialRunMode', initialRunMode);
|
|
907
|
+
}
|
|
908
|
+
if (!gptClient) {
|
|
909
|
+
await throwIfAnyToolsRequireGpt(flowParams.allowedTools ?? null, flowParams.toolCallsOnStart ?? null);
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
async function setupAllowedTools(flowParams, hasGptClient) {
|
|
913
|
+
const customTools = flowParams.customTools?.map((tool) => new CustomToolRunnerTool_1.CustomToolRunnerTool(tool)) ?? [];
|
|
914
|
+
const toolsNeededOnStart = flowParams.toolCallsOnStart?.map((t) => t.name) ?? [];
|
|
915
|
+
let prepackagedTools;
|
|
916
|
+
if (flowParams.allowedTools?.length) {
|
|
917
|
+
const allowedTools = [...toolsNeededOnStart, ...flowParams.allowedTools];
|
|
918
|
+
// The user has specified a list of tools to use.
|
|
919
|
+
prepackagedTools = (await ToolManager_1.ToolManager.allTools()).filter((tool) => allowedTools.includes(tool.name));
|
|
920
|
+
}
|
|
921
|
+
else {
|
|
922
|
+
// The user has not specified a list of tools to use, so use the default.
|
|
923
|
+
const defaultTools = await ToolManager_1.ToolManager.defaultTools();
|
|
924
|
+
const allowedTools = [
|
|
925
|
+
...toolsNeededOnStart,
|
|
926
|
+
...defaultTools.map((t) => t.name),
|
|
927
|
+
];
|
|
928
|
+
prepackagedTools = (await ToolManager_1.ToolManager.allTools()).filter((tool) => allowedTools.includes(tool.name));
|
|
929
|
+
}
|
|
930
|
+
// If there is no GPT client, only include tools that do not require it.
|
|
931
|
+
const prepackagedToolsWithGptFiltered = prepackagedTools.filter((tool) => {
|
|
932
|
+
return hasGptClient || !tool.requiresGpt;
|
|
933
|
+
});
|
|
934
|
+
const minimalTools = await ToolManager_1.ToolManager.minimalTools();
|
|
935
|
+
const existingToolNames = new Set([...customTools, ...prepackagedToolsWithGptFiltered].map((tool) => tool.name));
|
|
936
|
+
const missingMinimalTools = minimalTools.filter((tool) => !existingToolNames.has(tool.name));
|
|
937
|
+
const combinedTools = [
|
|
938
|
+
...customTools,
|
|
939
|
+
...prepackagedToolsWithGptFiltered,
|
|
940
|
+
...missingMinimalTools,
|
|
941
|
+
];
|
|
942
|
+
const dedupedTools = Array.from(combinedTools
|
|
943
|
+
.reduce((uniqueTools, tool) => {
|
|
944
|
+
if (!uniqueTools.has(tool.name)) {
|
|
945
|
+
uniqueTools.set(tool.name, tool);
|
|
946
|
+
}
|
|
947
|
+
return uniqueTools;
|
|
948
|
+
}, new Map())
|
|
949
|
+
.values());
|
|
950
|
+
return dedupedTools.sort((a, b) => a.name.localeCompare(b.name));
|
|
951
|
+
}
|
|
952
|
+
function prepareInitialToolCalls(flowParams) {
|
|
953
|
+
if (!flowParams.toolCallsOnStart?.length && flowParams.targetWebsite) {
|
|
954
|
+
return [
|
|
955
|
+
{
|
|
956
|
+
name: GoToWebpageTool_1.GoToWebpageTool.NAME,
|
|
957
|
+
parameters: {
|
|
958
|
+
rationale: 'Initializing web navigation.',
|
|
959
|
+
url: flowParams.targetWebsite.toString(),
|
|
960
|
+
},
|
|
961
|
+
},
|
|
962
|
+
];
|
|
963
|
+
}
|
|
964
|
+
if (flowParams.toolCallsOnStart) {
|
|
965
|
+
return flowParams.toolCallsOnStart;
|
|
966
|
+
}
|
|
967
|
+
else {
|
|
968
|
+
return [];
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
/**
|
|
972
|
+
* This method creates a temporary directory for the flow with the given ID,
|
|
973
|
+
* returning the path to the directory.
|
|
974
|
+
*/
|
|
975
|
+
async function createTempDirectoryForFlow(flowId) {
|
|
976
|
+
const tempDir = path.join((0, os_1.tmpdir)(), flowId);
|
|
977
|
+
await fs.mkdir(tempDir);
|
|
978
|
+
return tempDir;
|
|
979
|
+
}
|
|
980
|
+
async function removeTempDirectoryForFlow(flowId) {
|
|
981
|
+
try {
|
|
982
|
+
const tempDir = path.join((0, os_1.tmpdir)(), flowId);
|
|
983
|
+
await fs.rm(tempDir, { recursive: true, force: true });
|
|
984
|
+
}
|
|
985
|
+
catch (error) {
|
|
986
|
+
Logger_1.appLogger.error('Failed to remove temporary directory:', error);
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
/**
|
|
990
|
+
* Searches the given directory for the largest video file and sets it as the
|
|
991
|
+
* flow's video. This should be called after the flow has completed.
|
|
992
|
+
*/
|
|
993
|
+
async function setFlowVideo(flowId, flowTempDir, flowsPersistence) {
|
|
994
|
+
const files = (await fs.readdir(flowTempDir))
|
|
995
|
+
.filter((file) => file.endsWith('.webm'))
|
|
996
|
+
.map((file) => path.join(flowTempDir, file));
|
|
997
|
+
if (!files.length) {
|
|
998
|
+
return;
|
|
999
|
+
}
|
|
1000
|
+
const filesWithSizes = await Promise.all(files.map(async (filePath) => ({
|
|
1001
|
+
filePath,
|
|
1002
|
+
size: (await fs.stat(filePath)).size,
|
|
1003
|
+
})));
|
|
1004
|
+
const largestFile = filesWithSizes.reduce((largest, current) => current.size > largest.size ? current : largest);
|
|
1005
|
+
const videoPath = largestFile?.filePath ?? null;
|
|
1006
|
+
if (videoPath) {
|
|
1007
|
+
const videoBytes = await fs.readFile(videoPath);
|
|
1008
|
+
await flowsPersistence.setVideo(flowId, videoBytes);
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
async function throwIfAnyToolsRequireGpt(requestedTools, toolCallsOnStart) {
|
|
1012
|
+
const toolMap = new Map((await ToolManager_1.ToolManager.allTools()).map((tool) => [tool.name, tool]));
|
|
1013
|
+
const requestedToolsRequiringGpt = [...(requestedTools ?? [])].filter((name) => toolMap.get(name)?.requiresGpt);
|
|
1014
|
+
if (requestedToolsRequiringGpt.length) {
|
|
1015
|
+
throw new ToolRequiresGptException_1.ToolRequiresGptException(requestedToolsRequiringGpt[0]);
|
|
1016
|
+
}
|
|
1017
|
+
const toolCallsRequiringGpt = toolCallsOnStart?.filter((call) => toolMap.get(call.name)?.requiresGpt);
|
|
1018
|
+
if (toolCallsRequiringGpt?.length) {
|
|
1019
|
+
throw new ToolRequiresGptException_1.ToolRequiresGptException(toolCallsRequiringGpt[0].name);
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
/**
|
|
1023
|
+
* Parse a composite page token into pagination state
|
|
1024
|
+
*/
|
|
1025
|
+
function parseCompositePageToken(token) {
|
|
1026
|
+
if (!token) {
|
|
1027
|
+
return {
|
|
1028
|
+
sourceTokens: {},
|
|
1029
|
+
exhaustedSources: [],
|
|
1030
|
+
cursorTimestamp: null,
|
|
1031
|
+
};
|
|
1032
|
+
}
|
|
1033
|
+
try {
|
|
1034
|
+
return JSON.parse(Buffer.from(token, 'base64').toString('utf8'));
|
|
1035
|
+
}
|
|
1036
|
+
catch (_error) {
|
|
1037
|
+
// If token parsing fails, start fresh
|
|
1038
|
+
return {
|
|
1039
|
+
sourceTokens: {},
|
|
1040
|
+
exhaustedSources: [],
|
|
1041
|
+
cursorTimestamp: null,
|
|
1042
|
+
};
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1024
1045
|
//# sourceMappingURL=DonobuFlowsManager.js.map
|