donobu 5.18.2 → 5.19.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/clients/GptClientFactory.js +3 -0
- package/dist/clients/OllamaGptClient.d.ts +29 -0
- package/dist/clients/OllamaGptClient.js +76 -0
- package/dist/codegen/runGenerateSiteTests.js +1 -1
- package/dist/envVars.d.ts +4 -0
- package/dist/envVars.js +7 -0
- package/dist/esm/clients/GptClientFactory.js +3 -0
- package/dist/esm/clients/OllamaGptClient.d.ts +29 -0
- package/dist/esm/clients/OllamaGptClient.js +76 -0
- package/dist/esm/codegen/runGenerateSiteTests.js +1 -1
- package/dist/esm/envVars.d.ts +4 -0
- package/dist/esm/envVars.js +7 -0
- package/dist/esm/lib/test/fixtures/gptClients.d.ts +1 -0
- package/dist/esm/lib/test/fixtures/gptClients.js +11 -0
- package/dist/esm/lib/test/testExtension.js +6 -0
- package/dist/esm/lib/test/utils/donobuTestStack.js +1 -1
- package/dist/esm/managers/AdminApiController.d.ts +1 -1
- package/dist/esm/managers/DonobuFlowsManager.d.ts +3 -2
- package/dist/esm/managers/DonobuFlowsManager.js +11 -1
- package/dist/esm/managers/DonobuStack.d.ts +4 -0
- package/dist/esm/managers/DonobuStack.js +1 -1
- package/dist/esm/managers/WebTargetInspector.js +2 -75
- package/dist/esm/models/GptConfig.d.ts +14 -0
- package/dist/esm/models/GptConfig.js +7 -1
- package/dist/esm/utils/PageLogListeners.d.ts +15 -0
- package/dist/esm/utils/PageLogListeners.js +94 -0
- package/dist/lib/test/fixtures/gptClients.d.ts +1 -0
- package/dist/lib/test/fixtures/gptClients.js +11 -0
- package/dist/lib/test/testExtension.js +6 -0
- package/dist/lib/test/utils/donobuTestStack.js +1 -1
- package/dist/managers/AdminApiController.d.ts +1 -1
- package/dist/managers/DonobuFlowsManager.d.ts +3 -2
- package/dist/managers/DonobuFlowsManager.js +11 -1
- package/dist/managers/DonobuStack.d.ts +4 -0
- package/dist/managers/DonobuStack.js +1 -1
- package/dist/managers/WebTargetInspector.js +2 -75
- package/dist/models/GptConfig.d.ts +14 -0
- package/dist/models/GptConfig.js +7 -1
- package/dist/utils/PageLogListeners.d.ts +15 -0
- package/dist/utils/PageLogListeners.js +94 -0
- package/package.json +1 -1
|
@@ -7,6 +7,7 @@ const AnthropicGptClient_1 = require("./AnthropicGptClient");
|
|
|
7
7
|
const DonobuGptClient_1 = require("./DonobuGptClient");
|
|
8
8
|
const GoogleGenerativeAiGptClient_1 = require("./GoogleGenerativeAiGptClient");
|
|
9
9
|
const GptClientPlugin_1 = require("./GptClientPlugin");
|
|
10
|
+
const OllamaGptClient_1 = require("./OllamaGptClient");
|
|
10
11
|
const OpenAiGptClient_1 = require("./OpenAiGptClient");
|
|
11
12
|
/**
|
|
12
13
|
* Default implementation of GptClientFactory that creates GPT clients
|
|
@@ -51,6 +52,8 @@ class GptClientFactoryImpl {
|
|
|
51
52
|
return new DonobuGptClient_1.DonobuGptClient(config);
|
|
52
53
|
case 'GOOGLE_GEMINI':
|
|
53
54
|
return new GoogleGenerativeAiGptClient_1.GoogleGenerativeAiGptClient(config);
|
|
55
|
+
case 'OLLAMA':
|
|
56
|
+
return new OllamaGptClient_1.OllamaGptClient(config);
|
|
54
57
|
case 'OPENAI':
|
|
55
58
|
return new OpenAiGptClient_1.OpenAiGptClient(config);
|
|
56
59
|
default:
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { ZodType } from 'zod/v4';
|
|
2
|
+
import type { OllamaConfig } from '../models/GptConfig';
|
|
3
|
+
import type { AssistantMessage, GptMessage, ProposedToolCallsMessage, StructuredOutputMessage } from '../models/GptMessage';
|
|
4
|
+
import type { ToolOption } from './GptClient';
|
|
5
|
+
import { GptClient } from './GptClient';
|
|
6
|
+
/**
|
|
7
|
+
* A GPT client for Ollama, a local LLM runner that exposes an OpenAI-compatible API.
|
|
8
|
+
* Delegates to {@link OpenAiGptClient} for request handling, with Ollama-specific
|
|
9
|
+
* overrides for ping and structured output.
|
|
10
|
+
*/
|
|
11
|
+
export declare class OllamaGptClient extends GptClient {
|
|
12
|
+
private static readonly DEFAULT_API_URL;
|
|
13
|
+
private readonly delegate;
|
|
14
|
+
private readonly apiUrl;
|
|
15
|
+
constructor(ollamaConfig: OllamaConfig);
|
|
16
|
+
ping(options?: {
|
|
17
|
+
signal?: AbortSignal;
|
|
18
|
+
}): Promise<void>;
|
|
19
|
+
getMessage(messages: GptMessage[], options?: {
|
|
20
|
+
signal?: AbortSignal;
|
|
21
|
+
}): Promise<AssistantMessage>;
|
|
22
|
+
getStructuredOutput<T>(messages: GptMessage[], zodSchema: ZodType<T>, options?: {
|
|
23
|
+
signal?: AbortSignal;
|
|
24
|
+
}): Promise<StructuredOutputMessage<T>>;
|
|
25
|
+
getToolCalls(messages: GptMessage[], tools: ToolOption[], options?: {
|
|
26
|
+
signal?: AbortSignal;
|
|
27
|
+
}): Promise<ProposedToolCallsMessage>;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=OllamaGptClient.d.ts.map
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OllamaGptClient = void 0;
|
|
4
|
+
const GptModelNotFoundException_1 = require("../exceptions/GptModelNotFoundException");
|
|
5
|
+
const GptPlatformNotReachableException_1 = require("../exceptions/GptPlatformNotReachableException");
|
|
6
|
+
const Logger_1 = require("../utils/Logger");
|
|
7
|
+
const GptClient_1 = require("./GptClient");
|
|
8
|
+
const OpenAiGptClient_1 = require("./OpenAiGptClient");
|
|
9
|
+
/**
|
|
10
|
+
* A GPT client for Ollama, a local LLM runner that exposes an OpenAI-compatible API.
|
|
11
|
+
* Delegates to {@link OpenAiGptClient} for request handling, with Ollama-specific
|
|
12
|
+
* overrides for ping and structured output.
|
|
13
|
+
*/
|
|
14
|
+
class OllamaGptClient extends GptClient_1.GptClient {
|
|
15
|
+
constructor(ollamaConfig) {
|
|
16
|
+
super(ollamaConfig);
|
|
17
|
+
this.apiUrl = ollamaConfig.apiUrl ?? OllamaGptClient.DEFAULT_API_URL;
|
|
18
|
+
this.delegate = new OpenAiGptClient_1.OpenAiGptClient({
|
|
19
|
+
type: 'OPENAI',
|
|
20
|
+
modelName: ollamaConfig.modelName,
|
|
21
|
+
apiKey: 'ollama',
|
|
22
|
+
}, this.apiUrl);
|
|
23
|
+
}
|
|
24
|
+
async ping(options) {
|
|
25
|
+
const signal = options?.signal ?? AbortSignal.timeout(10_000);
|
|
26
|
+
let resp;
|
|
27
|
+
try {
|
|
28
|
+
resp = await fetch(`${this.apiUrl}/api/tags`, { signal });
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
if (error instanceof TypeError) {
|
|
32
|
+
Logger_1.appLogger.error('Failed to reach Ollama due to exception', error);
|
|
33
|
+
throw new GptPlatformNotReachableException_1.GptPlatformNotReachableException(this.config.type);
|
|
34
|
+
}
|
|
35
|
+
throw error;
|
|
36
|
+
}
|
|
37
|
+
if (!resp.ok) {
|
|
38
|
+
throw new GptPlatformNotReachableException_1.GptPlatformNotReachableException(this.config.type);
|
|
39
|
+
}
|
|
40
|
+
const data = (await resp.json());
|
|
41
|
+
const models = data.models ?? [];
|
|
42
|
+
const modelName = this.config.modelName;
|
|
43
|
+
const found = models.some((m) => {
|
|
44
|
+
const name = m.name ?? '';
|
|
45
|
+
return name === modelName || name === `${modelName}:latest`;
|
|
46
|
+
});
|
|
47
|
+
if (!found) {
|
|
48
|
+
throw new GptModelNotFoundException_1.GptModelNotFoundException(this.config.type, modelName);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
async getMessage(messages, options) {
|
|
52
|
+
return this.delegate.getMessage(messages, options);
|
|
53
|
+
}
|
|
54
|
+
async getStructuredOutput(messages, zodSchema, options) {
|
|
55
|
+
const resp = await this.getToolCalls(messages, [
|
|
56
|
+
{
|
|
57
|
+
name: 'output',
|
|
58
|
+
description: 'The schema of the expected response structure.',
|
|
59
|
+
inputSchema: zodSchema,
|
|
60
|
+
},
|
|
61
|
+
], options);
|
|
62
|
+
const toolCall = resp.proposedToolCalls.at(0);
|
|
63
|
+
return {
|
|
64
|
+
completionTokensUsed: resp.completionTokensUsed,
|
|
65
|
+
promptTokensUsed: resp.promptTokensUsed,
|
|
66
|
+
type: 'structured_output',
|
|
67
|
+
output: (0, GptClient_1.parseOrLogAndThrow)(toolCall?.parameters, zodSchema),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
async getToolCalls(messages, tools, options) {
|
|
71
|
+
return this.delegate.getToolCalls(messages, tools, options);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
exports.OllamaGptClient = OllamaGptClient;
|
|
75
|
+
OllamaGptClient.DEFAULT_API_URL = 'http://localhost:11434';
|
|
76
|
+
//# sourceMappingURL=OllamaGptClient.js.map
|
|
@@ -769,7 +769,7 @@ async function runGenerateSiteTests(opts, onProgress, shouldCancel) {
|
|
|
769
769
|
}
|
|
770
770
|
const storageState = await loadStorageState(storageStatePath);
|
|
771
771
|
assertNotCancelled('loading storage state');
|
|
772
|
-
const donobuStack = await (0, DonobuStack_1.setupDonobuStack)('LOCAL', ControlPanel_1.NoOpControlPanelFactory, new EnvPersistenceVolatile_1.EnvPersistenceVolatile(snapshotEnv()), envVars_1.env.pick('ANTHROPIC_API_KEY', 'ANTHROPIC_MODEL_NAME', 'AWS_ACCESS_KEY_ID', 'AWS_BEDROCK_MODEL_NAME', 'AWS_REGION', 'AWS_S3_BUCKET', 'AWS_S3_REGION', 'AWS_SECRET_ACCESS_KEY', 'BASE64_GPT_CONFIG', 'BROWSERBASE_API_KEY', 'BROWSERBASE_PROJECT_ID', 'DONOBU_API_BASE_URL', 'DONOBU_API_KEY', 'GOOGLE_GENERATIVE_AI_API_KEY', 'GOOGLE_GENERATIVE_AI_MODEL_NAME', 'GOOGLE_CLOUD_STORAGE_BUCKET', 'OPENAI_API_KEY', 'OPENAI_API_MODEL_NAME', 'PERSISTENCE_PRIORITY'));
|
|
772
|
+
const donobuStack = await (0, DonobuStack_1.setupDonobuStack)('LOCAL', ControlPanel_1.NoOpControlPanelFactory, new EnvPersistenceVolatile_1.EnvPersistenceVolatile(snapshotEnv()), envVars_1.env.pick('ANTHROPIC_API_KEY', 'ANTHROPIC_MODEL_NAME', 'AWS_ACCESS_KEY_ID', 'AWS_BEDROCK_MODEL_NAME', 'AWS_REGION', 'AWS_S3_BUCKET', 'AWS_S3_REGION', 'AWS_SECRET_ACCESS_KEY', 'BASE64_GPT_CONFIG', 'BROWSERBASE_API_KEY', 'BROWSERBASE_PROJECT_ID', 'DONOBU_API_BASE_URL', 'DONOBU_API_KEY', 'GOOGLE_GENERATIVE_AI_API_KEY', 'GOOGLE_GENERATIVE_AI_MODEL_NAME', 'GOOGLE_CLOUD_STORAGE_BUCKET', 'OLLAMA_API_URL', 'OLLAMA_MODEL_NAME', 'OPENAI_API_KEY', 'OPENAI_API_MODEL_NAME', 'PERSISTENCE_PRIORITY'));
|
|
773
773
|
await ensureGptAvailability(donobuStack, gptConfigName);
|
|
774
774
|
assertNotCancelled('ensuring GPT availability');
|
|
775
775
|
const allowedTools = buildAllowedTools(toolAllowlist, toolDenylist);
|
package/dist/envVars.d.ts
CHANGED
|
@@ -41,6 +41,8 @@ export declare const env: Env<{
|
|
|
41
41
|
}>>;
|
|
42
42
|
GOOGLE_GENERATIVE_AI_API_KEY: z.ZodOptional<z.ZodString>;
|
|
43
43
|
GOOGLE_GENERATIVE_AI_MODEL_NAME: z.ZodOptional<z.ZodString>;
|
|
44
|
+
OLLAMA_MODEL_NAME: z.ZodOptional<z.ZodString>;
|
|
45
|
+
OLLAMA_API_URL: z.ZodOptional<z.ZodString>;
|
|
44
46
|
OPENAI_API_KEY: z.ZodOptional<z.ZodString>;
|
|
45
47
|
OPENAI_API_MODEL_NAME: z.ZodOptional<z.ZodString>;
|
|
46
48
|
PERSISTENCE_PRIORITY: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
@@ -79,6 +81,8 @@ export declare const env: Env<{
|
|
|
79
81
|
DONOBU_PAGE_AI_CLEAR_CACHE?: "0" | "1" | "true" | "false" | undefined;
|
|
80
82
|
GOOGLE_GENERATIVE_AI_API_KEY?: string | undefined;
|
|
81
83
|
GOOGLE_GENERATIVE_AI_MODEL_NAME?: string | undefined;
|
|
84
|
+
OLLAMA_MODEL_NAME?: string | undefined;
|
|
85
|
+
OLLAMA_API_URL?: string | undefined;
|
|
82
86
|
OPENAI_API_KEY?: string | undefined;
|
|
83
87
|
OPENAI_API_MODEL_NAME?: string | undefined;
|
|
84
88
|
AWS_S3_BUCKET?: string | undefined;
|
package/dist/envVars.js
CHANGED
|
@@ -73,6 +73,13 @@ underlying models they map to (ex: "gemini-2.0-flash", etc).`),
|
|
|
73
73
|
GOOGLE_GENERATIVE_AI_MODEL_NAME: v4_1.z.string().optional()
|
|
74
74
|
.describe(`If specified, this will shade the default flow runner agent when running
|
|
75
75
|
flows. If specified, GOOGLE_GENERATIVE_AI_API_KEY must also be specified.`),
|
|
76
|
+
OLLAMA_MODEL_NAME: v4_1.z.string().optional()
|
|
77
|
+
.describe(`If specified, automatically create a GPT configuration for Ollama using
|
|
78
|
+
this model name (e.g. "llama3.2", "qwen2.5"). Ollama must be running
|
|
79
|
+
locally or at the URL specified by OLLAMA_API_URL.`),
|
|
80
|
+
OLLAMA_API_URL: v4_1.z.string().optional()
|
|
81
|
+
.describe(`The base URL for the Ollama API. Defaults to http://localhost:11434 if
|
|
82
|
+
not specified. Only used when OLLAMA_MODEL_NAME is also set.`),
|
|
76
83
|
OPENAI_API_KEY: v4_1.z.string().optional()
|
|
77
84
|
.describe(`Automatically create GPT configurations for OpenAI using this API key.
|
|
78
85
|
For convenience, the created configuration names will reflect the
|
|
@@ -7,6 +7,7 @@ const AnthropicGptClient_1 = require("./AnthropicGptClient");
|
|
|
7
7
|
const DonobuGptClient_1 = require("./DonobuGptClient");
|
|
8
8
|
const GoogleGenerativeAiGptClient_1 = require("./GoogleGenerativeAiGptClient");
|
|
9
9
|
const GptClientPlugin_1 = require("./GptClientPlugin");
|
|
10
|
+
const OllamaGptClient_1 = require("./OllamaGptClient");
|
|
10
11
|
const OpenAiGptClient_1 = require("./OpenAiGptClient");
|
|
11
12
|
/**
|
|
12
13
|
* Default implementation of GptClientFactory that creates GPT clients
|
|
@@ -51,6 +52,8 @@ class GptClientFactoryImpl {
|
|
|
51
52
|
return new DonobuGptClient_1.DonobuGptClient(config);
|
|
52
53
|
case 'GOOGLE_GEMINI':
|
|
53
54
|
return new GoogleGenerativeAiGptClient_1.GoogleGenerativeAiGptClient(config);
|
|
55
|
+
case 'OLLAMA':
|
|
56
|
+
return new OllamaGptClient_1.OllamaGptClient(config);
|
|
54
57
|
case 'OPENAI':
|
|
55
58
|
return new OpenAiGptClient_1.OpenAiGptClient(config);
|
|
56
59
|
default:
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { ZodType } from 'zod/v4';
|
|
2
|
+
import type { OllamaConfig } from '../models/GptConfig';
|
|
3
|
+
import type { AssistantMessage, GptMessage, ProposedToolCallsMessage, StructuredOutputMessage } from '../models/GptMessage';
|
|
4
|
+
import type { ToolOption } from './GptClient';
|
|
5
|
+
import { GptClient } from './GptClient';
|
|
6
|
+
/**
|
|
7
|
+
* A GPT client for Ollama, a local LLM runner that exposes an OpenAI-compatible API.
|
|
8
|
+
* Delegates to {@link OpenAiGptClient} for request handling, with Ollama-specific
|
|
9
|
+
* overrides for ping and structured output.
|
|
10
|
+
*/
|
|
11
|
+
export declare class OllamaGptClient extends GptClient {
|
|
12
|
+
private static readonly DEFAULT_API_URL;
|
|
13
|
+
private readonly delegate;
|
|
14
|
+
private readonly apiUrl;
|
|
15
|
+
constructor(ollamaConfig: OllamaConfig);
|
|
16
|
+
ping(options?: {
|
|
17
|
+
signal?: AbortSignal;
|
|
18
|
+
}): Promise<void>;
|
|
19
|
+
getMessage(messages: GptMessage[], options?: {
|
|
20
|
+
signal?: AbortSignal;
|
|
21
|
+
}): Promise<AssistantMessage>;
|
|
22
|
+
getStructuredOutput<T>(messages: GptMessage[], zodSchema: ZodType<T>, options?: {
|
|
23
|
+
signal?: AbortSignal;
|
|
24
|
+
}): Promise<StructuredOutputMessage<T>>;
|
|
25
|
+
getToolCalls(messages: GptMessage[], tools: ToolOption[], options?: {
|
|
26
|
+
signal?: AbortSignal;
|
|
27
|
+
}): Promise<ProposedToolCallsMessage>;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=OllamaGptClient.d.ts.map
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OllamaGptClient = void 0;
|
|
4
|
+
const GptModelNotFoundException_1 = require("../exceptions/GptModelNotFoundException");
|
|
5
|
+
const GptPlatformNotReachableException_1 = require("../exceptions/GptPlatformNotReachableException");
|
|
6
|
+
const Logger_1 = require("../utils/Logger");
|
|
7
|
+
const GptClient_1 = require("./GptClient");
|
|
8
|
+
const OpenAiGptClient_1 = require("./OpenAiGptClient");
|
|
9
|
+
/**
|
|
10
|
+
* A GPT client for Ollama, a local LLM runner that exposes an OpenAI-compatible API.
|
|
11
|
+
* Delegates to {@link OpenAiGptClient} for request handling, with Ollama-specific
|
|
12
|
+
* overrides for ping and structured output.
|
|
13
|
+
*/
|
|
14
|
+
class OllamaGptClient extends GptClient_1.GptClient {
|
|
15
|
+
constructor(ollamaConfig) {
|
|
16
|
+
super(ollamaConfig);
|
|
17
|
+
this.apiUrl = ollamaConfig.apiUrl ?? OllamaGptClient.DEFAULT_API_URL;
|
|
18
|
+
this.delegate = new OpenAiGptClient_1.OpenAiGptClient({
|
|
19
|
+
type: 'OPENAI',
|
|
20
|
+
modelName: ollamaConfig.modelName,
|
|
21
|
+
apiKey: 'ollama',
|
|
22
|
+
}, this.apiUrl);
|
|
23
|
+
}
|
|
24
|
+
async ping(options) {
|
|
25
|
+
const signal = options?.signal ?? AbortSignal.timeout(10_000);
|
|
26
|
+
let resp;
|
|
27
|
+
try {
|
|
28
|
+
resp = await fetch(`${this.apiUrl}/api/tags`, { signal });
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
if (error instanceof TypeError) {
|
|
32
|
+
Logger_1.appLogger.error('Failed to reach Ollama due to exception', error);
|
|
33
|
+
throw new GptPlatformNotReachableException_1.GptPlatformNotReachableException(this.config.type);
|
|
34
|
+
}
|
|
35
|
+
throw error;
|
|
36
|
+
}
|
|
37
|
+
if (!resp.ok) {
|
|
38
|
+
throw new GptPlatformNotReachableException_1.GptPlatformNotReachableException(this.config.type);
|
|
39
|
+
}
|
|
40
|
+
const data = (await resp.json());
|
|
41
|
+
const models = data.models ?? [];
|
|
42
|
+
const modelName = this.config.modelName;
|
|
43
|
+
const found = models.some((m) => {
|
|
44
|
+
const name = m.name ?? '';
|
|
45
|
+
return name === modelName || name === `${modelName}:latest`;
|
|
46
|
+
});
|
|
47
|
+
if (!found) {
|
|
48
|
+
throw new GptModelNotFoundException_1.GptModelNotFoundException(this.config.type, modelName);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
async getMessage(messages, options) {
|
|
52
|
+
return this.delegate.getMessage(messages, options);
|
|
53
|
+
}
|
|
54
|
+
async getStructuredOutput(messages, zodSchema, options) {
|
|
55
|
+
const resp = await this.getToolCalls(messages, [
|
|
56
|
+
{
|
|
57
|
+
name: 'output',
|
|
58
|
+
description: 'The schema of the expected response structure.',
|
|
59
|
+
inputSchema: zodSchema,
|
|
60
|
+
},
|
|
61
|
+
], options);
|
|
62
|
+
const toolCall = resp.proposedToolCalls.at(0);
|
|
63
|
+
return {
|
|
64
|
+
completionTokensUsed: resp.completionTokensUsed,
|
|
65
|
+
promptTokensUsed: resp.promptTokensUsed,
|
|
66
|
+
type: 'structured_output',
|
|
67
|
+
output: (0, GptClient_1.parseOrLogAndThrow)(toolCall?.parameters, zodSchema),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
async getToolCalls(messages, tools, options) {
|
|
71
|
+
return this.delegate.getToolCalls(messages, tools, options);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
exports.OllamaGptClient = OllamaGptClient;
|
|
75
|
+
OllamaGptClient.DEFAULT_API_URL = 'http://localhost:11434';
|
|
76
|
+
//# sourceMappingURL=OllamaGptClient.js.map
|
|
@@ -769,7 +769,7 @@ async function runGenerateSiteTests(opts, onProgress, shouldCancel) {
|
|
|
769
769
|
}
|
|
770
770
|
const storageState = await loadStorageState(storageStatePath);
|
|
771
771
|
assertNotCancelled('loading storage state');
|
|
772
|
-
const donobuStack = await (0, DonobuStack_1.setupDonobuStack)('LOCAL', ControlPanel_1.NoOpControlPanelFactory, new EnvPersistenceVolatile_1.EnvPersistenceVolatile(snapshotEnv()), envVars_1.env.pick('ANTHROPIC_API_KEY', 'ANTHROPIC_MODEL_NAME', 'AWS_ACCESS_KEY_ID', 'AWS_BEDROCK_MODEL_NAME', 'AWS_REGION', 'AWS_S3_BUCKET', 'AWS_S3_REGION', 'AWS_SECRET_ACCESS_KEY', 'BASE64_GPT_CONFIG', 'BROWSERBASE_API_KEY', 'BROWSERBASE_PROJECT_ID', 'DONOBU_API_BASE_URL', 'DONOBU_API_KEY', 'GOOGLE_GENERATIVE_AI_API_KEY', 'GOOGLE_GENERATIVE_AI_MODEL_NAME', 'GOOGLE_CLOUD_STORAGE_BUCKET', 'OPENAI_API_KEY', 'OPENAI_API_MODEL_NAME', 'PERSISTENCE_PRIORITY'));
|
|
772
|
+
const donobuStack = await (0, DonobuStack_1.setupDonobuStack)('LOCAL', ControlPanel_1.NoOpControlPanelFactory, new EnvPersistenceVolatile_1.EnvPersistenceVolatile(snapshotEnv()), envVars_1.env.pick('ANTHROPIC_API_KEY', 'ANTHROPIC_MODEL_NAME', 'AWS_ACCESS_KEY_ID', 'AWS_BEDROCK_MODEL_NAME', 'AWS_REGION', 'AWS_S3_BUCKET', 'AWS_S3_REGION', 'AWS_SECRET_ACCESS_KEY', 'BASE64_GPT_CONFIG', 'BROWSERBASE_API_KEY', 'BROWSERBASE_PROJECT_ID', 'DONOBU_API_BASE_URL', 'DONOBU_API_KEY', 'GOOGLE_GENERATIVE_AI_API_KEY', 'GOOGLE_GENERATIVE_AI_MODEL_NAME', 'GOOGLE_CLOUD_STORAGE_BUCKET', 'OLLAMA_API_URL', 'OLLAMA_MODEL_NAME', 'OPENAI_API_KEY', 'OPENAI_API_MODEL_NAME', 'PERSISTENCE_PRIORITY'));
|
|
773
773
|
await ensureGptAvailability(donobuStack, gptConfigName);
|
|
774
774
|
assertNotCancelled('ensuring GPT availability');
|
|
775
775
|
const allowedTools = buildAllowedTools(toolAllowlist, toolDenylist);
|
package/dist/esm/envVars.d.ts
CHANGED
|
@@ -41,6 +41,8 @@ export declare const env: Env<{
|
|
|
41
41
|
}>>;
|
|
42
42
|
GOOGLE_GENERATIVE_AI_API_KEY: z.ZodOptional<z.ZodString>;
|
|
43
43
|
GOOGLE_GENERATIVE_AI_MODEL_NAME: z.ZodOptional<z.ZodString>;
|
|
44
|
+
OLLAMA_MODEL_NAME: z.ZodOptional<z.ZodString>;
|
|
45
|
+
OLLAMA_API_URL: z.ZodOptional<z.ZodString>;
|
|
44
46
|
OPENAI_API_KEY: z.ZodOptional<z.ZodString>;
|
|
45
47
|
OPENAI_API_MODEL_NAME: z.ZodOptional<z.ZodString>;
|
|
46
48
|
PERSISTENCE_PRIORITY: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
@@ -79,6 +81,8 @@ export declare const env: Env<{
|
|
|
79
81
|
DONOBU_PAGE_AI_CLEAR_CACHE?: "0" | "1" | "true" | "false" | undefined;
|
|
80
82
|
GOOGLE_GENERATIVE_AI_API_KEY?: string | undefined;
|
|
81
83
|
GOOGLE_GENERATIVE_AI_MODEL_NAME?: string | undefined;
|
|
84
|
+
OLLAMA_MODEL_NAME?: string | undefined;
|
|
85
|
+
OLLAMA_API_URL?: string | undefined;
|
|
82
86
|
OPENAI_API_KEY?: string | undefined;
|
|
83
87
|
OPENAI_API_MODEL_NAME?: string | undefined;
|
|
84
88
|
AWS_S3_BUCKET?: string | undefined;
|
package/dist/esm/envVars.js
CHANGED
|
@@ -73,6 +73,13 @@ underlying models they map to (ex: "gemini-2.0-flash", etc).`),
|
|
|
73
73
|
GOOGLE_GENERATIVE_AI_MODEL_NAME: v4_1.z.string().optional()
|
|
74
74
|
.describe(`If specified, this will shade the default flow runner agent when running
|
|
75
75
|
flows. If specified, GOOGLE_GENERATIVE_AI_API_KEY must also be specified.`),
|
|
76
|
+
OLLAMA_MODEL_NAME: v4_1.z.string().optional()
|
|
77
|
+
.describe(`If specified, automatically create a GPT configuration for Ollama using
|
|
78
|
+
this model name (e.g. "llama3.2", "qwen2.5"). Ollama must be running
|
|
79
|
+
locally or at the URL specified by OLLAMA_API_URL.`),
|
|
80
|
+
OLLAMA_API_URL: v4_1.z.string().optional()
|
|
81
|
+
.describe(`The base URL for the Ollama API. Defaults to http://localhost:11434 if
|
|
82
|
+
not specified. Only used when OLLAMA_MODEL_NAME is also set.`),
|
|
76
83
|
OPENAI_API_KEY: v4_1.z.string().optional()
|
|
77
84
|
.describe(`Automatically create GPT configurations for OpenAI using this API key.
|
|
78
85
|
For convenience, the created configuration names will reflect the
|
|
@@ -8,6 +8,7 @@ export declare function donobuGptClientFixture(apiKey?: string | undefined): Tes
|
|
|
8
8
|
export declare function anthropicClientFixture(modelName: string, apiKey?: string | undefined): TestFixture<GptClient, any>;
|
|
9
9
|
export declare function anthropicAwsBedrockClientFixture(modelName: string, region?: string | undefined, accessKeyId?: string | undefined, secretAccessKey?: string | undefined): TestFixture<GptClient, any>;
|
|
10
10
|
export declare function googleGeminiClientFixture(modelName: string, apiKey?: string | undefined): TestFixture<GptClient, any>;
|
|
11
|
+
export declare function ollamaClientFixture(modelName: string, apiUrl?: string): TestFixture<GptClient, any>;
|
|
11
12
|
export declare function openAiClientFixture(modelName: string, apiKey?: string | undefined): TestFixture<GptClient, any>;
|
|
12
13
|
export declare function vercelAiClientFixture(model: Exclude<LanguageModel, string>): TestFixture<GptClient, any>;
|
|
13
14
|
export declare function gptClientFixture(): TestFixture<GptClient, any>;
|
|
@@ -6,6 +6,7 @@ exports.donobuGptClientFixture = donobuGptClientFixture;
|
|
|
6
6
|
exports.anthropicClientFixture = anthropicClientFixture;
|
|
7
7
|
exports.anthropicAwsBedrockClientFixture = anthropicAwsBedrockClientFixture;
|
|
8
8
|
exports.googleGeminiClientFixture = googleGeminiClientFixture;
|
|
9
|
+
exports.ollamaClientFixture = ollamaClientFixture;
|
|
9
10
|
exports.openAiClientFixture = openAiClientFixture;
|
|
10
11
|
exports.vercelAiClientFixture = vercelAiClientFixture;
|
|
11
12
|
exports.gptClientFixture = gptClientFixture;
|
|
@@ -87,6 +88,16 @@ Please provide one as an argument or set it using the ${envVars_1.env.keys.GOOGL
|
|
|
87
88
|
await use(client);
|
|
88
89
|
};
|
|
89
90
|
}
|
|
91
|
+
function ollamaClientFixture(modelName, apiUrl) {
|
|
92
|
+
return async ({}, use) => {
|
|
93
|
+
const client = await createClient({
|
|
94
|
+
type: 'OLLAMA',
|
|
95
|
+
modelName,
|
|
96
|
+
...(apiUrl ? { apiUrl } : {}),
|
|
97
|
+
});
|
|
98
|
+
await use(client);
|
|
99
|
+
};
|
|
100
|
+
}
|
|
90
101
|
function openAiClientFixture(modelName, apiKey = envVars_1.env.data.OPENAI_API_KEY) {
|
|
91
102
|
if (!apiKey) {
|
|
92
103
|
throw new Error(`An API key is required to use the OpenAI API.
|
|
@@ -25,6 +25,7 @@ const BrowserUtils_1 = require("../../utils/BrowserUtils");
|
|
|
25
25
|
const FlowLogBuffer_1 = require("../../utils/FlowLogBuffer");
|
|
26
26
|
const Logger_1 = require("../../utils/Logger");
|
|
27
27
|
const MiscUtils_1 = require("../../utils/MiscUtils");
|
|
28
|
+
const PageLogListeners_1 = require("../../utils/PageLogListeners");
|
|
28
29
|
const cacheLocator_1 = require("../ai/cache/cacheLocator");
|
|
29
30
|
const extendPage_1 = require("../page/extendPage");
|
|
30
31
|
const tbd_1 = require("../page/tbd");
|
|
@@ -101,6 +102,11 @@ exports.test = test_1.test.extend({
|
|
|
101
102
|
});
|
|
102
103
|
extendedPage._dnb.donobuFlowMetadata.name = getSanitizedTestName(testInfo);
|
|
103
104
|
extendedPage._dnb.donobuFlowMetadata.overallObjective = overallObjective;
|
|
105
|
+
// Register browser console and network listeners so that logs from these
|
|
106
|
+
// sources are captured into the flow's logBuffer. In Studio-launched flows
|
|
107
|
+
// this is done by WebTargetInspector.initialize(), but that method is not
|
|
108
|
+
// called during test runs, so we wire the listeners up here directly.
|
|
109
|
+
(0, PageLogListeners_1.registerPageLogListeners)(page);
|
|
104
110
|
// Bind the Playwright-provided `use` callback to an async resource so that
|
|
105
111
|
// any microtasks scheduled inside the test body keep the flow logging
|
|
106
112
|
// context. Without this, Playwright may re-use earlier async resources that
|
|
@@ -20,7 +20,7 @@ function getEnvSnapshot() {
|
|
|
20
20
|
}
|
|
21
21
|
async function getOrCreateDonobuStack() {
|
|
22
22
|
if (!donobuStack) {
|
|
23
|
-
donobuStack = await (0, DonobuStack_1.setupDonobuStack)('LOCAL', ControlPanel_1.NoOpControlPanelFactory, new EnvPersistenceVolatile_1.EnvPersistenceVolatile(getEnvSnapshot()), envVars_1.env.pick('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_BASE_URL', 'DONOBU_API_KEY', 'GOOGLE_GENERATIVE_AI_API_KEY', 'GOOGLE_GENERATIVE_AI_MODEL_NAME', 'OPENAI_API_KEY', 'OPENAI_API_MODEL_NAME', 'PERSISTENCE_PRIORITY'));
|
|
23
|
+
donobuStack = await (0, DonobuStack_1.setupDonobuStack)('LOCAL', ControlPanel_1.NoOpControlPanelFactory, new EnvPersistenceVolatile_1.EnvPersistenceVolatile(getEnvSnapshot()), envVars_1.env.pick('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_BASE_URL', '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', 'PERSISTENCE_PRIORITY'));
|
|
24
24
|
return donobuStack;
|
|
25
25
|
}
|
|
26
26
|
else {
|
|
@@ -59,7 +59,7 @@ export declare class AdminApiController {
|
|
|
59
59
|
* - no checking for flow ownership is performed, as all flows are considered owned by the
|
|
60
60
|
* local environment.
|
|
61
61
|
*/
|
|
62
|
-
static create(donobuDeploymentEnvironment: DonobuDeploymentEnvironment, 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_BASE_URL' | 'DONOBU_API_KEY' | 'GOOGLE_GENERATIVE_AI_API_KEY' | 'GOOGLE_GENERATIVE_AI_MODEL_NAME' | 'OPENAI_API_KEY' | 'OPENAI_API_MODEL_NAME' | 'PERSISTENCE_PRIORITY'>): Promise<AdminApiController>;
|
|
62
|
+
static create(donobuDeploymentEnvironment: DonobuDeploymentEnvironment, 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_BASE_URL' | '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' | 'PERSISTENCE_PRIORITY'>): Promise<AdminApiController>;
|
|
63
63
|
private constructor();
|
|
64
64
|
/**
|
|
65
65
|
* Serves the API and web assets; this blocks until stop() is called.
|
|
@@ -48,7 +48,7 @@ export declare class DonobuFlowsManager {
|
|
|
48
48
|
static readonly FLOW_NAME_MAX_LENGTH = 255;
|
|
49
49
|
private readonly flowRuntime;
|
|
50
50
|
private readonly flowCatalog;
|
|
51
|
-
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' | 'OPENAI_API_KEY' | 'OPENAI_API_MODEL_NAME'>, toolRegistry: ToolRegistry, targetRuntimePlugins: TargetRuntimePluginRegistry);
|
|
51
|
+
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);
|
|
52
52
|
/**
|
|
53
53
|
* Create a flow with the given parameters and invoke its `DonobuFlow#run`
|
|
54
54
|
* method, adding it to list of active flows.
|
|
@@ -132,7 +132,8 @@ export declare class DonobuFlowsManager {
|
|
|
132
132
|
* Resolves a GPT client using the provided GPT configuration name, falling back
|
|
133
133
|
* to environment-provided configs (BASE64_GPT_CONFIG, DONOBU_API_KEY,
|
|
134
134
|
* AWS_BEDROCK_MODEL_NAME, ANTHROPIC_API_KEY, GOOGLE_GENERATIVE_AI_API_KEY,
|
|
135
|
-
* OPENAI_API_KEY) and finally the config bound to the
|
|
135
|
+
* OPENAI_API_KEY, OLLAMA_MODEL_NAME) and finally the config bound to the
|
|
136
|
+
* 'flow-runner' agent.
|
|
136
137
|
* Returns a null client if no configuration source is available.
|
|
137
138
|
*
|
|
138
139
|
* Public for testing only.
|
|
@@ -479,7 +479,8 @@ class DonobuFlowsManager {
|
|
|
479
479
|
* Resolves a GPT client using the provided GPT configuration name, falling back
|
|
480
480
|
* to environment-provided configs (BASE64_GPT_CONFIG, DONOBU_API_KEY,
|
|
481
481
|
* AWS_BEDROCK_MODEL_NAME, ANTHROPIC_API_KEY, GOOGLE_GENERATIVE_AI_API_KEY,
|
|
482
|
-
* OPENAI_API_KEY) and finally the config bound to the
|
|
482
|
+
* OPENAI_API_KEY, OLLAMA_MODEL_NAME) and finally the config bound to the
|
|
483
|
+
* 'flow-runner' agent.
|
|
483
484
|
* Returns a null client if no configuration source is available.
|
|
484
485
|
*
|
|
485
486
|
* Public for testing only.
|
|
@@ -551,6 +552,15 @@ class DonobuFlowsManager {
|
|
|
551
552
|
apiKey: this.environ.data.OPENAI_API_KEY,
|
|
552
553
|
};
|
|
553
554
|
}
|
|
555
|
+
else if (this.environ.data.OLLAMA_MODEL_NAME) {
|
|
556
|
+
gptConfigFromEnv = {
|
|
557
|
+
type: 'OLLAMA',
|
|
558
|
+
modelName: this.environ.data.OLLAMA_MODEL_NAME,
|
|
559
|
+
...(this.environ.data.OLLAMA_API_URL
|
|
560
|
+
? { apiUrl: this.environ.data.OLLAMA_API_URL }
|
|
561
|
+
: {}),
|
|
562
|
+
};
|
|
563
|
+
}
|
|
554
564
|
if (gptConfigFromEnv) {
|
|
555
565
|
const gptClient = await this.gptClientFactory.createClient(gptConfigFromEnv);
|
|
556
566
|
return {
|
|
@@ -43,6 +43,8 @@ export declare function setupDonobuStack(donobuDeploymentEnvironment: DonobuDepl
|
|
|
43
43
|
ANTHROPIC_MODEL_NAME: import("zod/v4").ZodOptional<import("zod/v4").ZodString>;
|
|
44
44
|
GOOGLE_GENERATIVE_AI_API_KEY: import("zod/v4").ZodOptional<import("zod/v4").ZodString>;
|
|
45
45
|
GOOGLE_GENERATIVE_AI_MODEL_NAME: import("zod/v4").ZodOptional<import("zod/v4").ZodString>;
|
|
46
|
+
OLLAMA_MODEL_NAME: import("zod/v4").ZodOptional<import("zod/v4").ZodString>;
|
|
47
|
+
OLLAMA_API_URL: import("zod/v4").ZodOptional<import("zod/v4").ZodString>;
|
|
46
48
|
OPENAI_API_KEY: import("zod/v4").ZodOptional<import("zod/v4").ZodString>;
|
|
47
49
|
OPENAI_API_MODEL_NAME: import("zod/v4").ZodOptional<import("zod/v4").ZodString>;
|
|
48
50
|
PERSISTENCE_PRIORITY: import("zod/v4").ZodDefault<import("zod/v4").ZodArray<import("zod/v4").ZodString>>;
|
|
@@ -59,6 +61,8 @@ export declare function setupDonobuStack(donobuDeploymentEnvironment: DonobuDepl
|
|
|
59
61
|
ANTHROPIC_MODEL_NAME?: string | undefined;
|
|
60
62
|
GOOGLE_GENERATIVE_AI_API_KEY?: string | undefined;
|
|
61
63
|
GOOGLE_GENERATIVE_AI_MODEL_NAME?: string | undefined;
|
|
64
|
+
OLLAMA_MODEL_NAME?: string | undefined;
|
|
65
|
+
OLLAMA_API_URL?: string | undefined;
|
|
62
66
|
OPENAI_API_KEY?: string | undefined;
|
|
63
67
|
OPENAI_API_MODEL_NAME?: string | undefined;
|
|
64
68
|
PERSISTENCE_PRIORITY: string[];
|
|
@@ -29,7 +29,7 @@ const ToolRegistry_1 = require("./ToolRegistry");
|
|
|
29
29
|
* then having this snapshot is relevant so that tests can use normal
|
|
30
30
|
* environment variables.
|
|
31
31
|
*/
|
|
32
|
-
async function setupDonobuStack(donobuDeploymentEnvironment, controlPanelFactory, envPersistenceVolatile, environ = envVars_1.env.pick('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_BASE_URL', 'DONOBU_API_KEY', 'GOOGLE_GENERATIVE_AI_API_KEY', 'GOOGLE_GENERATIVE_AI_MODEL_NAME', 'OPENAI_API_KEY', 'OPENAI_API_MODEL_NAME', 'PERSISTENCE_PRIORITY')) {
|
|
32
|
+
async function setupDonobuStack(donobuDeploymentEnvironment, controlPanelFactory, envPersistenceVolatile, environ = envVars_1.env.pick('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_BASE_URL', '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', 'PERSISTENCE_PRIORITY')) {
|
|
33
33
|
const loadedPlugins = await loadDefaultPlugins();
|
|
34
34
|
const resolvedToolRegistry = await (0, ToolRegistry_1.createDefaultToolRegistry)(loadedPlugins.tools);
|
|
35
35
|
const persistencePlugins = new PersistencePlugin_1.PersistencePluginRegistry(loadedPlugins.persistencePlugins);
|
|
@@ -6,6 +6,7 @@ const SetDonobuAnnotations_1 = require("../bindings/SetDonobuAnnotations");
|
|
|
6
6
|
const PageClosedException_1 = require("../exceptions/PageClosedException");
|
|
7
7
|
const BrowserUtils_1 = require("../utils/BrowserUtils");
|
|
8
8
|
const Logger_1 = require("../utils/Logger");
|
|
9
|
+
const PageLogListeners_1 = require("../utils/PageLogListeners");
|
|
9
10
|
const PlaywrightUtils_1 = require("../utils/PlaywrightUtils");
|
|
10
11
|
const PageInspector_1 = require("./PageInspector");
|
|
11
12
|
/**
|
|
@@ -185,81 +186,7 @@ The active (i.e. in focus) tab is ${this._target.current.url()}`;
|
|
|
185
186
|
/* ------------------------------------------------------------------ */
|
|
186
187
|
handleNewPage(page, callbacks) {
|
|
187
188
|
this._target.current = page;
|
|
188
|
-
|
|
189
|
-
const { url, lineNumber, columnNumber } = msg.location();
|
|
190
|
-
const hasSourceLocation = lineNumber !== 0 || columnNumber !== 0;
|
|
191
|
-
const meta = url
|
|
192
|
-
? hasSourceLocation
|
|
193
|
-
? { url, lineNumber, columnNumber }
|
|
194
|
-
: { url }
|
|
195
|
-
: undefined;
|
|
196
|
-
switch (msg.type()) {
|
|
197
|
-
case 'error':
|
|
198
|
-
Logger_1.browserLogger.error(msg.text(), meta);
|
|
199
|
-
break;
|
|
200
|
-
case 'warning':
|
|
201
|
-
Logger_1.browserLogger.warn(msg.text(), meta);
|
|
202
|
-
break;
|
|
203
|
-
case 'debug':
|
|
204
|
-
Logger_1.browserLogger.debug(msg.text(), meta);
|
|
205
|
-
break;
|
|
206
|
-
default:
|
|
207
|
-
Logger_1.browserLogger.info(msg.text(), meta);
|
|
208
|
-
break;
|
|
209
|
-
}
|
|
210
|
-
});
|
|
211
|
-
page.on('pageerror', (error) => {
|
|
212
|
-
Logger_1.browserLogger.error(error.message, {
|
|
213
|
-
stack: error.stack,
|
|
214
|
-
url: page.url(),
|
|
215
|
-
});
|
|
216
|
-
});
|
|
217
|
-
// Fallback timing: track request start times keyed by the Request object
|
|
218
|
-
// itself (via WeakMap) so concurrent requests to the same URL don't collide.
|
|
219
|
-
// Prefer Playwright's native timing API when it has data.
|
|
220
|
-
const requestStartTimes = new WeakMap();
|
|
221
|
-
page.on('request', (request) => {
|
|
222
|
-
requestStartTimes.set(request, Date.now());
|
|
223
|
-
});
|
|
224
|
-
const getDuration = (request) => {
|
|
225
|
-
const timing = request.timing();
|
|
226
|
-
if (timing.responseEnd >= 0) {
|
|
227
|
-
return Math.round(timing.responseEnd);
|
|
228
|
-
}
|
|
229
|
-
const startTime = requestStartTimes.get(request);
|
|
230
|
-
return startTime !== undefined ? Date.now() - startTime : undefined;
|
|
231
|
-
};
|
|
232
|
-
page.on('response', (response) => {
|
|
233
|
-
const request = response.request();
|
|
234
|
-
const status = response.status();
|
|
235
|
-
const duration = getDuration(request);
|
|
236
|
-
const meta = {
|
|
237
|
-
method: request.method(),
|
|
238
|
-
url: request.url(),
|
|
239
|
-
status,
|
|
240
|
-
duration,
|
|
241
|
-
resourceType: request.resourceType(),
|
|
242
|
-
};
|
|
243
|
-
if (status >= 500) {
|
|
244
|
-
Logger_1.networkLogger.error(request.url(), meta);
|
|
245
|
-
}
|
|
246
|
-
else if (status >= 400) {
|
|
247
|
-
Logger_1.networkLogger.warn(request.url(), meta);
|
|
248
|
-
}
|
|
249
|
-
else {
|
|
250
|
-
Logger_1.networkLogger.info(request.url(), meta);
|
|
251
|
-
}
|
|
252
|
-
});
|
|
253
|
-
page.on('requestfailed', (request) => {
|
|
254
|
-
const duration = getDuration(request);
|
|
255
|
-
Logger_1.networkLogger.error(`${request.url()} FAILED: ${request.failure()?.errorText}`, {
|
|
256
|
-
method: request.method(),
|
|
257
|
-
url: request.url(),
|
|
258
|
-
resourceType: request.resourceType(),
|
|
259
|
-
failureReason: request.failure()?.errorText,
|
|
260
|
-
duration,
|
|
261
|
-
});
|
|
262
|
-
});
|
|
189
|
+
(0, PageLogListeners_1.registerPageLogListeners)(page);
|
|
263
190
|
if (callbacks.metadata.runMode !== 'INSTRUCT') {
|
|
264
191
|
page.on('domcontentloaded', async () => {
|
|
265
192
|
await this._interactionVisualizer.showMouse(page);
|
|
@@ -16,6 +16,12 @@ export declare const GoogleGenerativeAiConfigSchema: z.ZodObject<{
|
|
|
16
16
|
modelName: z.ZodString;
|
|
17
17
|
}, z.core.$strip>;
|
|
18
18
|
export type GoogleGenerativeAiConfig = z.infer<typeof GoogleGenerativeAiConfigSchema>;
|
|
19
|
+
export declare const OllamaConfigSchema: z.ZodObject<{
|
|
20
|
+
type: z.ZodLiteral<"OLLAMA">;
|
|
21
|
+
modelName: z.ZodString;
|
|
22
|
+
apiUrl: z.ZodOptional<z.ZodString>;
|
|
23
|
+
}, z.core.$strip>;
|
|
24
|
+
export type OllamaConfig = z.infer<typeof OllamaConfigSchema>;
|
|
19
25
|
export declare const OpenAiConfigSchema: z.ZodObject<{
|
|
20
26
|
type: z.ZodLiteral<"OPENAI">;
|
|
21
27
|
apiKey: z.ZodString;
|
|
@@ -45,6 +51,10 @@ export declare const GptConfigSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
45
51
|
type: z.ZodLiteral<"GOOGLE_GEMINI">;
|
|
46
52
|
apiKey: z.ZodString;
|
|
47
53
|
modelName: z.ZodString;
|
|
54
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
55
|
+
type: z.ZodLiteral<"OLLAMA">;
|
|
56
|
+
modelName: z.ZodString;
|
|
57
|
+
apiUrl: z.ZodOptional<z.ZodString>;
|
|
48
58
|
}, z.core.$strip>, z.ZodObject<{
|
|
49
59
|
type: z.ZodLiteral<"OPENAI">;
|
|
50
60
|
apiKey: z.ZodString;
|
|
@@ -71,6 +81,10 @@ export declare const GptConfigInputSchema: z.ZodUnion<readonly [z.ZodDiscriminat
|
|
|
71
81
|
type: z.ZodLiteral<"GOOGLE_GEMINI">;
|
|
72
82
|
apiKey: z.ZodString;
|
|
73
83
|
modelName: z.ZodString;
|
|
84
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
85
|
+
type: z.ZodLiteral<"OLLAMA">;
|
|
86
|
+
modelName: z.ZodString;
|
|
87
|
+
apiUrl: z.ZodOptional<z.ZodString>;
|
|
74
88
|
}, z.core.$strip>, z.ZodObject<{
|
|
75
89
|
type: z.ZodLiteral<"OPENAI">;
|
|
76
90
|
apiKey: z.ZodString;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.GptConfigInputSchema = exports.GptConfigSchema = exports.VercelAiConfigSchema = exports.OpenAiConfigSchema = exports.GoogleGenerativeAiConfigSchema = exports.DonobuGptClientConfigSchema = exports.AnthropicConfigSchema = void 0;
|
|
3
|
+
exports.GptConfigInputSchema = exports.GptConfigSchema = exports.VercelAiConfigSchema = exports.OpenAiConfigSchema = exports.OllamaConfigSchema = exports.GoogleGenerativeAiConfigSchema = exports.DonobuGptClientConfigSchema = exports.AnthropicConfigSchema = void 0;
|
|
4
4
|
const v4_1 = require("zod/v4");
|
|
5
5
|
exports.AnthropicConfigSchema = v4_1.z.object({
|
|
6
6
|
type: v4_1.z.literal('ANTHROPIC'),
|
|
@@ -16,6 +16,11 @@ exports.GoogleGenerativeAiConfigSchema = v4_1.z.object({
|
|
|
16
16
|
apiKey: v4_1.z.string(),
|
|
17
17
|
modelName: v4_1.z.string(),
|
|
18
18
|
});
|
|
19
|
+
exports.OllamaConfigSchema = v4_1.z.object({
|
|
20
|
+
type: v4_1.z.literal('OLLAMA'),
|
|
21
|
+
modelName: v4_1.z.string(),
|
|
22
|
+
apiUrl: v4_1.z.string().optional(),
|
|
23
|
+
});
|
|
19
24
|
exports.OpenAiConfigSchema = v4_1.z.object({
|
|
20
25
|
type: v4_1.z.literal('OPENAI'),
|
|
21
26
|
apiKey: v4_1.z.string(),
|
|
@@ -36,6 +41,7 @@ exports.GptConfigSchema = v4_1.z.discriminatedUnion('type', [
|
|
|
36
41
|
exports.AnthropicConfigSchema,
|
|
37
42
|
exports.DonobuGptClientConfigSchema,
|
|
38
43
|
exports.GoogleGenerativeAiConfigSchema,
|
|
44
|
+
exports.OllamaConfigSchema,
|
|
39
45
|
exports.OpenAiConfigSchema,
|
|
40
46
|
exports.VercelAiConfigSchema,
|
|
41
47
|
]);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Page } from 'playwright';
|
|
2
|
+
/**
|
|
3
|
+
* Registers Playwright page event listeners that route browser console messages
|
|
4
|
+
* and network request/response data to the {@link browserLogger} and
|
|
5
|
+
* {@link networkLogger} Winston loggers. These loggers include a
|
|
6
|
+
* {@link FlowLogBufferTransport} that captures entries into the per-flow
|
|
7
|
+
* log buffer (when one is available via AsyncLocalStorage or the process-local
|
|
8
|
+
* fallback).
|
|
9
|
+
*
|
|
10
|
+
* This function is called from both {@link WebTargetInspector.handleNewPage}
|
|
11
|
+
* (Studio-launched flows) and the Playwright test extension fixture, ensuring
|
|
12
|
+
* identical logging behaviour across both runtime contexts.
|
|
13
|
+
*/
|
|
14
|
+
export declare function registerPageLogListeners(page: Page): void;
|
|
15
|
+
//# sourceMappingURL=PageLogListeners.d.ts.map
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerPageLogListeners = registerPageLogListeners;
|
|
4
|
+
const Logger_1 = require("./Logger");
|
|
5
|
+
/**
|
|
6
|
+
* Registers Playwright page event listeners that route browser console messages
|
|
7
|
+
* and network request/response data to the {@link browserLogger} and
|
|
8
|
+
* {@link networkLogger} Winston loggers. These loggers include a
|
|
9
|
+
* {@link FlowLogBufferTransport} that captures entries into the per-flow
|
|
10
|
+
* log buffer (when one is available via AsyncLocalStorage or the process-local
|
|
11
|
+
* fallback).
|
|
12
|
+
*
|
|
13
|
+
* This function is called from both {@link WebTargetInspector.handleNewPage}
|
|
14
|
+
* (Studio-launched flows) and the Playwright test extension fixture, ensuring
|
|
15
|
+
* identical logging behaviour across both runtime contexts.
|
|
16
|
+
*/
|
|
17
|
+
function registerPageLogListeners(page) {
|
|
18
|
+
page.on('console', (msg) => {
|
|
19
|
+
const { url, lineNumber, columnNumber } = msg.location();
|
|
20
|
+
const hasSourceLocation = lineNumber !== 0 || columnNumber !== 0;
|
|
21
|
+
const meta = url
|
|
22
|
+
? hasSourceLocation
|
|
23
|
+
? { url, lineNumber, columnNumber }
|
|
24
|
+
: { url }
|
|
25
|
+
: undefined;
|
|
26
|
+
switch (msg.type()) {
|
|
27
|
+
case 'error':
|
|
28
|
+
Logger_1.browserLogger.error(msg.text(), meta);
|
|
29
|
+
break;
|
|
30
|
+
case 'warning':
|
|
31
|
+
Logger_1.browserLogger.warn(msg.text(), meta);
|
|
32
|
+
break;
|
|
33
|
+
case 'debug':
|
|
34
|
+
Logger_1.browserLogger.debug(msg.text(), meta);
|
|
35
|
+
break;
|
|
36
|
+
default:
|
|
37
|
+
Logger_1.browserLogger.info(msg.text(), meta);
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
page.on('pageerror', (error) => {
|
|
42
|
+
Logger_1.browserLogger.error(error.message, {
|
|
43
|
+
stack: error.stack,
|
|
44
|
+
url: page.url(),
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
// Fallback timing: track request start times keyed by the Request object
|
|
48
|
+
// itself (via WeakMap) so concurrent requests to the same URL don't collide.
|
|
49
|
+
// Prefer Playwright's native timing API when it has data.
|
|
50
|
+
const requestStartTimes = new WeakMap();
|
|
51
|
+
page.on('request', (request) => {
|
|
52
|
+
requestStartTimes.set(request, Date.now());
|
|
53
|
+
});
|
|
54
|
+
const getDuration = (request) => {
|
|
55
|
+
const timing = request.timing();
|
|
56
|
+
if (timing.responseEnd >= 0) {
|
|
57
|
+
return Math.round(timing.responseEnd);
|
|
58
|
+
}
|
|
59
|
+
const startTime = requestStartTimes.get(request);
|
|
60
|
+
return startTime !== undefined ? Date.now() - startTime : undefined;
|
|
61
|
+
};
|
|
62
|
+
page.on('response', (response) => {
|
|
63
|
+
const request = response.request();
|
|
64
|
+
const status = response.status();
|
|
65
|
+
const duration = getDuration(request);
|
|
66
|
+
const meta = {
|
|
67
|
+
method: request.method(),
|
|
68
|
+
url: request.url(),
|
|
69
|
+
status,
|
|
70
|
+
duration,
|
|
71
|
+
resourceType: request.resourceType(),
|
|
72
|
+
};
|
|
73
|
+
if (status >= 500) {
|
|
74
|
+
Logger_1.networkLogger.error(request.url(), meta);
|
|
75
|
+
}
|
|
76
|
+
else if (status >= 400) {
|
|
77
|
+
Logger_1.networkLogger.warn(request.url(), meta);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
Logger_1.networkLogger.info(request.url(), meta);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
page.on('requestfailed', (request) => {
|
|
84
|
+
const duration = getDuration(request);
|
|
85
|
+
Logger_1.networkLogger.error(`${request.url()} FAILED: ${request.failure()?.errorText}`, {
|
|
86
|
+
method: request.method(),
|
|
87
|
+
url: request.url(),
|
|
88
|
+
resourceType: request.resourceType(),
|
|
89
|
+
failureReason: request.failure()?.errorText,
|
|
90
|
+
duration,
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=PageLogListeners.js.map
|
|
@@ -8,6 +8,7 @@ export declare function donobuGptClientFixture(apiKey?: string | undefined): Tes
|
|
|
8
8
|
export declare function anthropicClientFixture(modelName: string, apiKey?: string | undefined): TestFixture<GptClient, any>;
|
|
9
9
|
export declare function anthropicAwsBedrockClientFixture(modelName: string, region?: string | undefined, accessKeyId?: string | undefined, secretAccessKey?: string | undefined): TestFixture<GptClient, any>;
|
|
10
10
|
export declare function googleGeminiClientFixture(modelName: string, apiKey?: string | undefined): TestFixture<GptClient, any>;
|
|
11
|
+
export declare function ollamaClientFixture(modelName: string, apiUrl?: string): TestFixture<GptClient, any>;
|
|
11
12
|
export declare function openAiClientFixture(modelName: string, apiKey?: string | undefined): TestFixture<GptClient, any>;
|
|
12
13
|
export declare function vercelAiClientFixture(model: Exclude<LanguageModel, string>): TestFixture<GptClient, any>;
|
|
13
14
|
export declare function gptClientFixture(): TestFixture<GptClient, any>;
|
|
@@ -6,6 +6,7 @@ exports.donobuGptClientFixture = donobuGptClientFixture;
|
|
|
6
6
|
exports.anthropicClientFixture = anthropicClientFixture;
|
|
7
7
|
exports.anthropicAwsBedrockClientFixture = anthropicAwsBedrockClientFixture;
|
|
8
8
|
exports.googleGeminiClientFixture = googleGeminiClientFixture;
|
|
9
|
+
exports.ollamaClientFixture = ollamaClientFixture;
|
|
9
10
|
exports.openAiClientFixture = openAiClientFixture;
|
|
10
11
|
exports.vercelAiClientFixture = vercelAiClientFixture;
|
|
11
12
|
exports.gptClientFixture = gptClientFixture;
|
|
@@ -87,6 +88,16 @@ Please provide one as an argument or set it using the ${envVars_1.env.keys.GOOGL
|
|
|
87
88
|
await use(client);
|
|
88
89
|
};
|
|
89
90
|
}
|
|
91
|
+
function ollamaClientFixture(modelName, apiUrl) {
|
|
92
|
+
return async ({}, use) => {
|
|
93
|
+
const client = await createClient({
|
|
94
|
+
type: 'OLLAMA',
|
|
95
|
+
modelName,
|
|
96
|
+
...(apiUrl ? { apiUrl } : {}),
|
|
97
|
+
});
|
|
98
|
+
await use(client);
|
|
99
|
+
};
|
|
100
|
+
}
|
|
90
101
|
function openAiClientFixture(modelName, apiKey = envVars_1.env.data.OPENAI_API_KEY) {
|
|
91
102
|
if (!apiKey) {
|
|
92
103
|
throw new Error(`An API key is required to use the OpenAI API.
|
|
@@ -25,6 +25,7 @@ const BrowserUtils_1 = require("../../utils/BrowserUtils");
|
|
|
25
25
|
const FlowLogBuffer_1 = require("../../utils/FlowLogBuffer");
|
|
26
26
|
const Logger_1 = require("../../utils/Logger");
|
|
27
27
|
const MiscUtils_1 = require("../../utils/MiscUtils");
|
|
28
|
+
const PageLogListeners_1 = require("../../utils/PageLogListeners");
|
|
28
29
|
const cacheLocator_1 = require("../ai/cache/cacheLocator");
|
|
29
30
|
const extendPage_1 = require("../page/extendPage");
|
|
30
31
|
const tbd_1 = require("../page/tbd");
|
|
@@ -101,6 +102,11 @@ exports.test = test_1.test.extend({
|
|
|
101
102
|
});
|
|
102
103
|
extendedPage._dnb.donobuFlowMetadata.name = getSanitizedTestName(testInfo);
|
|
103
104
|
extendedPage._dnb.donobuFlowMetadata.overallObjective = overallObjective;
|
|
105
|
+
// Register browser console and network listeners so that logs from these
|
|
106
|
+
// sources are captured into the flow's logBuffer. In Studio-launched flows
|
|
107
|
+
// this is done by WebTargetInspector.initialize(), but that method is not
|
|
108
|
+
// called during test runs, so we wire the listeners up here directly.
|
|
109
|
+
(0, PageLogListeners_1.registerPageLogListeners)(page);
|
|
104
110
|
// Bind the Playwright-provided `use` callback to an async resource so that
|
|
105
111
|
// any microtasks scheduled inside the test body keep the flow logging
|
|
106
112
|
// context. Without this, Playwright may re-use earlier async resources that
|
|
@@ -20,7 +20,7 @@ function getEnvSnapshot() {
|
|
|
20
20
|
}
|
|
21
21
|
async function getOrCreateDonobuStack() {
|
|
22
22
|
if (!donobuStack) {
|
|
23
|
-
donobuStack = await (0, DonobuStack_1.setupDonobuStack)('LOCAL', ControlPanel_1.NoOpControlPanelFactory, new EnvPersistenceVolatile_1.EnvPersistenceVolatile(getEnvSnapshot()), envVars_1.env.pick('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_BASE_URL', 'DONOBU_API_KEY', 'GOOGLE_GENERATIVE_AI_API_KEY', 'GOOGLE_GENERATIVE_AI_MODEL_NAME', 'OPENAI_API_KEY', 'OPENAI_API_MODEL_NAME', 'PERSISTENCE_PRIORITY'));
|
|
23
|
+
donobuStack = await (0, DonobuStack_1.setupDonobuStack)('LOCAL', ControlPanel_1.NoOpControlPanelFactory, new EnvPersistenceVolatile_1.EnvPersistenceVolatile(getEnvSnapshot()), envVars_1.env.pick('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_BASE_URL', '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', 'PERSISTENCE_PRIORITY'));
|
|
24
24
|
return donobuStack;
|
|
25
25
|
}
|
|
26
26
|
else {
|
|
@@ -59,7 +59,7 @@ export declare class AdminApiController {
|
|
|
59
59
|
* - no checking for flow ownership is performed, as all flows are considered owned by the
|
|
60
60
|
* local environment.
|
|
61
61
|
*/
|
|
62
|
-
static create(donobuDeploymentEnvironment: DonobuDeploymentEnvironment, 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_BASE_URL' | 'DONOBU_API_KEY' | 'GOOGLE_GENERATIVE_AI_API_KEY' | 'GOOGLE_GENERATIVE_AI_MODEL_NAME' | 'OPENAI_API_KEY' | 'OPENAI_API_MODEL_NAME' | 'PERSISTENCE_PRIORITY'>): Promise<AdminApiController>;
|
|
62
|
+
static create(donobuDeploymentEnvironment: DonobuDeploymentEnvironment, 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_BASE_URL' | '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' | 'PERSISTENCE_PRIORITY'>): Promise<AdminApiController>;
|
|
63
63
|
private constructor();
|
|
64
64
|
/**
|
|
65
65
|
* Serves the API and web assets; this blocks until stop() is called.
|
|
@@ -48,7 +48,7 @@ export declare class DonobuFlowsManager {
|
|
|
48
48
|
static readonly FLOW_NAME_MAX_LENGTH = 255;
|
|
49
49
|
private readonly flowRuntime;
|
|
50
50
|
private readonly flowCatalog;
|
|
51
|
-
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' | 'OPENAI_API_KEY' | 'OPENAI_API_MODEL_NAME'>, toolRegistry: ToolRegistry, targetRuntimePlugins: TargetRuntimePluginRegistry);
|
|
51
|
+
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);
|
|
52
52
|
/**
|
|
53
53
|
* Create a flow with the given parameters and invoke its `DonobuFlow#run`
|
|
54
54
|
* method, adding it to list of active flows.
|
|
@@ -132,7 +132,8 @@ export declare class DonobuFlowsManager {
|
|
|
132
132
|
* Resolves a GPT client using the provided GPT configuration name, falling back
|
|
133
133
|
* to environment-provided configs (BASE64_GPT_CONFIG, DONOBU_API_KEY,
|
|
134
134
|
* AWS_BEDROCK_MODEL_NAME, ANTHROPIC_API_KEY, GOOGLE_GENERATIVE_AI_API_KEY,
|
|
135
|
-
* OPENAI_API_KEY) and finally the config bound to the
|
|
135
|
+
* OPENAI_API_KEY, OLLAMA_MODEL_NAME) and finally the config bound to the
|
|
136
|
+
* 'flow-runner' agent.
|
|
136
137
|
* Returns a null client if no configuration source is available.
|
|
137
138
|
*
|
|
138
139
|
* Public for testing only.
|
|
@@ -479,7 +479,8 @@ class DonobuFlowsManager {
|
|
|
479
479
|
* Resolves a GPT client using the provided GPT configuration name, falling back
|
|
480
480
|
* to environment-provided configs (BASE64_GPT_CONFIG, DONOBU_API_KEY,
|
|
481
481
|
* AWS_BEDROCK_MODEL_NAME, ANTHROPIC_API_KEY, GOOGLE_GENERATIVE_AI_API_KEY,
|
|
482
|
-
* OPENAI_API_KEY) and finally the config bound to the
|
|
482
|
+
* OPENAI_API_KEY, OLLAMA_MODEL_NAME) and finally the config bound to the
|
|
483
|
+
* 'flow-runner' agent.
|
|
483
484
|
* Returns a null client if no configuration source is available.
|
|
484
485
|
*
|
|
485
486
|
* Public for testing only.
|
|
@@ -551,6 +552,15 @@ class DonobuFlowsManager {
|
|
|
551
552
|
apiKey: this.environ.data.OPENAI_API_KEY,
|
|
552
553
|
};
|
|
553
554
|
}
|
|
555
|
+
else if (this.environ.data.OLLAMA_MODEL_NAME) {
|
|
556
|
+
gptConfigFromEnv = {
|
|
557
|
+
type: 'OLLAMA',
|
|
558
|
+
modelName: this.environ.data.OLLAMA_MODEL_NAME,
|
|
559
|
+
...(this.environ.data.OLLAMA_API_URL
|
|
560
|
+
? { apiUrl: this.environ.data.OLLAMA_API_URL }
|
|
561
|
+
: {}),
|
|
562
|
+
};
|
|
563
|
+
}
|
|
554
564
|
if (gptConfigFromEnv) {
|
|
555
565
|
const gptClient = await this.gptClientFactory.createClient(gptConfigFromEnv);
|
|
556
566
|
return {
|
|
@@ -43,6 +43,8 @@ export declare function setupDonobuStack(donobuDeploymentEnvironment: DonobuDepl
|
|
|
43
43
|
ANTHROPIC_MODEL_NAME: import("zod/v4").ZodOptional<import("zod/v4").ZodString>;
|
|
44
44
|
GOOGLE_GENERATIVE_AI_API_KEY: import("zod/v4").ZodOptional<import("zod/v4").ZodString>;
|
|
45
45
|
GOOGLE_GENERATIVE_AI_MODEL_NAME: import("zod/v4").ZodOptional<import("zod/v4").ZodString>;
|
|
46
|
+
OLLAMA_MODEL_NAME: import("zod/v4").ZodOptional<import("zod/v4").ZodString>;
|
|
47
|
+
OLLAMA_API_URL: import("zod/v4").ZodOptional<import("zod/v4").ZodString>;
|
|
46
48
|
OPENAI_API_KEY: import("zod/v4").ZodOptional<import("zod/v4").ZodString>;
|
|
47
49
|
OPENAI_API_MODEL_NAME: import("zod/v4").ZodOptional<import("zod/v4").ZodString>;
|
|
48
50
|
PERSISTENCE_PRIORITY: import("zod/v4").ZodDefault<import("zod/v4").ZodArray<import("zod/v4").ZodString>>;
|
|
@@ -59,6 +61,8 @@ export declare function setupDonobuStack(donobuDeploymentEnvironment: DonobuDepl
|
|
|
59
61
|
ANTHROPIC_MODEL_NAME?: string | undefined;
|
|
60
62
|
GOOGLE_GENERATIVE_AI_API_KEY?: string | undefined;
|
|
61
63
|
GOOGLE_GENERATIVE_AI_MODEL_NAME?: string | undefined;
|
|
64
|
+
OLLAMA_MODEL_NAME?: string | undefined;
|
|
65
|
+
OLLAMA_API_URL?: string | undefined;
|
|
62
66
|
OPENAI_API_KEY?: string | undefined;
|
|
63
67
|
OPENAI_API_MODEL_NAME?: string | undefined;
|
|
64
68
|
PERSISTENCE_PRIORITY: string[];
|
|
@@ -29,7 +29,7 @@ const ToolRegistry_1 = require("./ToolRegistry");
|
|
|
29
29
|
* then having this snapshot is relevant so that tests can use normal
|
|
30
30
|
* environment variables.
|
|
31
31
|
*/
|
|
32
|
-
async function setupDonobuStack(donobuDeploymentEnvironment, controlPanelFactory, envPersistenceVolatile, environ = envVars_1.env.pick('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_BASE_URL', 'DONOBU_API_KEY', 'GOOGLE_GENERATIVE_AI_API_KEY', 'GOOGLE_GENERATIVE_AI_MODEL_NAME', 'OPENAI_API_KEY', 'OPENAI_API_MODEL_NAME', 'PERSISTENCE_PRIORITY')) {
|
|
32
|
+
async function setupDonobuStack(donobuDeploymentEnvironment, controlPanelFactory, envPersistenceVolatile, environ = envVars_1.env.pick('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_BASE_URL', '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', 'PERSISTENCE_PRIORITY')) {
|
|
33
33
|
const loadedPlugins = await loadDefaultPlugins();
|
|
34
34
|
const resolvedToolRegistry = await (0, ToolRegistry_1.createDefaultToolRegistry)(loadedPlugins.tools);
|
|
35
35
|
const persistencePlugins = new PersistencePlugin_1.PersistencePluginRegistry(loadedPlugins.persistencePlugins);
|
|
@@ -6,6 +6,7 @@ const SetDonobuAnnotations_1 = require("../bindings/SetDonobuAnnotations");
|
|
|
6
6
|
const PageClosedException_1 = require("../exceptions/PageClosedException");
|
|
7
7
|
const BrowserUtils_1 = require("../utils/BrowserUtils");
|
|
8
8
|
const Logger_1 = require("../utils/Logger");
|
|
9
|
+
const PageLogListeners_1 = require("../utils/PageLogListeners");
|
|
9
10
|
const PlaywrightUtils_1 = require("../utils/PlaywrightUtils");
|
|
10
11
|
const PageInspector_1 = require("./PageInspector");
|
|
11
12
|
/**
|
|
@@ -185,81 +186,7 @@ The active (i.e. in focus) tab is ${this._target.current.url()}`;
|
|
|
185
186
|
/* ------------------------------------------------------------------ */
|
|
186
187
|
handleNewPage(page, callbacks) {
|
|
187
188
|
this._target.current = page;
|
|
188
|
-
|
|
189
|
-
const { url, lineNumber, columnNumber } = msg.location();
|
|
190
|
-
const hasSourceLocation = lineNumber !== 0 || columnNumber !== 0;
|
|
191
|
-
const meta = url
|
|
192
|
-
? hasSourceLocation
|
|
193
|
-
? { url, lineNumber, columnNumber }
|
|
194
|
-
: { url }
|
|
195
|
-
: undefined;
|
|
196
|
-
switch (msg.type()) {
|
|
197
|
-
case 'error':
|
|
198
|
-
Logger_1.browserLogger.error(msg.text(), meta);
|
|
199
|
-
break;
|
|
200
|
-
case 'warning':
|
|
201
|
-
Logger_1.browserLogger.warn(msg.text(), meta);
|
|
202
|
-
break;
|
|
203
|
-
case 'debug':
|
|
204
|
-
Logger_1.browserLogger.debug(msg.text(), meta);
|
|
205
|
-
break;
|
|
206
|
-
default:
|
|
207
|
-
Logger_1.browserLogger.info(msg.text(), meta);
|
|
208
|
-
break;
|
|
209
|
-
}
|
|
210
|
-
});
|
|
211
|
-
page.on('pageerror', (error) => {
|
|
212
|
-
Logger_1.browserLogger.error(error.message, {
|
|
213
|
-
stack: error.stack,
|
|
214
|
-
url: page.url(),
|
|
215
|
-
});
|
|
216
|
-
});
|
|
217
|
-
// Fallback timing: track request start times keyed by the Request object
|
|
218
|
-
// itself (via WeakMap) so concurrent requests to the same URL don't collide.
|
|
219
|
-
// Prefer Playwright's native timing API when it has data.
|
|
220
|
-
const requestStartTimes = new WeakMap();
|
|
221
|
-
page.on('request', (request) => {
|
|
222
|
-
requestStartTimes.set(request, Date.now());
|
|
223
|
-
});
|
|
224
|
-
const getDuration = (request) => {
|
|
225
|
-
const timing = request.timing();
|
|
226
|
-
if (timing.responseEnd >= 0) {
|
|
227
|
-
return Math.round(timing.responseEnd);
|
|
228
|
-
}
|
|
229
|
-
const startTime = requestStartTimes.get(request);
|
|
230
|
-
return startTime !== undefined ? Date.now() - startTime : undefined;
|
|
231
|
-
};
|
|
232
|
-
page.on('response', (response) => {
|
|
233
|
-
const request = response.request();
|
|
234
|
-
const status = response.status();
|
|
235
|
-
const duration = getDuration(request);
|
|
236
|
-
const meta = {
|
|
237
|
-
method: request.method(),
|
|
238
|
-
url: request.url(),
|
|
239
|
-
status,
|
|
240
|
-
duration,
|
|
241
|
-
resourceType: request.resourceType(),
|
|
242
|
-
};
|
|
243
|
-
if (status >= 500) {
|
|
244
|
-
Logger_1.networkLogger.error(request.url(), meta);
|
|
245
|
-
}
|
|
246
|
-
else if (status >= 400) {
|
|
247
|
-
Logger_1.networkLogger.warn(request.url(), meta);
|
|
248
|
-
}
|
|
249
|
-
else {
|
|
250
|
-
Logger_1.networkLogger.info(request.url(), meta);
|
|
251
|
-
}
|
|
252
|
-
});
|
|
253
|
-
page.on('requestfailed', (request) => {
|
|
254
|
-
const duration = getDuration(request);
|
|
255
|
-
Logger_1.networkLogger.error(`${request.url()} FAILED: ${request.failure()?.errorText}`, {
|
|
256
|
-
method: request.method(),
|
|
257
|
-
url: request.url(),
|
|
258
|
-
resourceType: request.resourceType(),
|
|
259
|
-
failureReason: request.failure()?.errorText,
|
|
260
|
-
duration,
|
|
261
|
-
});
|
|
262
|
-
});
|
|
189
|
+
(0, PageLogListeners_1.registerPageLogListeners)(page);
|
|
263
190
|
if (callbacks.metadata.runMode !== 'INSTRUCT') {
|
|
264
191
|
page.on('domcontentloaded', async () => {
|
|
265
192
|
await this._interactionVisualizer.showMouse(page);
|
|
@@ -16,6 +16,12 @@ export declare const GoogleGenerativeAiConfigSchema: z.ZodObject<{
|
|
|
16
16
|
modelName: z.ZodString;
|
|
17
17
|
}, z.core.$strip>;
|
|
18
18
|
export type GoogleGenerativeAiConfig = z.infer<typeof GoogleGenerativeAiConfigSchema>;
|
|
19
|
+
export declare const OllamaConfigSchema: z.ZodObject<{
|
|
20
|
+
type: z.ZodLiteral<"OLLAMA">;
|
|
21
|
+
modelName: z.ZodString;
|
|
22
|
+
apiUrl: z.ZodOptional<z.ZodString>;
|
|
23
|
+
}, z.core.$strip>;
|
|
24
|
+
export type OllamaConfig = z.infer<typeof OllamaConfigSchema>;
|
|
19
25
|
export declare const OpenAiConfigSchema: z.ZodObject<{
|
|
20
26
|
type: z.ZodLiteral<"OPENAI">;
|
|
21
27
|
apiKey: z.ZodString;
|
|
@@ -45,6 +51,10 @@ export declare const GptConfigSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
45
51
|
type: z.ZodLiteral<"GOOGLE_GEMINI">;
|
|
46
52
|
apiKey: z.ZodString;
|
|
47
53
|
modelName: z.ZodString;
|
|
54
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
55
|
+
type: z.ZodLiteral<"OLLAMA">;
|
|
56
|
+
modelName: z.ZodString;
|
|
57
|
+
apiUrl: z.ZodOptional<z.ZodString>;
|
|
48
58
|
}, z.core.$strip>, z.ZodObject<{
|
|
49
59
|
type: z.ZodLiteral<"OPENAI">;
|
|
50
60
|
apiKey: z.ZodString;
|
|
@@ -71,6 +81,10 @@ export declare const GptConfigInputSchema: z.ZodUnion<readonly [z.ZodDiscriminat
|
|
|
71
81
|
type: z.ZodLiteral<"GOOGLE_GEMINI">;
|
|
72
82
|
apiKey: z.ZodString;
|
|
73
83
|
modelName: z.ZodString;
|
|
84
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
85
|
+
type: z.ZodLiteral<"OLLAMA">;
|
|
86
|
+
modelName: z.ZodString;
|
|
87
|
+
apiUrl: z.ZodOptional<z.ZodString>;
|
|
74
88
|
}, z.core.$strip>, z.ZodObject<{
|
|
75
89
|
type: z.ZodLiteral<"OPENAI">;
|
|
76
90
|
apiKey: z.ZodString;
|
package/dist/models/GptConfig.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.GptConfigInputSchema = exports.GptConfigSchema = exports.VercelAiConfigSchema = exports.OpenAiConfigSchema = exports.GoogleGenerativeAiConfigSchema = exports.DonobuGptClientConfigSchema = exports.AnthropicConfigSchema = void 0;
|
|
3
|
+
exports.GptConfigInputSchema = exports.GptConfigSchema = exports.VercelAiConfigSchema = exports.OpenAiConfigSchema = exports.OllamaConfigSchema = exports.GoogleGenerativeAiConfigSchema = exports.DonobuGptClientConfigSchema = exports.AnthropicConfigSchema = void 0;
|
|
4
4
|
const v4_1 = require("zod/v4");
|
|
5
5
|
exports.AnthropicConfigSchema = v4_1.z.object({
|
|
6
6
|
type: v4_1.z.literal('ANTHROPIC'),
|
|
@@ -16,6 +16,11 @@ exports.GoogleGenerativeAiConfigSchema = v4_1.z.object({
|
|
|
16
16
|
apiKey: v4_1.z.string(),
|
|
17
17
|
modelName: v4_1.z.string(),
|
|
18
18
|
});
|
|
19
|
+
exports.OllamaConfigSchema = v4_1.z.object({
|
|
20
|
+
type: v4_1.z.literal('OLLAMA'),
|
|
21
|
+
modelName: v4_1.z.string(),
|
|
22
|
+
apiUrl: v4_1.z.string().optional(),
|
|
23
|
+
});
|
|
19
24
|
exports.OpenAiConfigSchema = v4_1.z.object({
|
|
20
25
|
type: v4_1.z.literal('OPENAI'),
|
|
21
26
|
apiKey: v4_1.z.string(),
|
|
@@ -36,6 +41,7 @@ exports.GptConfigSchema = v4_1.z.discriminatedUnion('type', [
|
|
|
36
41
|
exports.AnthropicConfigSchema,
|
|
37
42
|
exports.DonobuGptClientConfigSchema,
|
|
38
43
|
exports.GoogleGenerativeAiConfigSchema,
|
|
44
|
+
exports.OllamaConfigSchema,
|
|
39
45
|
exports.OpenAiConfigSchema,
|
|
40
46
|
exports.VercelAiConfigSchema,
|
|
41
47
|
]);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Page } from 'playwright';
|
|
2
|
+
/**
|
|
3
|
+
* Registers Playwright page event listeners that route browser console messages
|
|
4
|
+
* and network request/response data to the {@link browserLogger} and
|
|
5
|
+
* {@link networkLogger} Winston loggers. These loggers include a
|
|
6
|
+
* {@link FlowLogBufferTransport} that captures entries into the per-flow
|
|
7
|
+
* log buffer (when one is available via AsyncLocalStorage or the process-local
|
|
8
|
+
* fallback).
|
|
9
|
+
*
|
|
10
|
+
* This function is called from both {@link WebTargetInspector.handleNewPage}
|
|
11
|
+
* (Studio-launched flows) and the Playwright test extension fixture, ensuring
|
|
12
|
+
* identical logging behaviour across both runtime contexts.
|
|
13
|
+
*/
|
|
14
|
+
export declare function registerPageLogListeners(page: Page): void;
|
|
15
|
+
//# sourceMappingURL=PageLogListeners.d.ts.map
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerPageLogListeners = registerPageLogListeners;
|
|
4
|
+
const Logger_1 = require("./Logger");
|
|
5
|
+
/**
|
|
6
|
+
* Registers Playwright page event listeners that route browser console messages
|
|
7
|
+
* and network request/response data to the {@link browserLogger} and
|
|
8
|
+
* {@link networkLogger} Winston loggers. These loggers include a
|
|
9
|
+
* {@link FlowLogBufferTransport} that captures entries into the per-flow
|
|
10
|
+
* log buffer (when one is available via AsyncLocalStorage or the process-local
|
|
11
|
+
* fallback).
|
|
12
|
+
*
|
|
13
|
+
* This function is called from both {@link WebTargetInspector.handleNewPage}
|
|
14
|
+
* (Studio-launched flows) and the Playwright test extension fixture, ensuring
|
|
15
|
+
* identical logging behaviour across both runtime contexts.
|
|
16
|
+
*/
|
|
17
|
+
function registerPageLogListeners(page) {
|
|
18
|
+
page.on('console', (msg) => {
|
|
19
|
+
const { url, lineNumber, columnNumber } = msg.location();
|
|
20
|
+
const hasSourceLocation = lineNumber !== 0 || columnNumber !== 0;
|
|
21
|
+
const meta = url
|
|
22
|
+
? hasSourceLocation
|
|
23
|
+
? { url, lineNumber, columnNumber }
|
|
24
|
+
: { url }
|
|
25
|
+
: undefined;
|
|
26
|
+
switch (msg.type()) {
|
|
27
|
+
case 'error':
|
|
28
|
+
Logger_1.browserLogger.error(msg.text(), meta);
|
|
29
|
+
break;
|
|
30
|
+
case 'warning':
|
|
31
|
+
Logger_1.browserLogger.warn(msg.text(), meta);
|
|
32
|
+
break;
|
|
33
|
+
case 'debug':
|
|
34
|
+
Logger_1.browserLogger.debug(msg.text(), meta);
|
|
35
|
+
break;
|
|
36
|
+
default:
|
|
37
|
+
Logger_1.browserLogger.info(msg.text(), meta);
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
page.on('pageerror', (error) => {
|
|
42
|
+
Logger_1.browserLogger.error(error.message, {
|
|
43
|
+
stack: error.stack,
|
|
44
|
+
url: page.url(),
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
// Fallback timing: track request start times keyed by the Request object
|
|
48
|
+
// itself (via WeakMap) so concurrent requests to the same URL don't collide.
|
|
49
|
+
// Prefer Playwright's native timing API when it has data.
|
|
50
|
+
const requestStartTimes = new WeakMap();
|
|
51
|
+
page.on('request', (request) => {
|
|
52
|
+
requestStartTimes.set(request, Date.now());
|
|
53
|
+
});
|
|
54
|
+
const getDuration = (request) => {
|
|
55
|
+
const timing = request.timing();
|
|
56
|
+
if (timing.responseEnd >= 0) {
|
|
57
|
+
return Math.round(timing.responseEnd);
|
|
58
|
+
}
|
|
59
|
+
const startTime = requestStartTimes.get(request);
|
|
60
|
+
return startTime !== undefined ? Date.now() - startTime : undefined;
|
|
61
|
+
};
|
|
62
|
+
page.on('response', (response) => {
|
|
63
|
+
const request = response.request();
|
|
64
|
+
const status = response.status();
|
|
65
|
+
const duration = getDuration(request);
|
|
66
|
+
const meta = {
|
|
67
|
+
method: request.method(),
|
|
68
|
+
url: request.url(),
|
|
69
|
+
status,
|
|
70
|
+
duration,
|
|
71
|
+
resourceType: request.resourceType(),
|
|
72
|
+
};
|
|
73
|
+
if (status >= 500) {
|
|
74
|
+
Logger_1.networkLogger.error(request.url(), meta);
|
|
75
|
+
}
|
|
76
|
+
else if (status >= 400) {
|
|
77
|
+
Logger_1.networkLogger.warn(request.url(), meta);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
Logger_1.networkLogger.info(request.url(), meta);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
page.on('requestfailed', (request) => {
|
|
84
|
+
const duration = getDuration(request);
|
|
85
|
+
Logger_1.networkLogger.error(`${request.url()} FAILED: ${request.failure()?.errorText}`, {
|
|
86
|
+
method: request.method(),
|
|
87
|
+
url: request.url(),
|
|
88
|
+
resourceType: request.resourceType(),
|
|
89
|
+
failureReason: request.failure()?.errorText,
|
|
90
|
+
duration,
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=PageLogListeners.js.map
|