@browserbasehq/orca 3.2.0-preview.1 → 3.2.0-preview.2
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/cjs/lib/utils.d.ts +1 -0
- package/dist/cjs/lib/utils.js +4 -0
- package/dist/cjs/lib/utils.js.map +1 -1
- package/dist/cjs/lib/v3/agent/AnthropicCUAClient.js +4 -6
- package/dist/cjs/lib/v3/agent/AnthropicCUAClient.js.map +1 -1
- package/dist/cjs/lib/v3/agent/GoogleCUAClient.js +4 -6
- package/dist/cjs/lib/v3/agent/GoogleCUAClient.js.map +1 -1
- package/dist/cjs/lib/v3/agent/OpenAICUAClient.js +4 -6
- package/dist/cjs/lib/v3/agent/OpenAICUAClient.js.map +1 -1
- package/dist/cjs/lib/v3/agent/prompts/agentSystemPrompt.d.ts +2 -0
- package/dist/cjs/lib/v3/agent/prompts/agentSystemPrompt.js +2 -2
- package/dist/cjs/lib/v3/agent/prompts/agentSystemPrompt.js.map +1 -1
- package/dist/cjs/lib/v3/agent/tools/{search.js → braveSearch.js} +1 -1
- package/dist/cjs/lib/v3/agent/tools/braveSearch.js.map +1 -0
- package/dist/cjs/lib/v3/agent/tools/browserbaseSearch.d.ts +13 -0
- package/dist/cjs/lib/v3/agent/tools/browserbaseSearch.js +70 -0
- package/dist/cjs/lib/v3/agent/tools/browserbaseSearch.js.map +1 -0
- package/dist/cjs/lib/v3/agent/tools/index.d.ts +14 -3
- package/dist/cjs/lib/v3/agent/tools/index.js +7 -3
- package/dist/cjs/lib/v3/agent/tools/index.js.map +1 -1
- package/dist/cjs/lib/v3/eventStore.d.ts +41 -0
- package/dist/cjs/lib/v3/eventStore.js +375 -0
- package/dist/cjs/lib/v3/eventStore.js.map +1 -0
- package/dist/cjs/lib/v3/flowLogger.d.ts +62 -103
- package/dist/cjs/lib/v3/flowLogger.js +362 -773
- package/dist/cjs/lib/v3/flowLogger.js.map +1 -1
- package/dist/cjs/lib/v3/handlers/handlerUtils/actHandlerUtils.js +21 -33
- package/dist/cjs/lib/v3/handlers/handlerUtils/actHandlerUtils.js.map +1 -1
- package/dist/cjs/lib/v3/handlers/v3AgentHandler.d.ts +0 -4
- package/dist/cjs/lib/v3/handlers/v3AgentHandler.js +14 -34
- package/dist/cjs/lib/v3/handlers/v3AgentHandler.js.map +1 -1
- package/dist/cjs/lib/v3/handlers/v3CuaAgentHandler.js +10 -12
- package/dist/cjs/lib/v3/handlers/v3CuaAgentHandler.js.map +1 -1
- package/dist/cjs/lib/v3/llm/aisdk.js +10 -16
- package/dist/cjs/lib/v3/llm/aisdk.js.map +1 -1
- package/dist/cjs/lib/v3/types/public/agent.d.ts +16 -2
- package/dist/cjs/lib/v3/types/public/agent.js.map +1 -1
- package/dist/cjs/lib/v3/types/public/options.d.ts +5 -0
- package/dist/cjs/lib/v3/types/public/options.js.map +1 -1
- package/dist/cjs/lib/v3/understudy/cdp.d.ts +3 -12
- package/dist/cjs/lib/v3/understudy/cdp.js +83 -10
- package/dist/cjs/lib/v3/understudy/cdp.js.map +1 -1
- package/dist/cjs/lib/v3/understudy/page.js +32 -17
- package/dist/cjs/lib/v3/understudy/page.js.map +1 -1
- package/dist/cjs/lib/v3/v3.d.ts +10 -0
- package/dist/cjs/lib/v3/v3.js +181 -157
- package/dist/cjs/lib/v3/v3.js.map +1 -1
- package/dist/cjs/tests/unit/public-api/public-types.test.js.map +1 -1
- package/dist/esm/lib/utils.d.ts +1 -0
- package/dist/esm/lib/utils.js +3 -0
- package/dist/esm/lib/utils.js.map +1 -1
- package/dist/esm/lib/v3/agent/AnthropicCUAClient.js +5 -7
- package/dist/esm/lib/v3/agent/AnthropicCUAClient.js.map +1 -1
- package/dist/esm/lib/v3/agent/GoogleCUAClient.js +5 -7
- package/dist/esm/lib/v3/agent/GoogleCUAClient.js.map +1 -1
- package/dist/esm/lib/v3/agent/OpenAICUAClient.js +5 -7
- package/dist/esm/lib/v3/agent/OpenAICUAClient.js.map +1 -1
- package/dist/esm/lib/v3/agent/prompts/agentSystemPrompt.d.ts +2 -0
- package/dist/esm/lib/v3/agent/prompts/agentSystemPrompt.js +2 -2
- package/dist/esm/lib/v3/agent/prompts/agentSystemPrompt.js.map +1 -1
- package/dist/esm/lib/v3/agent/tools/{search.js → braveSearch.js} +1 -1
- package/dist/esm/lib/v3/agent/tools/braveSearch.js.map +1 -0
- package/dist/esm/lib/v3/agent/tools/browserbaseSearch.d.ts +13 -0
- package/dist/esm/lib/v3/agent/tools/browserbaseSearch.js +66 -0
- package/dist/esm/lib/v3/agent/tools/browserbaseSearch.js.map +1 -0
- package/dist/esm/lib/v3/agent/tools/index.d.ts +14 -3
- package/dist/esm/lib/v3/agent/tools/index.js +7 -3
- package/dist/esm/lib/v3/agent/tools/index.js.map +1 -1
- package/dist/esm/lib/v3/eventStore.d.ts +41 -0
- package/dist/esm/lib/v3/eventStore.js +363 -0
- package/dist/esm/lib/v3/eventStore.js.map +1 -0
- package/dist/esm/lib/v3/flowLogger.d.ts +62 -103
- package/dist/esm/lib/v3/flowLogger.js +356 -762
- package/dist/esm/lib/v3/flowLogger.js.map +1 -1
- package/dist/esm/lib/v3/handlers/handlerUtils/actHandlerUtils.js +22 -34
- package/dist/esm/lib/v3/handlers/handlerUtils/actHandlerUtils.js.map +1 -1
- package/dist/esm/lib/v3/handlers/v3AgentHandler.d.ts +0 -4
- package/dist/esm/lib/v3/handlers/v3AgentHandler.js +16 -36
- package/dist/esm/lib/v3/handlers/v3AgentHandler.js.map +1 -1
- package/dist/esm/lib/v3/handlers/v3CuaAgentHandler.js +11 -13
- package/dist/esm/lib/v3/handlers/v3CuaAgentHandler.js.map +1 -1
- package/dist/esm/lib/v3/llm/aisdk.js +11 -17
- package/dist/esm/lib/v3/llm/aisdk.js.map +1 -1
- package/dist/esm/lib/v3/types/public/agent.d.ts +16 -2
- package/dist/esm/lib/v3/types/public/agent.js.map +1 -1
- package/dist/esm/lib/v3/types/public/options.d.ts +5 -0
- package/dist/esm/lib/v3/types/public/options.js.map +1 -1
- package/dist/esm/lib/v3/understudy/cdp.d.ts +3 -12
- package/dist/esm/lib/v3/understudy/cdp.js +83 -10
- package/dist/esm/lib/v3/understudy/cdp.js.map +1 -1
- package/dist/esm/lib/v3/understudy/page.js +33 -18
- package/dist/esm/lib/v3/understudy/page.js.map +1 -1
- package/dist/esm/lib/v3/v3.d.ts +10 -0
- package/dist/esm/lib/v3/v3.js +182 -158
- package/dist/esm/lib/v3/v3.js.map +1 -1
- package/dist/esm/tests/unit/public-api/public-types.test.js.map +1 -1
- package/package.json +1 -3
- package/dist/cjs/lib/v3/agent/tools/search.js.map +0 -1
- package/dist/cjs/tests/unit/rerender-missing-shadows.test.d.ts +0 -1
- package/dist/cjs/tests/unit/rerender-missing-shadows.test.js +0 -209
- package/dist/cjs/tests/unit/rerender-missing-shadows.test.js.map +0 -1
- package/dist/esm/lib/v3/agent/tools/search.js.map +0 -1
- package/dist/esm/tests/unit/rerender-missing-shadows.test.d.ts +0 -1
- package/dist/esm/tests/unit/rerender-missing-shadows.test.js +0 -207
- package/dist/esm/tests/unit/rerender-missing-shadows.test.js.map +0 -1
- /package/dist/cjs/lib/v3/agent/tools/{search.d.ts → braveSearch.d.ts} +0 -0
- /package/dist/esm/lib/v3/agent/tools/{search.d.ts → braveSearch.d.ts} +0 -0
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.FileEventStore = void 0;
|
|
7
|
+
exports.aggregateFlowEventMetrics = aggregateFlowEventMetrics;
|
|
8
|
+
exports.getConfigDir = getConfigDir;
|
|
9
|
+
exports.setEventStore = setEventStore;
|
|
10
|
+
exports.getEventStore = getEventStore;
|
|
11
|
+
exports.destroyEventStore = destroyEventStore;
|
|
12
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
13
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
14
|
+
const node_stream_1 = require("node:stream");
|
|
15
|
+
const pino_1 = __importDefault(require("pino"));
|
|
16
|
+
const MAX_LINE_LENGTH = 160;
|
|
17
|
+
const CONFIG_DIR = process.env.BROWSERBASE_CONFIG_DIR || "";
|
|
18
|
+
// helper to take a list of events and compute aggregate metrics
|
|
19
|
+
function aggregateFlowEventMetrics(events) {
|
|
20
|
+
return events.reduce((totals, event) => {
|
|
21
|
+
if (event.eventType === "LlmRequestEvent") {
|
|
22
|
+
totals.llmRequests += 1;
|
|
23
|
+
}
|
|
24
|
+
if (event.eventType === "LlmResponseEvent") {
|
|
25
|
+
const data = event.data;
|
|
26
|
+
totals.inputTokens += data?.inputTokens ?? 0;
|
|
27
|
+
totals.outputTokens += data?.outputTokens ?? 0;
|
|
28
|
+
}
|
|
29
|
+
if (event.eventType === "CdpCallEvent") {
|
|
30
|
+
totals.cdpEvents += 1;
|
|
31
|
+
}
|
|
32
|
+
return totals;
|
|
33
|
+
}, {
|
|
34
|
+
llmRequests: 0,
|
|
35
|
+
inputTokens: 0,
|
|
36
|
+
outputTokens: 0,
|
|
37
|
+
cdpEvents: 0,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
function truncateCdpIds(value) {
|
|
41
|
+
return value.replace(/([iI]d:?"?)([0-9A-F]{32})(?="?[,})\s]|$)/g, (_, prefix, id) => `${prefix}${id.slice(0, 4)}…${id.slice(-4)}`);
|
|
42
|
+
}
|
|
43
|
+
function sanitizeSinkValue(value) {
|
|
44
|
+
if (typeof value === "string") {
|
|
45
|
+
return truncateCdpIds(value);
|
|
46
|
+
}
|
|
47
|
+
if (Array.isArray(value)) {
|
|
48
|
+
return value.map((entry) => sanitizeSinkValue(entry));
|
|
49
|
+
}
|
|
50
|
+
if (value && typeof value === "object") {
|
|
51
|
+
return Object.fromEntries(Object.entries(value).map(([key, entry]) => [
|
|
52
|
+
key,
|
|
53
|
+
sanitizeSinkValue(entry),
|
|
54
|
+
]));
|
|
55
|
+
}
|
|
56
|
+
return value;
|
|
57
|
+
}
|
|
58
|
+
function sanitizeEventForFileStore(event) {
|
|
59
|
+
if (!event.eventType.startsWith("Cdp")) {
|
|
60
|
+
return event;
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
...event,
|
|
64
|
+
data: sanitizeSinkValue(event.data),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function truncateLine(value, maxLen) {
|
|
68
|
+
const collapsed = value.replace(/\s+/g, " ");
|
|
69
|
+
if (collapsed.length <= maxLen) {
|
|
70
|
+
return collapsed;
|
|
71
|
+
}
|
|
72
|
+
const endLen = Math.floor(maxLen * 0.3);
|
|
73
|
+
const startLen = maxLen - endLen - 1;
|
|
74
|
+
return `${collapsed.slice(0, startLen)}…${collapsed.slice(-endLen)}`;
|
|
75
|
+
}
|
|
76
|
+
function formatValue(value) {
|
|
77
|
+
if (typeof value === "string")
|
|
78
|
+
return `'${value}'`;
|
|
79
|
+
if (value == null || typeof value !== "object")
|
|
80
|
+
return String(value);
|
|
81
|
+
try {
|
|
82
|
+
return JSON.stringify(value);
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
return "[unserializable]";
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
function formatArgs(args) {
|
|
89
|
+
if (args === undefined) {
|
|
90
|
+
return "";
|
|
91
|
+
}
|
|
92
|
+
return (Array.isArray(args) ? args : [args])
|
|
93
|
+
.filter((entry) => entry !== undefined)
|
|
94
|
+
.map(formatValue)
|
|
95
|
+
.filter((entry) => entry.length > 0)
|
|
96
|
+
.join(", ");
|
|
97
|
+
}
|
|
98
|
+
function shortId(id) {
|
|
99
|
+
return id ? id.slice(-4) : "-";
|
|
100
|
+
}
|
|
101
|
+
let nonce = 0;
|
|
102
|
+
function formatTimestamp() {
|
|
103
|
+
const date = new Date();
|
|
104
|
+
const pad = (value, width = 2) => String(value).padStart(width, "0");
|
|
105
|
+
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}.${pad(date.getMilliseconds(), 3)}${pad(nonce++ % 100)}`;
|
|
106
|
+
}
|
|
107
|
+
const SENSITIVE_KEYS = /apikey|api_key|key|secret|token|password|passwd|pwd|credential|auth/i;
|
|
108
|
+
function sanitizeOptions(options) {
|
|
109
|
+
const sanitize = (value) => {
|
|
110
|
+
if (typeof value !== "object" || value === null)
|
|
111
|
+
return value;
|
|
112
|
+
if (Array.isArray(value))
|
|
113
|
+
return value.map(sanitize);
|
|
114
|
+
const result = {};
|
|
115
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
116
|
+
result[key] = SENSITIVE_KEYS.test(key) ? "******" : sanitize(entry);
|
|
117
|
+
}
|
|
118
|
+
return result;
|
|
119
|
+
};
|
|
120
|
+
return sanitize({ ...options });
|
|
121
|
+
}
|
|
122
|
+
function removeQuotes(value) {
|
|
123
|
+
return value
|
|
124
|
+
.replace(/([^\\])["']/g, "$1")
|
|
125
|
+
.replace(/^["']|["']$/g, "")
|
|
126
|
+
.trim();
|
|
127
|
+
}
|
|
128
|
+
function formatEventTimestamp(value) {
|
|
129
|
+
const date = new Date(value);
|
|
130
|
+
if (Number.isNaN(date.getTime())) {
|
|
131
|
+
return formatTimestamp();
|
|
132
|
+
}
|
|
133
|
+
const pad = (entry, width = 2) => String(entry).padStart(width, "0");
|
|
134
|
+
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}.${pad(date.getMilliseconds(), 3)}${pad(nonce++ % 100)}`;
|
|
135
|
+
}
|
|
136
|
+
function prettifyEvent(event) {
|
|
137
|
+
const indent = " ".repeat(event.eventParentIds.length);
|
|
138
|
+
const tag = `[#${shortId(event.eventId)}]`;
|
|
139
|
+
const data = event.data;
|
|
140
|
+
const argsStr = data?.params
|
|
141
|
+
? formatArgs(data.params)
|
|
142
|
+
: formatArgs(event.data);
|
|
143
|
+
const durationSec = data?.durationMs
|
|
144
|
+
? (data.durationMs / 1000).toFixed(2)
|
|
145
|
+
: null;
|
|
146
|
+
const promptStr = data?.prompt ? ` ${String(data.prompt)}` : "";
|
|
147
|
+
const outputStr = data?.output ? ` ${String(data.output)}` : "";
|
|
148
|
+
const hasTokens = data?.inputTokens !== undefined || data?.outputTokens !== undefined;
|
|
149
|
+
const tokenStr = hasTokens
|
|
150
|
+
? ` ꜛ${data?.inputTokens ?? 0} ꜜ${data?.outputTokens ?? 0}`
|
|
151
|
+
: "";
|
|
152
|
+
const details = [
|
|
153
|
+
event.eventType,
|
|
154
|
+
argsStr ? `(${argsStr})` : "",
|
|
155
|
+
promptStr,
|
|
156
|
+
outputStr,
|
|
157
|
+
tokenStr,
|
|
158
|
+
durationSec ? ` ${durationSec}s` : "",
|
|
159
|
+
data?.msg ? ` ${data.msg}` : "",
|
|
160
|
+
data?.error ? ` ERROR ${data.error}` : "",
|
|
161
|
+
].join("");
|
|
162
|
+
if (!details) {
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
const fullLine = `${formatEventTimestamp(event.createdAt)} ${indent}${tag} ${details}`;
|
|
166
|
+
const cleaned = removeQuotes(fullLine);
|
|
167
|
+
return truncateLine(cleaned, MAX_LINE_LENGTH);
|
|
168
|
+
}
|
|
169
|
+
function isWritable(stream) {
|
|
170
|
+
return !!(stream && !stream.destroyed && stream.writable);
|
|
171
|
+
}
|
|
172
|
+
function createJsonlStream(ctx) {
|
|
173
|
+
return new node_stream_1.Writable({
|
|
174
|
+
objectMode: true,
|
|
175
|
+
write(chunk, _, cb) {
|
|
176
|
+
if (ctx.initialized && isWritable(ctx.fileStreams.jsonl)) {
|
|
177
|
+
ctx.fileStreams.jsonl.write(chunk, cb);
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
cb();
|
|
181
|
+
},
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
function createPrettyStream(ctx) {
|
|
185
|
+
return new node_stream_1.Writable({
|
|
186
|
+
objectMode: true,
|
|
187
|
+
write(chunk, _, cb) {
|
|
188
|
+
const stream = ctx.fileStreams.pretty;
|
|
189
|
+
if (!ctx.initialized || !isWritable(stream)) {
|
|
190
|
+
cb();
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
try {
|
|
194
|
+
const event = JSON.parse(chunk);
|
|
195
|
+
const line = prettifyEvent(event);
|
|
196
|
+
if (line) {
|
|
197
|
+
stream.write(line + "\n", cb);
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
catch {
|
|
202
|
+
// fall through
|
|
203
|
+
}
|
|
204
|
+
cb();
|
|
205
|
+
},
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
function getConfigDir() {
|
|
209
|
+
return CONFIG_DIR ? node_path_1.default.resolve(CONFIG_DIR) : "";
|
|
210
|
+
}
|
|
211
|
+
function matchesQuery(event, query) {
|
|
212
|
+
if (query.sessionId && event.sessionId !== query.sessionId)
|
|
213
|
+
return false;
|
|
214
|
+
if (query.eventId) {
|
|
215
|
+
const matchesEvent = event.eventId === query.eventId ||
|
|
216
|
+
event.eventParentIds.includes(query.eventId);
|
|
217
|
+
if (!matchesEvent) {
|
|
218
|
+
return false;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
if (query.eventType) {
|
|
222
|
+
const pattern = new RegExp(`^${query.eventType
|
|
223
|
+
.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
|
|
224
|
+
.replace(/\\\*/g, ".*")}$`);
|
|
225
|
+
if (!pattern.test(event.eventType)) {
|
|
226
|
+
return false;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return true;
|
|
230
|
+
}
|
|
231
|
+
class FileEventStore {
|
|
232
|
+
sessionContexts = new Map();
|
|
233
|
+
eventsBySession = new Map();
|
|
234
|
+
subscribers = new Set();
|
|
235
|
+
async initializeSession(sessionId, v3Options) {
|
|
236
|
+
const existing = this.sessionContexts.get(sessionId);
|
|
237
|
+
if (existing) {
|
|
238
|
+
await existing.initPromise;
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
const configDir = getConfigDir();
|
|
242
|
+
const sessionDir = configDir
|
|
243
|
+
? node_path_1.default.join(configDir, "sessions", sessionId)
|
|
244
|
+
: "";
|
|
245
|
+
const ctx = {
|
|
246
|
+
logger: null,
|
|
247
|
+
sessionId,
|
|
248
|
+
sessionDir,
|
|
249
|
+
configDir,
|
|
250
|
+
initPromise: Promise.resolve(),
|
|
251
|
+
initialized: false,
|
|
252
|
+
fileStreams: {
|
|
253
|
+
pretty: null,
|
|
254
|
+
jsonl: null,
|
|
255
|
+
},
|
|
256
|
+
};
|
|
257
|
+
ctx.initPromise = this.initSessionContext(ctx, v3Options);
|
|
258
|
+
this.sessionContexts.set(sessionId, ctx);
|
|
259
|
+
await ctx.initPromise;
|
|
260
|
+
}
|
|
261
|
+
async initSessionContext(ctx, v3Options) {
|
|
262
|
+
if (!ctx.configDir) {
|
|
263
|
+
ctx.initialized = true;
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
await node_fs_1.default.promises.mkdir(ctx.sessionDir, { recursive: true });
|
|
267
|
+
if (v3Options) {
|
|
268
|
+
const sessionJsonPath = node_path_1.default.join(ctx.sessionDir, "session.json");
|
|
269
|
+
await node_fs_1.default.promises.writeFile(sessionJsonPath, JSON.stringify(sanitizeOptions(v3Options), null, 2), "utf-8");
|
|
270
|
+
}
|
|
271
|
+
const latestLink = node_path_1.default.join(ctx.configDir, "sessions", "latest");
|
|
272
|
+
try {
|
|
273
|
+
try {
|
|
274
|
+
await node_fs_1.default.promises.unlink(latestLink);
|
|
275
|
+
}
|
|
276
|
+
catch {
|
|
277
|
+
// ignore missing link
|
|
278
|
+
}
|
|
279
|
+
await node_fs_1.default.promises.symlink(ctx.sessionId, latestLink, "dir");
|
|
280
|
+
}
|
|
281
|
+
catch {
|
|
282
|
+
// symlink best effort only
|
|
283
|
+
}
|
|
284
|
+
ctx.fileStreams.pretty = node_fs_1.default.createWriteStream(node_path_1.default.join(ctx.sessionDir, "session_events.log"), { flags: "a" });
|
|
285
|
+
ctx.fileStreams.jsonl = node_fs_1.default.createWriteStream(node_path_1.default.join(ctx.sessionDir, "session_events.jsonl"), { flags: "a" });
|
|
286
|
+
ctx.initialized = true;
|
|
287
|
+
ctx.logger = (0, pino_1.default)({ level: "info" }, pino_1.default.multistream([
|
|
288
|
+
{ stream: createJsonlStream(ctx) },
|
|
289
|
+
{ stream: createPrettyStream(ctx) },
|
|
290
|
+
]));
|
|
291
|
+
}
|
|
292
|
+
async appendEvent(event) {
|
|
293
|
+
const storedEvent = sanitizeEventForFileStore(event);
|
|
294
|
+
const existing = this.eventsBySession.get(storedEvent.sessionId) ?? [];
|
|
295
|
+
existing.push(storedEvent);
|
|
296
|
+
this.eventsBySession.set(storedEvent.sessionId, existing);
|
|
297
|
+
for (const subscriber of this.subscribers) {
|
|
298
|
+
if (matchesQuery(storedEvent, subscriber.query)) {
|
|
299
|
+
subscriber.listener(storedEvent);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
const ctx = this.sessionContexts.get(storedEvent.sessionId);
|
|
303
|
+
if (!ctx) {
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
await ctx.initPromise;
|
|
307
|
+
ctx.logger?.info(storedEvent);
|
|
308
|
+
}
|
|
309
|
+
attachBus(sessionId, bus) {
|
|
310
|
+
const emit = bus.emit.bind(bus);
|
|
311
|
+
bus.emit = ((eventName, ...args) => {
|
|
312
|
+
const [event] = args;
|
|
313
|
+
if (event.sessionId === sessionId) {
|
|
314
|
+
void this.appendEvent(event);
|
|
315
|
+
}
|
|
316
|
+
return emit(eventName, ...args);
|
|
317
|
+
});
|
|
318
|
+
return () => {
|
|
319
|
+
bus.emit = emit;
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
async listEvents(query) {
|
|
323
|
+
const sourceEvents = query.sessionId
|
|
324
|
+
? [...(this.eventsBySession.get(query.sessionId) ?? [])]
|
|
325
|
+
: [...this.eventsBySession.values()].flat();
|
|
326
|
+
const filtered = sourceEvents.filter((event) => matchesQuery(event, query));
|
|
327
|
+
filtered.sort((left, right) => {
|
|
328
|
+
const createdAtOrder = left.createdAt.localeCompare(right.createdAt);
|
|
329
|
+
if (createdAtOrder !== 0) {
|
|
330
|
+
return createdAtOrder;
|
|
331
|
+
}
|
|
332
|
+
return left.eventId.localeCompare(right.eventId);
|
|
333
|
+
});
|
|
334
|
+
if (!query.limit) {
|
|
335
|
+
return filtered;
|
|
336
|
+
}
|
|
337
|
+
return filtered.slice(0, query.limit);
|
|
338
|
+
}
|
|
339
|
+
subscribe(query, listener) {
|
|
340
|
+
const subscriber = { query, listener };
|
|
341
|
+
this.subscribers.add(subscriber);
|
|
342
|
+
return () => {
|
|
343
|
+
this.subscribers.delete(subscriber);
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
async destroy() {
|
|
347
|
+
this.subscribers.clear();
|
|
348
|
+
this.eventsBySession.clear();
|
|
349
|
+
await Promise.all([...this.sessionContexts.values()].flatMap((ctx) => Object.values(ctx.fileStreams)
|
|
350
|
+
.filter(Boolean)
|
|
351
|
+
.map((stream) => new Promise((resolve) => {
|
|
352
|
+
stream.end(resolve);
|
|
353
|
+
})))).catch(() => { });
|
|
354
|
+
this.sessionContexts.clear();
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
exports.FileEventStore = FileEventStore;
|
|
358
|
+
let eventStore = null;
|
|
359
|
+
function setEventStore(store) {
|
|
360
|
+
eventStore = store;
|
|
361
|
+
}
|
|
362
|
+
function getEventStore() {
|
|
363
|
+
if (!eventStore) {
|
|
364
|
+
eventStore = new FileEventStore();
|
|
365
|
+
}
|
|
366
|
+
return eventStore;
|
|
367
|
+
}
|
|
368
|
+
async function destroyEventStore() {
|
|
369
|
+
if (!eventStore) {
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
await eventStore.destroy();
|
|
373
|
+
eventStore = null;
|
|
374
|
+
}
|
|
375
|
+
//# sourceMappingURL=eventStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eventStore.js","sourceRoot":"","sources":["../../../../lib/v3/eventStore.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { Writable } from \"node:stream\";\nimport type { EventEmitter } from \"node:events\";\nimport pino from \"pino\";\n\nimport type { V3Options } from \"./types/public/index.js\";\nimport { type FlowEvent } from \"./flowLogger.js\";\n\nconst MAX_LINE_LENGTH = 160;\nconst CONFIG_DIR = process.env.BROWSERBASE_CONFIG_DIR || \"\";\n\nexport interface FlowEventAggregateMetrics {\n llmRequests: number;\n inputTokens: number;\n outputTokens: number;\n cdpEvents: number;\n}\n\nexport interface EventStoreQuery {\n sessionId?: string;\n eventId?: string;\n eventType?: string;\n limit?: number;\n}\n\nexport type EventStoreListener = (event: FlowEvent) => void;\n\nexport interface EventStore {\n initializeSession(sessionId: string, v3Options?: V3Options): Promise<void>;\n appendEvent(event: FlowEvent): Promise<void>;\n attachBus(sessionId: string, bus: EventEmitter): () => void;\n listEvents(query: EventStoreQuery): Promise<FlowEvent[]>;\n subscribe(query: EventStoreQuery, listener: EventStoreListener): () => void;\n destroy(): Promise<void>;\n}\n\n// helper to take a list of events and compute aggregate metrics\nexport function aggregateFlowEventMetrics(\n events: FlowEvent[],\n): FlowEventAggregateMetrics {\n return events.reduce<FlowEventAggregateMetrics>(\n (totals, event) => {\n if (event.eventType === \"LlmRequestEvent\") {\n totals.llmRequests += 1;\n }\n\n if (event.eventType === \"LlmResponseEvent\") {\n const data = event.data as {\n inputTokens?: number;\n outputTokens?: number;\n };\n totals.inputTokens += data?.inputTokens ?? 0;\n totals.outputTokens += data?.outputTokens ?? 0;\n }\n\n if (event.eventType === \"CdpCallEvent\") {\n totals.cdpEvents += 1;\n }\n\n return totals;\n },\n {\n llmRequests: 0,\n inputTokens: 0,\n outputTokens: 0,\n cdpEvents: 0,\n },\n );\n}\n\ninterface SessionContext {\n logger: pino.Logger | null;\n sessionId: string;\n sessionDir: string;\n configDir: string;\n initPromise: Promise<void>;\n initialized: boolean;\n fileStreams: {\n pretty: fs.WriteStream | null;\n jsonl: fs.WriteStream | null;\n };\n}\n\ninterface EventSubscriber {\n listener: EventStoreListener;\n query: EventStoreQuery;\n}\n\nfunction truncateCdpIds(value: string): string {\n return value.replace(\n /([iI]d:?\"?)([0-9A-F]{32})(?=\"?[,})\\s]|$)/g,\n (_, prefix: string, id: string) =>\n `${prefix}${id.slice(0, 4)}…${id.slice(-4)}`,\n );\n}\n\nfunction sanitizeSinkValue(value: unknown): unknown {\n if (typeof value === \"string\") {\n return truncateCdpIds(value);\n }\n\n if (Array.isArray(value)) {\n return value.map((entry) => sanitizeSinkValue(entry));\n }\n\n if (value && typeof value === \"object\") {\n return Object.fromEntries(\n Object.entries(value).map(([key, entry]) => [\n key,\n sanitizeSinkValue(entry),\n ]),\n );\n }\n\n return value;\n}\n\nfunction sanitizeEventForFileStore(event: FlowEvent): FlowEvent {\n if (!event.eventType.startsWith(\"Cdp\")) {\n return event;\n }\n\n return {\n ...event,\n data: sanitizeSinkValue(event.data) as Record<string, unknown>,\n };\n}\n\nfunction truncateLine(value: string, maxLen: number): string {\n const collapsed = value.replace(/\\s+/g, \" \");\n if (collapsed.length <= maxLen) {\n return collapsed;\n }\n\n const endLen = Math.floor(maxLen * 0.3);\n const startLen = maxLen - endLen - 1;\n return `${collapsed.slice(0, startLen)}…${collapsed.slice(-endLen)}`;\n}\n\nfunction formatValue(value: unknown): string {\n if (typeof value === \"string\") return `'${value}'`;\n if (value == null || typeof value !== \"object\") return String(value);\n\n try {\n return JSON.stringify(value);\n } catch {\n return \"[unserializable]\";\n }\n}\n\nfunction formatArgs(args?: unknown | unknown[]): string {\n if (args === undefined) {\n return \"\";\n }\n\n return (Array.isArray(args) ? args : [args])\n .filter((entry) => entry !== undefined)\n .map(formatValue)\n .filter((entry) => entry.length > 0)\n .join(\", \");\n}\n\nfunction shortId(id: string | null | undefined): string {\n return id ? id.slice(-4) : \"-\";\n}\n\nlet nonce = 0;\nfunction formatTimestamp(): string {\n const date = new Date();\n const pad = (value: number, width = 2) => String(value).padStart(width, \"0\");\n return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}.${pad(date.getMilliseconds(), 3)}${pad(nonce++ % 100)}`;\n}\n\nconst SENSITIVE_KEYS =\n /apikey|api_key|key|secret|token|password|passwd|pwd|credential|auth/i;\n\nfunction sanitizeOptions(options: V3Options): Record<string, unknown> {\n const sanitize = (value: unknown): unknown => {\n if (typeof value !== \"object\" || value === null) return value;\n if (Array.isArray(value)) return value.map(sanitize);\n\n const result: Record<string, unknown> = {};\n for (const [key, entry] of Object.entries(value)) {\n result[key] = SENSITIVE_KEYS.test(key) ? \"******\" : sanitize(entry);\n }\n return result;\n };\n\n return sanitize({ ...options }) as Record<string, unknown>;\n}\n\nfunction removeQuotes(value: string): string {\n return value\n .replace(/([^\\\\])[\"']/g, \"$1\")\n .replace(/^[\"']|[\"']$/g, \"\")\n .trim();\n}\n\nfunction formatEventTimestamp(value: string): string {\n const date = new Date(value);\n if (Number.isNaN(date.getTime())) {\n return formatTimestamp();\n }\n\n const pad = (entry: number, width = 2) => String(entry).padStart(width, \"0\");\n return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}.${pad(date.getMilliseconds(), 3)}${pad(nonce++ % 100)}`;\n}\n\nfunction prettifyEvent(event: FlowEvent): string | null {\n const indent = \" \".repeat(event.eventParentIds.length);\n const tag = `[#${shortId(event.eventId)}]`;\n const data = event.data as {\n params?: unknown;\n prompt?: unknown;\n output?: unknown;\n durationMs?: number;\n inputTokens?: number;\n outputTokens?: number;\n error?: string;\n msg?: string;\n };\n const argsStr = data?.params\n ? formatArgs(data.params)\n : formatArgs(event.data);\n const durationSec = data?.durationMs\n ? (data.durationMs / 1000).toFixed(2)\n : null;\n const promptStr = data?.prompt ? ` ${String(data.prompt)}` : \"\";\n const outputStr = data?.output ? ` ${String(data.output)}` : \"\";\n const hasTokens =\n data?.inputTokens !== undefined || data?.outputTokens !== undefined;\n const tokenStr = hasTokens\n ? ` ꜛ${data?.inputTokens ?? 0} ꜜ${data?.outputTokens ?? 0}`\n : \"\";\n const details = [\n event.eventType,\n argsStr ? `(${argsStr})` : \"\",\n promptStr,\n outputStr,\n tokenStr,\n durationSec ? ` ${durationSec}s` : \"\",\n data?.msg ? ` ${data.msg}` : \"\",\n data?.error ? ` ERROR ${data.error}` : \"\",\n ].join(\"\");\n\n if (!details) {\n return null;\n }\n\n const fullLine = `${formatEventTimestamp(event.createdAt)} ${indent}${tag} ${details}`;\n const cleaned = removeQuotes(fullLine);\n return truncateLine(cleaned, MAX_LINE_LENGTH);\n}\n\nfunction isWritable(stream: fs.WriteStream | null): stream is fs.WriteStream {\n return !!(stream && !stream.destroyed && stream.writable);\n}\n\nfunction createJsonlStream(ctx: SessionContext): Writable {\n return new Writable({\n objectMode: true,\n write(chunk: string, _, cb) {\n if (ctx.initialized && isWritable(ctx.fileStreams.jsonl)) {\n ctx.fileStreams.jsonl.write(chunk, cb);\n return;\n }\n\n cb();\n },\n });\n}\n\nfunction createPrettyStream(ctx: SessionContext): Writable {\n return new Writable({\n objectMode: true,\n write(chunk: string, _, cb) {\n const stream = ctx.fileStreams.pretty;\n if (!ctx.initialized || !isWritable(stream)) {\n cb();\n return;\n }\n\n try {\n const event = JSON.parse(chunk) as FlowEvent;\n const line = prettifyEvent(event);\n if (line) {\n stream.write(line + \"\\n\", cb);\n return;\n }\n } catch {\n // fall through\n }\n\n cb();\n },\n });\n}\n\nexport function getConfigDir(): string {\n return CONFIG_DIR ? path.resolve(CONFIG_DIR) : \"\";\n}\n\nfunction matchesQuery(event: FlowEvent, query: EventStoreQuery): boolean {\n if (query.sessionId && event.sessionId !== query.sessionId) return false;\n if (query.eventId) {\n const matchesEvent =\n event.eventId === query.eventId ||\n event.eventParentIds.includes(query.eventId);\n if (!matchesEvent) {\n return false;\n }\n }\n if (query.eventType) {\n const pattern = new RegExp(\n `^${query.eventType\n .replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")\n .replace(/\\\\\\*/g, \".*\")}$`,\n );\n if (!pattern.test(event.eventType)) {\n return false;\n }\n }\n return true;\n}\n\nexport class FileEventStore implements EventStore {\n private readonly sessionContexts = new Map<string, SessionContext>();\n private readonly eventsBySession = new Map<string, FlowEvent[]>();\n private readonly subscribers = new Set<EventSubscriber>();\n\n async initializeSession(\n sessionId: string,\n v3Options?: V3Options,\n ): Promise<void> {\n const existing = this.sessionContexts.get(sessionId);\n if (existing) {\n await existing.initPromise;\n return;\n }\n\n const configDir = getConfigDir();\n const sessionDir = configDir\n ? path.join(configDir, \"sessions\", sessionId)\n : \"\";\n\n const ctx: SessionContext = {\n logger: null,\n sessionId,\n sessionDir,\n configDir,\n initPromise: Promise.resolve(),\n initialized: false,\n fileStreams: {\n pretty: null,\n jsonl: null,\n },\n };\n\n ctx.initPromise = this.initSessionContext(ctx, v3Options);\n this.sessionContexts.set(sessionId, ctx);\n await ctx.initPromise;\n }\n\n private async initSessionContext(\n ctx: SessionContext,\n v3Options?: V3Options,\n ): Promise<void> {\n if (!ctx.configDir) {\n ctx.initialized = true;\n return;\n }\n\n await fs.promises.mkdir(ctx.sessionDir, { recursive: true });\n\n if (v3Options) {\n const sessionJsonPath = path.join(ctx.sessionDir, \"session.json\");\n await fs.promises.writeFile(\n sessionJsonPath,\n JSON.stringify(sanitizeOptions(v3Options), null, 2),\n \"utf-8\",\n );\n }\n\n const latestLink = path.join(ctx.configDir, \"sessions\", \"latest\");\n try {\n try {\n await fs.promises.unlink(latestLink);\n } catch {\n // ignore missing link\n }\n await fs.promises.symlink(ctx.sessionId, latestLink, \"dir\");\n } catch {\n // symlink best effort only\n }\n\n ctx.fileStreams.pretty = fs.createWriteStream(\n path.join(ctx.sessionDir, \"session_events.log\"),\n { flags: \"a\" },\n );\n ctx.fileStreams.jsonl = fs.createWriteStream(\n path.join(ctx.sessionDir, \"session_events.jsonl\"),\n { flags: \"a\" },\n );\n\n ctx.initialized = true;\n ctx.logger = pino(\n { level: \"info\" },\n pino.multistream([\n { stream: createJsonlStream(ctx) },\n { stream: createPrettyStream(ctx) },\n ]),\n );\n }\n\n async appendEvent(event: FlowEvent): Promise<void> {\n const storedEvent = sanitizeEventForFileStore(event);\n const existing = this.eventsBySession.get(storedEvent.sessionId) ?? [];\n existing.push(storedEvent);\n this.eventsBySession.set(storedEvent.sessionId, existing);\n\n for (const subscriber of this.subscribers) {\n if (matchesQuery(storedEvent, subscriber.query)) {\n subscriber.listener(storedEvent);\n }\n }\n\n const ctx = this.sessionContexts.get(storedEvent.sessionId);\n if (!ctx) {\n return;\n }\n\n await ctx.initPromise;\n ctx.logger?.info(storedEvent);\n }\n\n attachBus(sessionId: string, bus: EventEmitter): () => void {\n const emit = bus.emit.bind(bus);\n bus.emit = ((eventName: string | symbol, ...args: [FlowEvent]) => {\n const [event] = args;\n if (event.sessionId === sessionId) {\n void this.appendEvent(event);\n }\n return emit(eventName, ...args);\n }) as typeof bus.emit;\n\n return () => {\n bus.emit = emit;\n };\n }\n\n async listEvents(query: EventStoreQuery): Promise<FlowEvent[]> {\n const sourceEvents = query.sessionId\n ? [...(this.eventsBySession.get(query.sessionId) ?? [])]\n : [...this.eventsBySession.values()].flat();\n\n const filtered = sourceEvents.filter((event) => matchesQuery(event, query));\n filtered.sort((left, right) => {\n const createdAtOrder = left.createdAt.localeCompare(right.createdAt);\n if (createdAtOrder !== 0) {\n return createdAtOrder;\n }\n\n return left.eventId.localeCompare(right.eventId);\n });\n\n if (!query.limit) {\n return filtered;\n }\n\n return filtered.slice(0, query.limit);\n }\n\n subscribe(query: EventStoreQuery, listener: EventStoreListener): () => void {\n const subscriber: EventSubscriber = { query, listener };\n this.subscribers.add(subscriber);\n\n return () => {\n this.subscribers.delete(subscriber);\n };\n }\n\n async destroy(): Promise<void> {\n this.subscribers.clear();\n this.eventsBySession.clear();\n\n await Promise.all(\n [...this.sessionContexts.values()].flatMap((ctx) =>\n Object.values(ctx.fileStreams)\n .filter(Boolean)\n .map(\n (stream) =>\n new Promise<void>((resolve) => {\n stream!.end(resolve);\n }),\n ),\n ),\n ).catch(() => {});\n\n this.sessionContexts.clear();\n }\n}\n\nlet eventStore: EventStore | null = null;\n\nexport function setEventStore(store: EventStore): void {\n eventStore = store;\n}\n\nexport function getEventStore(): EventStore {\n if (!eventStore) {\n eventStore = new FileEventStore();\n }\n\n return eventStore;\n}\n\nexport async function destroyEventStore(): Promise<void> {\n if (!eventStore) {\n return;\n }\n\n await eventStore.destroy();\n eventStore = null;\n}\n"]}
|
|
@@ -1,124 +1,76 @@
|
|
|
1
|
-
import
|
|
2
|
-
import pino from "pino";
|
|
1
|
+
import { EventEmitter } from "node:events";
|
|
3
2
|
import type { LanguageModelMiddleware } from "ai";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
3
|
+
export type FlowEventData = Record<string, unknown>;
|
|
4
|
+
export type FlowEventInput = Omit<FlowEvent, "eventId" | "createdAt" | "sessionId" | "eventParentIds" | "data"> & {
|
|
5
|
+
eventId?: string;
|
|
6
|
+
eventIdSuffix?: string;
|
|
7
|
+
createdAt?: string;
|
|
8
|
+
sessionId?: string;
|
|
9
|
+
eventParentIds?: string[];
|
|
10
|
+
data?: FlowEventData;
|
|
11
|
+
};
|
|
12
|
+
export declare class FlowEvent {
|
|
13
|
+
static createEventId(eventIdSuffix: string): string;
|
|
14
|
+
eventType: string;
|
|
15
|
+
eventId: string;
|
|
16
|
+
eventParentIds: string[];
|
|
17
|
+
createdAt: string;
|
|
18
|
+
sessionId: string;
|
|
19
|
+
data: FlowEventData;
|
|
20
|
+
constructor(input: FlowEventInput);
|
|
13
21
|
}
|
|
14
22
|
export interface FlowLoggerContext {
|
|
15
|
-
logger: pino.Logger;
|
|
16
|
-
metrics: FlowLoggerMetrics;
|
|
17
23
|
sessionId: string;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
initPromise: Promise<void>;
|
|
21
|
-
initialized: boolean;
|
|
22
|
-
taskId: string | null;
|
|
23
|
-
stepId: string | null;
|
|
24
|
-
stepLabel: string | null;
|
|
25
|
-
actionId: string | null;
|
|
26
|
-
actionLabel: string | null;
|
|
27
|
-
fileStreams: {
|
|
28
|
-
agent: fs.WriteStream | null;
|
|
29
|
-
stagehand: fs.WriteStream | null;
|
|
30
|
-
understudy: fs.WriteStream | null;
|
|
31
|
-
cdp: fs.WriteStream | null;
|
|
32
|
-
llm: fs.WriteStream | null;
|
|
33
|
-
jsonl: fs.WriteStream | null;
|
|
34
|
-
};
|
|
24
|
+
eventBus: EventEmitter;
|
|
25
|
+
parentEvents: FlowEvent[];
|
|
35
26
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
export declare function formatLlmPromptPreview(messages: Array<{
|
|
45
|
-
role: string;
|
|
46
|
-
content: unknown;
|
|
47
|
-
}>, options?: {
|
|
48
|
-
toolCount?: number;
|
|
49
|
-
hasSchema?: boolean;
|
|
50
|
-
}): string | undefined;
|
|
51
|
-
/**
|
|
52
|
-
* Extract a text preview from CUA-style messages.
|
|
53
|
-
* Accepts various message formats (Anthropic, OpenAI, Google).
|
|
54
|
-
*/
|
|
55
|
-
export declare function formatCuaPromptPreview(messages: unknown[], maxLen?: number): string | undefined;
|
|
56
|
-
/** Format CUA response output for logging */
|
|
57
|
-
export declare function formatCuaResponsePreview(output: unknown, maxLen?: number): string;
|
|
58
|
-
export declare class SessionFileLogger {
|
|
27
|
+
type AsyncOriginalMethod<TArgs extends unknown[] = unknown[], TResult = unknown, TThis = unknown> = (this: TThis, ...args: TArgs) => Promise<TResult>;
|
|
28
|
+
type FlowLoggerLogOptions = FlowEventInput & {
|
|
29
|
+
context?: FlowLoggerContext;
|
|
30
|
+
};
|
|
31
|
+
export declare class FlowLogger {
|
|
32
|
+
private static cloneContext;
|
|
33
|
+
private static emit;
|
|
34
|
+
private static runWithAutoStatusEventLogging;
|
|
59
35
|
/**
|
|
60
36
|
* Initialize a new logging context. Call this at the start of a session.
|
|
61
|
-
* If BROWSERBASE_CONFIG_DIR is not set, logging is disabled.
|
|
62
|
-
*/
|
|
63
|
-
static init(sessionId: string, v3Options?: V3Options): void;
|
|
64
|
-
private static initAsync;
|
|
65
|
-
static close(): Promise<void>;
|
|
66
|
-
static get sessionId(): string | null;
|
|
67
|
-
static get sessionDir(): string | null;
|
|
68
|
-
/**
|
|
69
|
-
* Get the current logger context object.
|
|
70
|
-
*/
|
|
71
|
-
static getContext(): FlowLoggerContext | null;
|
|
72
|
-
/**
|
|
73
|
-
* Start a new task and log it.
|
|
74
37
|
*/
|
|
75
|
-
static
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
static logAgentTaskCompleted(options?: {
|
|
83
|
-
cacheHit?: boolean;
|
|
84
|
-
}): void;
|
|
85
|
-
static logStagehandStepEvent({ invocation, args, label, }: {
|
|
86
|
-
invocation: string;
|
|
87
|
-
args?: unknown | unknown[];
|
|
88
|
-
label: string;
|
|
89
|
-
}): string;
|
|
90
|
-
static logStagehandStepCompleted(): void;
|
|
91
|
-
static logUnderstudyActionEvent({ actionType, target, args, }: {
|
|
92
|
-
actionType: string;
|
|
93
|
-
target?: string;
|
|
94
|
-
args?: unknown | unknown[];
|
|
95
|
-
}): string;
|
|
96
|
-
static logUnderstudyActionCompleted(): void;
|
|
38
|
+
static init(sessionId: string, eventBus: EventEmitter): FlowLoggerContext;
|
|
39
|
+
static close(context?: FlowLoggerContext | null): Promise<void>;
|
|
40
|
+
static get currentContext(): FlowLoggerContext;
|
|
41
|
+
static wrapWithLogging<TMethod extends AsyncOriginalMethod>(options: FlowLoggerLogOptions): <TWrappedMethod extends AsyncOriginalMethod<Parameters<TMethod>, Awaited<ReturnType<TMethod>>, ThisParameterType<TMethod>>>(originalMethod: TWrappedMethod) => TWrappedMethod;
|
|
42
|
+
static runWithLogging<TMethod extends AsyncOriginalMethod>(options: FlowLoggerLogOptions, originalMethod: TMethod, params: Readonly<Parameters<TMethod>>): Promise<Awaited<ReturnType<TMethod>>>;
|
|
43
|
+
static runWithLogging<TResult>(options: FlowLoggerLogOptions, originalMethod: AsyncOriginalMethod<[], TResult>, params: ReadonlyArray<unknown>): Promise<Awaited<TResult>>;
|
|
44
|
+
private static readonly NOISY_CDP_EVENTS;
|
|
97
45
|
private static logCdpEvent;
|
|
98
|
-
static logCdpCallEvent(data: {
|
|
46
|
+
static logCdpCallEvent(context: FlowLoggerContext, data: {
|
|
99
47
|
method: string;
|
|
100
48
|
params?: object;
|
|
101
49
|
targetId?: string | null;
|
|
102
|
-
}
|
|
103
|
-
static
|
|
50
|
+
}): FlowEvent | null;
|
|
51
|
+
static logCdpResponseEvent(context: FlowLoggerContext, parentEvent: Pick<FlowEvent, "eventId" | "eventParentIds">, data: {
|
|
52
|
+
method: string;
|
|
53
|
+
result?: unknown;
|
|
54
|
+
error?: string;
|
|
55
|
+
targetId?: string | null;
|
|
56
|
+
}): void;
|
|
57
|
+
static logCdpMessageEvent(context: FlowLoggerContext, parentEvent: Pick<FlowEvent, "eventId" | "eventParentIds">, data: {
|
|
104
58
|
method: string;
|
|
105
59
|
params?: unknown;
|
|
106
60
|
targetId?: string | null;
|
|
107
|
-
}
|
|
61
|
+
}): void;
|
|
108
62
|
static logLlmRequest({ requestId, model, prompt, }: {
|
|
109
63
|
requestId: string;
|
|
110
64
|
model: string;
|
|
111
|
-
operation: string;
|
|
112
65
|
prompt?: string;
|
|
113
|
-
}
|
|
66
|
+
}): void;
|
|
114
67
|
static logLlmResponse({ requestId, model, output, inputTokens, outputTokens, }: {
|
|
115
68
|
requestId: string;
|
|
116
69
|
model: string;
|
|
117
|
-
operation: string;
|
|
118
70
|
output?: string;
|
|
119
71
|
inputTokens?: number;
|
|
120
72
|
outputTokens?: number;
|
|
121
|
-
}
|
|
73
|
+
}): void;
|
|
122
74
|
/**
|
|
123
75
|
* Create middleware for wrapping language models with LLM call logging.
|
|
124
76
|
* Returns a no-op middleware when logging is disabled.
|
|
@@ -126,14 +78,21 @@ export declare class SessionFileLogger {
|
|
|
126
78
|
static createLlmLoggingMiddleware(modelId: string): Pick<LanguageModelMiddleware, "wrapGenerate">;
|
|
127
79
|
}
|
|
128
80
|
/**
|
|
129
|
-
*
|
|
130
|
-
*
|
|
81
|
+
* Format a prompt summary from LLM messages for logging.
|
|
82
|
+
* Returns format like: "some text +{5.8kb image} +{schema} +{12 tools}"
|
|
131
83
|
*/
|
|
132
|
-
export declare function
|
|
84
|
+
export declare function extractLlmPromptSummary(messages: Array<{
|
|
85
|
+
role: string;
|
|
86
|
+
content: unknown;
|
|
87
|
+
}>, options?: {
|
|
88
|
+
toolCount?: number;
|
|
89
|
+
hasSchema?: boolean;
|
|
90
|
+
}): string | undefined;
|
|
133
91
|
/**
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
* No-op when CONFIG_DIR is empty.
|
|
92
|
+
* Extract a text summary from CUA-style messages.
|
|
93
|
+
* Accepts various message formats (Anthropic, OpenAI, Google).
|
|
137
94
|
*/
|
|
138
|
-
export declare function
|
|
95
|
+
export declare function extractLlmCuaPromptSummary(messages: unknown[]): string | undefined;
|
|
96
|
+
/** Format a CUA response summary for logging */
|
|
97
|
+
export declare function extractLlmCuaResponseSummary(output: unknown): string;
|
|
139
98
|
export {};
|