@browserbasehq/orca 3.2.0-preview.2 → 3.2.0-preview.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (167) hide show
  1. package/dist/cjs/lib/v3/agent/AnthropicCUAClient.js +5 -5
  2. package/dist/cjs/lib/v3/agent/AnthropicCUAClient.js.map +1 -1
  3. package/dist/cjs/lib/v3/agent/GoogleCUAClient.js +5 -5
  4. package/dist/cjs/lib/v3/agent/GoogleCUAClient.js.map +1 -1
  5. package/dist/cjs/lib/v3/agent/OpenAICUAClient.js +5 -5
  6. package/dist/cjs/lib/v3/agent/OpenAICUAClient.js.map +1 -1
  7. package/dist/cjs/lib/v3/agent/tools/act.js +1 -10
  8. package/dist/cjs/lib/v3/agent/tools/act.js.map +1 -1
  9. package/dist/cjs/lib/v3/agent/tools/ariaTree.js +1 -12
  10. package/dist/cjs/lib/v3/agent/tools/ariaTree.js.map +1 -1
  11. package/dist/cjs/lib/v3/agent/tools/braveSearch.js.map +1 -1
  12. package/dist/cjs/lib/v3/agent/tools/browserbaseSearch.js.map +1 -1
  13. package/dist/cjs/lib/v3/agent/tools/click.js.map +1 -1
  14. package/dist/cjs/lib/v3/agent/tools/clickAndHold.js.map +1 -1
  15. package/dist/cjs/lib/v3/agent/tools/dragAndDrop.js.map +1 -1
  16. package/dist/cjs/lib/v3/agent/tools/extract.js +1 -10
  17. package/dist/cjs/lib/v3/agent/tools/extract.js.map +1 -1
  18. package/dist/cjs/lib/v3/agent/tools/fillFormVision.js.map +1 -1
  19. package/dist/cjs/lib/v3/agent/tools/fillform.js +1 -10
  20. package/dist/cjs/lib/v3/agent/tools/fillform.js.map +1 -1
  21. package/dist/cjs/lib/v3/agent/tools/index.d.ts +2 -2
  22. package/dist/cjs/lib/v3/agent/tools/index.js +53 -5
  23. package/dist/cjs/lib/v3/agent/tools/index.js.map +1 -1
  24. package/dist/cjs/lib/v3/agent/tools/keys.d.ts +1 -1
  25. package/dist/cjs/lib/v3/agent/tools/keys.js.map +1 -1
  26. package/dist/cjs/lib/v3/agent/tools/type.js.map +1 -1
  27. package/dist/cjs/lib/v3/api.js +9 -2
  28. package/dist/cjs/lib/v3/api.js.map +1 -1
  29. package/dist/cjs/lib/v3/flowlogger/EventEmitter.d.ts +7 -0
  30. package/dist/cjs/lib/v3/flowlogger/EventEmitter.js +30 -0
  31. package/dist/cjs/lib/v3/flowlogger/EventEmitter.js.map +1 -0
  32. package/dist/cjs/lib/v3/flowlogger/EventSink.d.ts +44 -0
  33. package/dist/cjs/lib/v3/flowlogger/EventSink.js +217 -0
  34. package/dist/cjs/lib/v3/flowlogger/EventSink.js.map +1 -0
  35. package/dist/cjs/lib/v3/flowlogger/EventStore.d.ts +26 -0
  36. package/dist/cjs/lib/v3/flowlogger/EventStore.js +135 -0
  37. package/dist/cjs/lib/v3/flowlogger/EventStore.js.map +1 -0
  38. package/dist/{esm/lib/v3/flowLogger.d.ts → cjs/lib/v3/flowlogger/FlowLogger.d.ts} +32 -31
  39. package/dist/cjs/lib/v3/flowlogger/FlowLogger.js +591 -0
  40. package/dist/cjs/lib/v3/flowlogger/FlowLogger.js.map +1 -0
  41. package/dist/cjs/lib/v3/flowlogger/prettify.d.ts +6 -0
  42. package/dist/cjs/lib/v3/flowlogger/prettify.js +395 -0
  43. package/dist/cjs/lib/v3/flowlogger/prettify.js.map +1 -0
  44. package/dist/cjs/lib/v3/handlers/handlerUtils/actHandlerUtils.js +26 -28
  45. package/dist/cjs/lib/v3/handlers/handlerUtils/actHandlerUtils.js.map +1 -1
  46. package/dist/cjs/lib/v3/handlers/v3AgentHandler.js +2 -2
  47. package/dist/cjs/lib/v3/handlers/v3AgentHandler.js.map +1 -1
  48. package/dist/cjs/lib/v3/handlers/v3CuaAgentHandler.js +3 -5
  49. package/dist/cjs/lib/v3/handlers/v3CuaAgentHandler.js.map +1 -1
  50. package/dist/cjs/lib/v3/llm/aisdk.js +9 -9
  51. package/dist/cjs/lib/v3/llm/aisdk.js.map +1 -1
  52. package/dist/cjs/lib/v3/types/public/options.d.ts +2 -0
  53. package/dist/cjs/lib/v3/types/public/options.js.map +1 -1
  54. package/dist/cjs/lib/v3/understudy/cdp.d.ts +1 -1
  55. package/dist/cjs/lib/v3/understudy/cdp.js +83 -43
  56. package/dist/cjs/lib/v3/understudy/cdp.js.map +1 -1
  57. package/dist/cjs/lib/v3/understudy/page.js +18 -23
  58. package/dist/cjs/lib/v3/understudy/page.js.map +1 -1
  59. package/dist/cjs/lib/v3/v3.d.ts +5 -5
  60. package/dist/cjs/lib/v3/v3.js +48 -46
  61. package/dist/cjs/lib/v3/v3.js.map +1 -1
  62. package/dist/cjs/tests/integration/flowLogger.spec.d.ts +1 -0
  63. package/dist/cjs/tests/integration/flowLogger.spec.js +714 -0
  64. package/dist/cjs/tests/integration/flowLogger.spec.js.map +1 -0
  65. package/dist/cjs/tests/integration/testUtils.d.ts +33 -0
  66. package/dist/cjs/tests/integration/testUtils.js +144 -0
  67. package/dist/cjs/tests/integration/testUtils.js.map +1 -1
  68. package/dist/cjs/tests/integration/timeouts.spec.js +112 -2
  69. package/dist/cjs/tests/integration/timeouts.spec.js.map +1 -1
  70. package/dist/cjs/tests/unit/flowlogger-capturing-cdp.test.d.ts +1 -0
  71. package/dist/cjs/tests/unit/flowlogger-capturing-cdp.test.js +95 -0
  72. package/dist/cjs/tests/unit/flowlogger-capturing-cdp.test.js.map +1 -0
  73. package/dist/cjs/tests/unit/flowlogger-capturing-llm.test.d.ts +1 -0
  74. package/dist/cjs/tests/unit/flowlogger-capturing-llm.test.js +43 -0
  75. package/dist/cjs/tests/unit/flowlogger-capturing-llm.test.js.map +1 -0
  76. package/dist/cjs/tests/unit/flowlogger-eventstore.test.d.ts +1 -0
  77. package/dist/cjs/tests/unit/flowlogger-eventstore.test.js +250 -0
  78. package/dist/cjs/tests/unit/flowlogger-eventstore.test.js.map +1 -0
  79. package/dist/esm/lib/v3/agent/AnthropicCUAClient.js +1 -1
  80. package/dist/esm/lib/v3/agent/AnthropicCUAClient.js.map +1 -1
  81. package/dist/esm/lib/v3/agent/GoogleCUAClient.js +1 -1
  82. package/dist/esm/lib/v3/agent/GoogleCUAClient.js.map +1 -1
  83. package/dist/esm/lib/v3/agent/OpenAICUAClient.js +1 -1
  84. package/dist/esm/lib/v3/agent/OpenAICUAClient.js.map +1 -1
  85. package/dist/esm/lib/v3/agent/tools/act.js +1 -10
  86. package/dist/esm/lib/v3/agent/tools/act.js.map +1 -1
  87. package/dist/esm/lib/v3/agent/tools/ariaTree.js +1 -12
  88. package/dist/esm/lib/v3/agent/tools/ariaTree.js.map +1 -1
  89. package/dist/esm/lib/v3/agent/tools/braveSearch.js.map +1 -1
  90. package/dist/esm/lib/v3/agent/tools/browserbaseSearch.js.map +1 -1
  91. package/dist/esm/lib/v3/agent/tools/click.js.map +1 -1
  92. package/dist/esm/lib/v3/agent/tools/clickAndHold.js.map +1 -1
  93. package/dist/esm/lib/v3/agent/tools/dragAndDrop.js.map +1 -1
  94. package/dist/esm/lib/v3/agent/tools/extract.js +1 -10
  95. package/dist/esm/lib/v3/agent/tools/extract.js.map +1 -1
  96. package/dist/esm/lib/v3/agent/tools/fillFormVision.js.map +1 -1
  97. package/dist/esm/lib/v3/agent/tools/fillform.js +1 -10
  98. package/dist/esm/lib/v3/agent/tools/fillform.js.map +1 -1
  99. package/dist/esm/lib/v3/agent/tools/index.d.ts +2 -2
  100. package/dist/esm/lib/v3/agent/tools/index.js +53 -5
  101. package/dist/esm/lib/v3/agent/tools/index.js.map +1 -1
  102. package/dist/esm/lib/v3/agent/tools/keys.d.ts +1 -1
  103. package/dist/esm/lib/v3/agent/tools/keys.js.map +1 -1
  104. package/dist/esm/lib/v3/agent/tools/type.js.map +1 -1
  105. package/dist/esm/lib/v3/api.js +9 -2
  106. package/dist/esm/lib/v3/api.js.map +1 -1
  107. package/dist/esm/lib/v3/flowlogger/EventEmitter.d.ts +7 -0
  108. package/dist/esm/lib/v3/flowlogger/EventEmitter.js +26 -0
  109. package/dist/esm/lib/v3/flowlogger/EventEmitter.js.map +1 -0
  110. package/dist/esm/lib/v3/flowlogger/EventSink.d.ts +44 -0
  111. package/dist/esm/lib/v3/flowlogger/EventSink.js +206 -0
  112. package/dist/esm/lib/v3/flowlogger/EventSink.js.map +1 -0
  113. package/dist/esm/lib/v3/flowlogger/EventStore.d.ts +26 -0
  114. package/dist/esm/lib/v3/flowlogger/EventStore.js +127 -0
  115. package/dist/esm/lib/v3/flowlogger/EventStore.js.map +1 -0
  116. package/dist/{cjs/lib/v3/flowLogger.d.ts → esm/lib/v3/flowlogger/FlowLogger.d.ts} +32 -31
  117. package/dist/esm/lib/v3/flowlogger/FlowLogger.js +583 -0
  118. package/dist/esm/lib/v3/flowlogger/FlowLogger.js.map +1 -0
  119. package/dist/esm/lib/v3/flowlogger/prettify.d.ts +6 -0
  120. package/dist/esm/lib/v3/flowlogger/prettify.js +389 -0
  121. package/dist/esm/lib/v3/flowlogger/prettify.js.map +1 -0
  122. package/dist/esm/lib/v3/handlers/handlerUtils/actHandlerUtils.js +25 -27
  123. package/dist/esm/lib/v3/handlers/handlerUtils/actHandlerUtils.js.map +1 -1
  124. package/dist/esm/lib/v3/handlers/v3AgentHandler.js +1 -1
  125. package/dist/esm/lib/v3/handlers/v3AgentHandler.js.map +1 -1
  126. package/dist/esm/lib/v3/handlers/v3CuaAgentHandler.js +2 -4
  127. package/dist/esm/lib/v3/handlers/v3CuaAgentHandler.js.map +1 -1
  128. package/dist/esm/lib/v3/llm/aisdk.js +1 -1
  129. package/dist/esm/lib/v3/llm/aisdk.js.map +1 -1
  130. package/dist/esm/lib/v3/types/public/options.d.ts +2 -0
  131. package/dist/esm/lib/v3/types/public/options.js.map +1 -1
  132. package/dist/esm/lib/v3/understudy/cdp.d.ts +1 -1
  133. package/dist/esm/lib/v3/understudy/cdp.js +78 -38
  134. package/dist/esm/lib/v3/understudy/cdp.js.map +1 -1
  135. package/dist/esm/lib/v3/understudy/page.js +13 -18
  136. package/dist/esm/lib/v3/understudy/page.js.map +1 -1
  137. package/dist/esm/lib/v3/v3.d.ts +5 -5
  138. package/dist/esm/lib/v3/v3.js +43 -41
  139. package/dist/esm/lib/v3/v3.js.map +1 -1
  140. package/dist/esm/tests/integration/flowLogger.spec.d.ts +1 -0
  141. package/dist/esm/tests/integration/flowLogger.spec.js +712 -0
  142. package/dist/esm/tests/integration/flowLogger.spec.js.map +1 -0
  143. package/dist/esm/tests/integration/testUtils.d.ts +33 -0
  144. package/dist/esm/tests/integration/testUtils.js +138 -0
  145. package/dist/esm/tests/integration/testUtils.js.map +1 -1
  146. package/dist/esm/tests/integration/timeouts.spec.js +112 -2
  147. package/dist/esm/tests/integration/timeouts.spec.js.map +1 -1
  148. package/dist/esm/tests/unit/flowlogger-capturing-cdp.test.d.ts +1 -0
  149. package/dist/esm/tests/unit/flowlogger-capturing-cdp.test.js +93 -0
  150. package/dist/esm/tests/unit/flowlogger-capturing-cdp.test.js.map +1 -0
  151. package/dist/esm/tests/unit/flowlogger-capturing-llm.test.d.ts +1 -0
  152. package/dist/esm/tests/unit/flowlogger-capturing-llm.test.js +41 -0
  153. package/dist/esm/tests/unit/flowlogger-capturing-llm.test.js.map +1 -0
  154. package/dist/esm/tests/unit/flowlogger-eventstore.test.d.ts +1 -0
  155. package/dist/esm/tests/unit/flowlogger-eventstore.test.js +248 -0
  156. package/dist/esm/tests/unit/flowlogger-eventstore.test.js.map +1 -0
  157. package/package.json +3 -1
  158. package/dist/cjs/lib/v3/eventStore.d.ts +0 -41
  159. package/dist/cjs/lib/v3/eventStore.js +0 -375
  160. package/dist/cjs/lib/v3/eventStore.js.map +0 -1
  161. package/dist/cjs/lib/v3/flowLogger.js +0 -470
  162. package/dist/cjs/lib/v3/flowLogger.js.map +0 -1
  163. package/dist/esm/lib/v3/eventStore.d.ts +0 -41
  164. package/dist/esm/lib/v3/eventStore.js +0 -363
  165. package/dist/esm/lib/v3/eventStore.js.map +0 -1
  166. package/dist/esm/lib/v3/flowLogger.js +0 -462
  167. package/dist/esm/lib/v3/flowLogger.js.map +0 -1
@@ -1,462 +0,0 @@
1
- import { AsyncLocalStorage } from "node:async_hooks";
2
- import { v7 as uuidv7 } from "uuid";
3
- export class FlowEvent {
4
- static createEventId(eventIdSuffix) {
5
- const rawEventId = uuidv7();
6
- return `${rawEventId.slice(0, -1)}${eventIdSuffix || "0"}`;
7
- }
8
- // base required fields for all events:
9
- eventType;
10
- eventId;
11
- eventParentIds;
12
- createdAt;
13
- sessionId;
14
- data; // event payload (e.g. params, action, result, error, etc.)
15
- constructor(input) {
16
- if (!input.sessionId) {
17
- throw new Error("FlowEvent.sessionId is required.");
18
- }
19
- if (input.eventId &&
20
- input.eventIdSuffix &&
21
- !input.eventId.endsWith(input.eventIdSuffix)) {
22
- throw new Error("FlowEvent cannot take both eventId and eventIdSuffix.");
23
- }
24
- this.eventType = input.eventType.endsWith("Event")
25
- ? input.eventType
26
- : `${input.eventType}Event`;
27
- this.eventId =
28
- input.eventId ?? FlowEvent.createEventId(input.eventIdSuffix ?? "0");
29
- this.eventParentIds = input.eventParentIds ?? [];
30
- this.createdAt = input.createdAt ?? new Date().toISOString();
31
- this.sessionId = input.sessionId;
32
- this.data = input.data ?? {};
33
- }
34
- }
35
- const loggerContext = new AsyncLocalStorage();
36
- function dataToKb(data) {
37
- return ((data.length * 0.75) / 1024).toFixed(1);
38
- }
39
- // =============================================================================
40
- // Flow Logger - Main API
41
- // =============================================================================
42
- export class FlowLogger {
43
- static cloneContext(ctx) {
44
- return {
45
- ...ctx,
46
- parentEvents: ctx.parentEvents.map((event) => ({
47
- ...event,
48
- eventParentIds: [...event.eventParentIds],
49
- })),
50
- };
51
- }
52
- static emit(event) {
53
- const ctx = FlowLogger.currentContext;
54
- const emittedEvent = new FlowEvent({
55
- ...event,
56
- eventParentIds: event.eventParentIds ??
57
- ctx.parentEvents.map((parent) => parent.eventId),
58
- sessionId: ctx.sessionId,
59
- });
60
- ctx.eventBus.emit(emittedEvent.eventType, emittedEvent);
61
- return emittedEvent;
62
- }
63
- static async runWithAutoStatusEventLogging(options, originalMethod) {
64
- const ctx = FlowLogger.currentContext;
65
- const { data, eventParentIds, eventType, eventIdSuffix } = options;
66
- let caughtError = null;
67
- // if eventParentIds is explicitly [], this is a root event, clear the parent events in context
68
- if (eventParentIds && eventParentIds.length === 0) {
69
- ctx.parentEvents = [];
70
- }
71
- const startedEvent = FlowLogger.emit({
72
- eventIdSuffix,
73
- eventType,
74
- data,
75
- eventParentIds,
76
- });
77
- ctx.parentEvents.push(startedEvent);
78
- try {
79
- return await originalMethod();
80
- }
81
- catch (error) {
82
- caughtError = error;
83
- FlowLogger.emit({
84
- eventIdSuffix,
85
- eventType: `${eventType}ErrorEvent`,
86
- eventParentIds: [...startedEvent.eventParentIds, startedEvent.eventId],
87
- data: {
88
- error: error instanceof Error ? error.message : String(error),
89
- durationMs: Date.now() - new Date(startedEvent.createdAt).getTime(),
90
- },
91
- });
92
- throw error;
93
- }
94
- finally {
95
- const parentEvent = ctx.parentEvents.pop();
96
- if (parentEvent?.eventId === startedEvent.eventId && !caughtError) {
97
- FlowLogger.emit({
98
- eventIdSuffix,
99
- eventType: `${eventType}CompletedEvent`,
100
- eventParentIds: [
101
- ...startedEvent.eventParentIds,
102
- startedEvent.eventId,
103
- ],
104
- data: {
105
- durationMs: Date.now() - new Date(startedEvent.createdAt).getTime(),
106
- },
107
- });
108
- }
109
- }
110
- }
111
- /**
112
- * Initialize a new logging context. Call this at the start of a session.
113
- */
114
- static init(sessionId, eventBus) {
115
- const ctx = {
116
- sessionId,
117
- eventBus,
118
- parentEvents: [],
119
- };
120
- loggerContext.enterWith(ctx);
121
- return ctx;
122
- }
123
- static async close(context) {
124
- const ctx = context ?? loggerContext.getStore() ?? null;
125
- if (!ctx)
126
- return;
127
- ctx.parentEvents = [];
128
- }
129
- static get currentContext() {
130
- const ctx = loggerContext.getStore() ?? null;
131
- if (!ctx) {
132
- throw new Error("FlowLogger context is missing.");
133
- }
134
- return ctx;
135
- }
136
- // decorator method to wrap a class method with automatic started/completed/error events
137
- static wrapWithLogging(options) {
138
- return function (originalMethod) {
139
- const wrappedMethod = async function (...args) {
140
- return await FlowLogger.runWithLogging(options, (...boundArgs) => originalMethod.apply(this, boundArgs), args);
141
- };
142
- return wrappedMethod;
143
- };
144
- }
145
- static runWithLogging(options, originalMethod, params) {
146
- const eventData = {
147
- ...(options.data ?? {}),
148
- params: [...params],
149
- };
150
- const execute = () => FlowLogger.runWithAutoStatusEventLogging({
151
- ...options,
152
- data: eventData,
153
- }, () => originalMethod(...params));
154
- if (!options.context && !(loggerContext.getStore() ?? null)) {
155
- return originalMethod(...params);
156
- }
157
- return options.context
158
- ? loggerContext.run(FlowLogger.cloneContext(options.context), execute)
159
- : execute();
160
- }
161
- // ===========================================================================
162
- // CDP Events
163
- // ===========================================================================
164
- static NOISY_CDP_EVENTS = new Set([
165
- "Target.targetInfoChanged",
166
- "Runtime.executionContextCreated",
167
- "Runtime.executionContextDestroyed",
168
- "Runtime.executionContextsCleared",
169
- "Page.lifecycleEvent",
170
- "Network.dataReceived",
171
- "Network.loadingFinished",
172
- "Network.requestWillBeSentExtraInfo",
173
- "Network.responseReceivedExtraInfo",
174
- "Network.requestWillBeSent",
175
- "Network.responseReceived",
176
- ]);
177
- static logCdpEvent(context, eventType, { method, params, result, error, targetId, }, eventParentIds) {
178
- if (method.endsWith(".enable") || method === "enable") {
179
- return null;
180
- }
181
- if (eventType === "message" && FlowLogger.NOISY_CDP_EVENTS.has(method)) {
182
- return null;
183
- }
184
- return loggerContext.run(FlowLogger.cloneContext(context), () => FlowLogger.emit({
185
- eventIdSuffix: "6",
186
- eventType: eventType === "call"
187
- ? "CdpCallEvent"
188
- : eventType === "response"
189
- ? "CdpResponseEvent"
190
- : eventType === "responseError"
191
- ? "CdpResponseErrorEvent"
192
- : "CdpMessageEvent",
193
- eventParentIds,
194
- data: {
195
- method,
196
- params,
197
- result,
198
- error,
199
- targetId,
200
- },
201
- }));
202
- }
203
- static logCdpCallEvent(context, data) {
204
- return FlowLogger.logCdpEvent(context, "call", data);
205
- }
206
- static logCdpResponseEvent(context, parentEvent, data) {
207
- FlowLogger.logCdpEvent(context, data.error ? "responseError" : "response", data, [...parentEvent.eventParentIds, parentEvent.eventId]);
208
- }
209
- static logCdpMessageEvent(context, parentEvent, data) {
210
- FlowLogger.logCdpEvent(context, "message", data, [
211
- ...parentEvent.eventParentIds,
212
- parentEvent.eventId,
213
- ]);
214
- }
215
- // ===========================================================================
216
- // LLM Events
217
- // ===========================================================================
218
- static logLlmRequest({ requestId, model, prompt, }) {
219
- FlowLogger.emit({
220
- eventIdSuffix: "7",
221
- eventType: "LlmRequestEvent",
222
- data: {
223
- requestId,
224
- model,
225
- prompt,
226
- },
227
- });
228
- }
229
- static logLlmResponse({ requestId, model, output, inputTokens, outputTokens, }) {
230
- FlowLogger.emit({
231
- eventIdSuffix: "7",
232
- eventType: "LlmResponseEvent",
233
- data: {
234
- requestId,
235
- model,
236
- output,
237
- inputTokens,
238
- outputTokens,
239
- },
240
- });
241
- }
242
- // ===========================================================================
243
- // LLM Logging Middleware
244
- // ===========================================================================
245
- /**
246
- * Create middleware for wrapping language models with LLM call logging.
247
- * Returns a no-op middleware when logging is disabled.
248
- */
249
- static createLlmLoggingMiddleware(modelId) {
250
- return {
251
- wrapGenerate: async ({ doGenerate, params }) => {
252
- const llmRequestId = uuidv7();
253
- const toolCount = Array.isArray(params.tools) ? params.tools.length : 0;
254
- const messages = (params.prompt ?? []);
255
- const lastMsg = messages.filter((m) => m.role !== "system").pop();
256
- let rolePrefix = lastMsg?.role ?? "?";
257
- let promptSummary = `(no text) +{${toolCount} tools}`;
258
- if (lastMsg) {
259
- if (typeof lastMsg.content === "string") {
260
- promptSummary = `${lastMsg.content} +{${toolCount} tools}`;
261
- }
262
- else if (Array.isArray(lastMsg.content)) {
263
- const toolResult = lastMsg.content.find((part) => part.type === "tool-result");
264
- if (toolResult) {
265
- rolePrefix = `tool result: ${toolResult.toolName}()`;
266
- if (toolResult.output?.type === "json" &&
267
- toolResult.output.value) {
268
- promptSummary = `${JSON.stringify(toolResult.output.value)} +{${toolCount} tools}`;
269
- }
270
- else if (Array.isArray(toolResult.output?.value)) {
271
- promptSummary = `${extractLlmMessageSummary({
272
- content: toolResult.output.value,
273
- }) ?? "(no text)"} +{${toolCount} tools}`;
274
- }
275
- }
276
- else {
277
- promptSummary = `${extractLlmMessageSummary({ content: lastMsg.content }) ??
278
- "(no text)"} +{${toolCount} tools}`;
279
- }
280
- }
281
- promptSummary = `${rolePrefix}: ${promptSummary}`;
282
- }
283
- else {
284
- promptSummary = `?: ${promptSummary}`;
285
- }
286
- FlowLogger.logLlmRequest({
287
- requestId: llmRequestId,
288
- model: modelId,
289
- prompt: promptSummary,
290
- });
291
- const result = await doGenerate();
292
- // Extract output summary
293
- const res = result;
294
- let outputSummary = res.text || "";
295
- if (!outputSummary && res.content) {
296
- if (typeof res.content === "string") {
297
- outputSummary = res.content;
298
- }
299
- else if (Array.isArray(res.content)) {
300
- outputSummary = res.content
301
- .map((c) => c.text ||
302
- (c.type === "tool-call"
303
- ? `tool call: ${c.toolName}()`
304
- : `[${c.type}]`))
305
- .join(" ");
306
- }
307
- }
308
- if (!outputSummary && res.toolCalls?.length) {
309
- outputSummary = `[${res.toolCalls.length} tool calls]`;
310
- }
311
- FlowLogger.logLlmResponse({
312
- requestId: llmRequestId,
313
- model: modelId,
314
- output: outputSummary || "[empty]",
315
- inputTokens: result.usage?.inputTokens,
316
- outputTokens: result.usage?.outputTokens,
317
- });
318
- return result;
319
- },
320
- };
321
- }
322
- }
323
- /** Extract text and image info from a content array (handles nested tool_result) */
324
- function extractLlmMessageContent(content) {
325
- const result = {
326
- text: undefined,
327
- extras: [],
328
- };
329
- for (const part of content) {
330
- const p = part;
331
- // Text
332
- if (!result.text && p.text) {
333
- result.text = p.type === "text" || !p.type ? p.text : undefined;
334
- }
335
- // Images - various formats
336
- if (p.type === "image" || p.type === "image_url") {
337
- const url = p.image_url?.url;
338
- if (url?.startsWith("data:"))
339
- result.extras.push(`${dataToKb(url)}kb image`);
340
- else if (p.source?.data)
341
- result.extras.push(`${dataToKb(p.source.data)}kb image`);
342
- else
343
- result.extras.push("image");
344
- }
345
- else if (p.source?.data) {
346
- result.extras.push(`${dataToKb(p.source.data)}kb image`);
347
- }
348
- else if (p.inlineData?.data) {
349
- result.extras.push(`${dataToKb(p.inlineData.data)}kb image`);
350
- }
351
- // Recurse into tool_result content
352
- if (p.type === "tool_result" && Array.isArray(p.content)) {
353
- const nested = extractLlmMessageContent(p.content);
354
- if (!result.text && nested.text) {
355
- result.text = nested.text;
356
- }
357
- result.extras.push(...nested.extras);
358
- }
359
- }
360
- return result;
361
- }
362
- function extractLlmMessageSummary(input, options) {
363
- const result = {
364
- text: undefined,
365
- extras: [...(options?.extras ?? [])],
366
- };
367
- if (typeof input.content === "string") {
368
- result.text = input.content;
369
- }
370
- else if (typeof input.text === "string") {
371
- result.text = input.text;
372
- }
373
- else if (Array.isArray(input.parts)) {
374
- const summary = extractLlmMessageContent(input.parts);
375
- result.text = summary.text;
376
- result.extras.push(...summary.extras);
377
- }
378
- else if (Array.isArray(input.content)) {
379
- const summary = extractLlmMessageContent(input.content);
380
- result.text = summary.text;
381
- result.extras.push(...summary.extras);
382
- }
383
- if (options?.trimInstructionPrefix && result.text) {
384
- result.text = result.text.replace(/^[Ii]nstruction: /, "");
385
- }
386
- const text = result.text;
387
- if (!text && result.extras.length === 0)
388
- return undefined;
389
- let summary = text || "";
390
- if (result.extras.length > 0) {
391
- const extrasStr = result.extras.map((e) => `+{${e}}`).join(" ");
392
- summary = summary ? `${summary} ${extrasStr}` : extrasStr;
393
- }
394
- return summary || undefined;
395
- }
396
- /**
397
- * Format a prompt summary from LLM messages for logging.
398
- * Returns format like: "some text +{5.8kb image} +{schema} +{12 tools}"
399
- */
400
- export function extractLlmPromptSummary(messages, options) {
401
- try {
402
- const lastUserMsg = messages.filter((m) => m.role === "user").pop();
403
- if (!lastUserMsg)
404
- return undefined;
405
- return extractLlmMessageSummary(lastUserMsg, {
406
- trimInstructionPrefix: true,
407
- extras: [
408
- ...(options?.hasSchema ? ["schema"] : []),
409
- ...(options?.toolCount ? [`${options.toolCount} tools`] : []),
410
- ],
411
- });
412
- }
413
- catch {
414
- return undefined;
415
- }
416
- }
417
- /**
418
- * Extract a text summary from CUA-style messages.
419
- * Accepts various message formats (Anthropic, OpenAI, Google).
420
- */
421
- export function extractLlmCuaPromptSummary(messages) {
422
- try {
423
- const lastMsg = messages
424
- .filter((m) => {
425
- const msg = m;
426
- return msg.role === "user" || msg.type === "tool_result";
427
- })
428
- .pop();
429
- if (!lastMsg)
430
- return undefined;
431
- return extractLlmMessageSummary(lastMsg);
432
- }
433
- catch {
434
- return undefined;
435
- }
436
- }
437
- /** Format a CUA response summary for logging */
438
- export function extractLlmCuaResponseSummary(output) {
439
- try {
440
- // Handle Google format or array
441
- const items = output
442
- ?.candidates?.[0]?.content?.parts ??
443
- (Array.isArray(output) ? output : []);
444
- const summary = items
445
- .map((item) => {
446
- const i = item;
447
- if (i.text)
448
- return i.text;
449
- if (i.functionCall?.name)
450
- return i.functionCall.name;
451
- if (i.type === "tool_use" && i.name)
452
- return i.name;
453
- return i.type ?? "[item]";
454
- })
455
- .join(" ");
456
- return summary;
457
- }
458
- catch {
459
- return "[error]";
460
- }
461
- }
462
- //# sourceMappingURL=flowLogger.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"flowLogger.js","sourceRoot":"","sources":["../../../../lib/v3/flowLogger.ts"],"names":[],"mappings":"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","sourcesContent":["import { AsyncLocalStorage } from \"node:async_hooks\";\nimport { EventEmitter } from \"node:events\";\nimport { v7 as uuidv7 } from \"uuid\";\nimport type { LanguageModelMiddleware } from \"ai\";\n\n// =============================================================================\n// Constants\n// =============================================================================\n\nexport type FlowEventData = Record<string, unknown>;\nexport type FlowEventInput = Omit<\n FlowEvent,\n \"eventId\" | \"createdAt\" | \"sessionId\" | \"eventParentIds\" | \"data\"\n> & {\n eventId?: string;\n eventIdSuffix?: string;\n createdAt?: string;\n sessionId?: string;\n eventParentIds?: string[];\n data?: FlowEventData;\n};\n\nexport class FlowEvent {\n static createEventId(eventIdSuffix: string): string {\n const rawEventId = uuidv7();\n return `${rawEventId.slice(0, -1)}${eventIdSuffix || \"0\"}`;\n }\n\n // base required fields for all events:\n eventType: string;\n eventId: string;\n eventParentIds: string[];\n createdAt: string;\n sessionId: string;\n data: FlowEventData; // event payload (e.g. params, action, result, error, etc.)\n\n constructor(input: FlowEventInput) {\n if (!input.sessionId) {\n throw new Error(\"FlowEvent.sessionId is required.\");\n }\n if (\n input.eventId &&\n input.eventIdSuffix &&\n !input.eventId.endsWith(input.eventIdSuffix)\n ) {\n throw new Error(\"FlowEvent cannot take both eventId and eventIdSuffix.\");\n }\n\n this.eventType = input.eventType.endsWith(\"Event\")\n ? input.eventType\n : `${input.eventType}Event`;\n this.eventId =\n input.eventId ?? FlowEvent.createEventId(input.eventIdSuffix ?? \"0\");\n this.eventParentIds = input.eventParentIds ?? [];\n this.createdAt = input.createdAt ?? new Date().toISOString();\n this.sessionId = input.sessionId;\n this.data = input.data ?? {};\n }\n}\n\nexport interface FlowLoggerContext {\n sessionId: string;\n eventBus: EventEmitter;\n parentEvents: FlowEvent[];\n}\n\ntype AsyncOriginalMethod<\n TArgs extends unknown[] = unknown[],\n TResult = unknown,\n TThis = unknown,\n> = (this: TThis, ...args: TArgs) => Promise<TResult>;\n\ntype FlowLoggerLogOptions = FlowEventInput & {\n context?: FlowLoggerContext;\n};\n\nconst loggerContext = new AsyncLocalStorage<FlowLoggerContext>();\n\nfunction dataToKb(data: string): string {\n return ((data.length * 0.75) / 1024).toFixed(1);\n}\n\n// =============================================================================\n// Flow Logger - Main API\n// =============================================================================\n\nexport class FlowLogger {\n private static cloneContext(ctx: FlowLoggerContext): FlowLoggerContext {\n return {\n ...ctx,\n parentEvents: ctx.parentEvents.map((event) => ({\n ...event,\n eventParentIds: [...event.eventParentIds],\n })),\n };\n }\n\n private static emit(event: FlowEventInput): FlowEvent | null {\n const ctx = FlowLogger.currentContext;\n\n const emittedEvent = new FlowEvent({\n ...event,\n eventParentIds:\n event.eventParentIds ??\n ctx.parentEvents.map((parent) => parent.eventId),\n sessionId: ctx.sessionId,\n });\n ctx.eventBus.emit(emittedEvent.eventType, emittedEvent);\n return emittedEvent;\n }\n\n private static async runWithAutoStatusEventLogging<TResult>(\n options: FlowLoggerLogOptions,\n originalMethod: AsyncOriginalMethod<[], TResult>,\n ): Promise<TResult> {\n const ctx = FlowLogger.currentContext;\n const { data, eventParentIds, eventType, eventIdSuffix } = options;\n let caughtError: unknown = null;\n\n // if eventParentIds is explicitly [], this is a root event, clear the parent events in context\n if (eventParentIds && eventParentIds.length === 0) {\n ctx.parentEvents = [];\n }\n\n const startedEvent = FlowLogger.emit({\n eventIdSuffix,\n eventType,\n data,\n eventParentIds,\n });\n\n ctx.parentEvents.push(startedEvent);\n\n try {\n return await originalMethod();\n } catch (error) {\n caughtError = error;\n FlowLogger.emit({\n eventIdSuffix,\n eventType: `${eventType}ErrorEvent`,\n eventParentIds: [...startedEvent.eventParentIds, startedEvent.eventId],\n data: {\n error: error instanceof Error ? error.message : String(error),\n durationMs: Date.now() - new Date(startedEvent.createdAt).getTime(),\n },\n });\n throw error;\n } finally {\n const parentEvent = ctx.parentEvents.pop();\n if (parentEvent?.eventId === startedEvent.eventId && !caughtError) {\n FlowLogger.emit({\n eventIdSuffix,\n eventType: `${eventType}CompletedEvent`,\n eventParentIds: [\n ...startedEvent.eventParentIds,\n startedEvent.eventId,\n ],\n data: {\n durationMs: Date.now() - new Date(startedEvent.createdAt).getTime(),\n },\n });\n }\n }\n }\n\n /**\n * Initialize a new logging context. Call this at the start of a session.\n */\n static init(sessionId: string, eventBus: EventEmitter): FlowLoggerContext {\n const ctx: FlowLoggerContext = {\n sessionId,\n eventBus,\n parentEvents: [],\n };\n\n loggerContext.enterWith(ctx);\n return ctx;\n }\n\n static async close(context?: FlowLoggerContext | null): Promise<void> {\n const ctx = context ?? loggerContext.getStore() ?? null;\n if (!ctx) return;\n ctx.parentEvents = [];\n }\n\n static get currentContext(): FlowLoggerContext {\n const ctx = loggerContext.getStore() ?? null;\n if (!ctx) {\n throw new Error(\"FlowLogger context is missing.\");\n }\n\n return ctx;\n }\n\n // decorator method to wrap a class method with automatic started/completed/error events\n static wrapWithLogging<TMethod extends AsyncOriginalMethod>(\n options: FlowLoggerLogOptions,\n ) {\n return function <\n TWrappedMethod extends AsyncOriginalMethod<\n Parameters<TMethod>,\n Awaited<ReturnType<TMethod>>,\n ThisParameterType<TMethod>\n >,\n >(originalMethod: TWrappedMethod): TWrappedMethod {\n const wrappedMethod = async function (\n this: ThisParameterType<TWrappedMethod>,\n ...args: Parameters<TWrappedMethod>\n ): Promise<Awaited<ReturnType<TWrappedMethod>>> {\n return await FlowLogger.runWithLogging(\n options,\n (...boundArgs: Parameters<TWrappedMethod>) =>\n originalMethod.apply(this, boundArgs) as Promise<\n Awaited<ReturnType<TWrappedMethod>>\n >,\n args,\n );\n };\n\n return wrappedMethod as unknown as TWrappedMethod;\n };\n }\n\n // closure runner to wrap some async work with automatic started/completed/error events\n // Standard case: the logged params are the same tuple passed to the wrapped method.\n static runWithLogging<TMethod extends AsyncOriginalMethod>(\n options: FlowLoggerLogOptions,\n originalMethod: TMethod,\n params: Readonly<Parameters<TMethod>>,\n ): Promise<Awaited<ReturnType<TMethod>>>;\n // Special case: log an arbitrary params tuple while executing a zero-arg closure.\n static runWithLogging<TResult>(\n options: FlowLoggerLogOptions,\n originalMethod: AsyncOriginalMethod<[], TResult>,\n params: ReadonlyArray<unknown>,\n ): Promise<Awaited<TResult>>;\n static runWithLogging(\n options: FlowLoggerLogOptions,\n originalMethod: AsyncOriginalMethod<unknown[], unknown>,\n params: ReadonlyArray<unknown>,\n ): Promise<unknown> {\n const eventData = {\n ...(options.data ?? {}),\n params: [...params],\n };\n\n const execute = (): Promise<unknown> =>\n FlowLogger.runWithAutoStatusEventLogging(\n {\n ...options,\n data: eventData,\n },\n () => originalMethod(...params),\n );\n\n if (!options.context && !(loggerContext.getStore() ?? null)) {\n return originalMethod(...params);\n }\n\n return options.context\n ? loggerContext.run(FlowLogger.cloneContext(options.context), execute)\n : execute();\n }\n\n // ===========================================================================\n // CDP Events\n // ===========================================================================\n\n private static readonly NOISY_CDP_EVENTS = new Set([\n \"Target.targetInfoChanged\",\n \"Runtime.executionContextCreated\",\n \"Runtime.executionContextDestroyed\",\n \"Runtime.executionContextsCleared\",\n \"Page.lifecycleEvent\",\n \"Network.dataReceived\",\n \"Network.loadingFinished\",\n \"Network.requestWillBeSentExtraInfo\",\n \"Network.responseReceivedExtraInfo\",\n \"Network.requestWillBeSent\",\n \"Network.responseReceived\",\n ]);\n\n private static logCdpEvent(\n context: FlowLoggerContext,\n eventType: \"call\" | \"response\" | \"responseError\" | \"message\",\n {\n method,\n params,\n result,\n error,\n targetId,\n }: {\n method: string;\n params?: unknown;\n result?: unknown;\n error?: string;\n targetId?: string | null;\n },\n eventParentIds?: string[],\n ): FlowEvent | null {\n if (method.endsWith(\".enable\") || method === \"enable\") {\n return null;\n }\n\n if (eventType === \"message\" && FlowLogger.NOISY_CDP_EVENTS.has(method)) {\n return null;\n }\n\n return loggerContext.run(FlowLogger.cloneContext(context), () =>\n FlowLogger.emit({\n eventIdSuffix: \"6\",\n eventType:\n eventType === \"call\"\n ? \"CdpCallEvent\"\n : eventType === \"response\"\n ? \"CdpResponseEvent\"\n : eventType === \"responseError\"\n ? \"CdpResponseErrorEvent\"\n : \"CdpMessageEvent\",\n eventParentIds,\n data: {\n method,\n params,\n result,\n error,\n targetId,\n },\n }),\n );\n }\n\n static logCdpCallEvent(\n context: FlowLoggerContext,\n data: {\n method: string;\n params?: object;\n targetId?: string | null;\n },\n ): FlowEvent | null {\n return FlowLogger.logCdpEvent(context, \"call\", data);\n }\n\n static logCdpResponseEvent(\n context: FlowLoggerContext,\n parentEvent: Pick<FlowEvent, \"eventId\" | \"eventParentIds\">,\n data: {\n method: string;\n result?: unknown;\n error?: string;\n targetId?: string | null;\n },\n ): void {\n FlowLogger.logCdpEvent(\n context,\n data.error ? \"responseError\" : \"response\",\n data,\n [...parentEvent.eventParentIds, parentEvent.eventId],\n );\n }\n\n static logCdpMessageEvent(\n context: FlowLoggerContext,\n parentEvent: Pick<FlowEvent, \"eventId\" | \"eventParentIds\">,\n data: {\n method: string;\n params?: unknown;\n targetId?: string | null;\n },\n ): void {\n FlowLogger.logCdpEvent(context, \"message\", data, [\n ...parentEvent.eventParentIds,\n parentEvent.eventId,\n ]);\n }\n\n // ===========================================================================\n // LLM Events\n // ===========================================================================\n\n static logLlmRequest({\n requestId,\n model,\n prompt,\n }: {\n requestId: string;\n model: string;\n prompt?: string;\n }): void {\n FlowLogger.emit({\n eventIdSuffix: \"7\",\n eventType: \"LlmRequestEvent\",\n data: {\n requestId,\n model,\n prompt,\n },\n });\n }\n\n static logLlmResponse({\n requestId,\n model,\n output,\n inputTokens,\n outputTokens,\n }: {\n requestId: string;\n model: string;\n output?: string;\n inputTokens?: number;\n outputTokens?: number;\n }): void {\n FlowLogger.emit({\n eventIdSuffix: \"7\",\n eventType: \"LlmResponseEvent\",\n data: {\n requestId,\n model,\n output,\n inputTokens,\n outputTokens,\n },\n });\n }\n\n // ===========================================================================\n // LLM Logging Middleware\n // ===========================================================================\n\n /**\n * Create middleware for wrapping language models with LLM call logging.\n * Returns a no-op middleware when logging is disabled.\n */\n static createLlmLoggingMiddleware(\n modelId: string,\n ): Pick<LanguageModelMiddleware, \"wrapGenerate\"> {\n return {\n wrapGenerate: async ({ doGenerate, params }) => {\n const llmRequestId = uuidv7();\n const toolCount = Array.isArray(params.tools) ? params.tools.length : 0;\n const messages = (params.prompt ?? []) as Array<{\n role?: string;\n content?: unknown;\n }>;\n const lastMsg = messages.filter((m) => m.role !== \"system\").pop();\n let rolePrefix = lastMsg?.role ?? \"?\";\n let promptSummary = `(no text) +{${toolCount} tools}`;\n\n if (lastMsg) {\n if (typeof lastMsg.content === \"string\") {\n promptSummary = `${lastMsg.content} +{${toolCount} tools}`;\n } else if (Array.isArray(lastMsg.content)) {\n const toolResult = (\n lastMsg.content as Array<{\n type?: string;\n toolName?: string;\n output?: { type?: string; value?: unknown };\n }>\n ).find((part) => part.type === \"tool-result\");\n\n if (toolResult) {\n rolePrefix = `tool result: ${toolResult.toolName}()`;\n if (\n toolResult.output?.type === \"json\" &&\n toolResult.output.value\n ) {\n promptSummary = `${JSON.stringify(toolResult.output.value)} +{${toolCount} tools}`;\n } else if (Array.isArray(toolResult.output?.value)) {\n promptSummary = `${\n extractLlmMessageSummary({\n content: toolResult.output.value,\n }) ?? \"(no text)\"\n } +{${toolCount} tools}`;\n }\n } else {\n promptSummary = `${\n extractLlmMessageSummary({ content: lastMsg.content }) ??\n \"(no text)\"\n } +{${toolCount} tools}`;\n }\n }\n\n promptSummary = `${rolePrefix}: ${promptSummary}`;\n } else {\n promptSummary = `?: ${promptSummary}`;\n }\n\n FlowLogger.logLlmRequest({\n requestId: llmRequestId,\n model: modelId,\n prompt: promptSummary,\n });\n\n const result = await doGenerate();\n\n // Extract output summary\n const res = result as {\n text?: string;\n content?: unknown;\n toolCalls?: unknown[];\n };\n let outputSummary = res.text || \"\";\n if (!outputSummary && res.content) {\n if (typeof res.content === \"string\") {\n outputSummary = res.content;\n } else if (Array.isArray(res.content)) {\n outputSummary = (\n res.content as Array<{\n type?: string;\n text?: string;\n toolName?: string;\n }>\n )\n .map(\n (c) =>\n c.text ||\n (c.type === \"tool-call\"\n ? `tool call: ${c.toolName}()`\n : `[${c.type}]`),\n )\n .join(\" \");\n }\n }\n if (!outputSummary && res.toolCalls?.length) {\n outputSummary = `[${res.toolCalls.length} tool calls]`;\n }\n\n FlowLogger.logLlmResponse({\n requestId: llmRequestId,\n model: modelId,\n output: outputSummary || \"[empty]\",\n inputTokens: result.usage?.inputTokens,\n outputTokens: result.usage?.outputTokens,\n });\n\n return result;\n },\n };\n }\n}\n\n// =============================================================================\n// LLM Event Extraction Helpers\n// =============================================================================\n\ntype ContentPart = {\n type?: string;\n text?: string;\n content?: unknown[];\n source?: { data?: string };\n image_url?: { url?: string };\n inlineData?: { data?: string };\n};\n\ntype LlmMessageContent = {\n content?: unknown;\n text?: string;\n parts?: unknown[];\n};\n\n/** Extract text and image info from a content array (handles nested tool_result) */\nfunction extractLlmMessageContent(content: unknown[]): {\n text?: string;\n extras: string[];\n} {\n const result = {\n text: undefined as string | undefined,\n extras: [] as string[],\n };\n\n for (const part of content) {\n const p = part as ContentPart;\n // Text\n if (!result.text && p.text) {\n result.text = p.type === \"text\" || !p.type ? p.text : undefined;\n }\n // Images - various formats\n if (p.type === \"image\" || p.type === \"image_url\") {\n const url = p.image_url?.url;\n if (url?.startsWith(\"data:\"))\n result.extras.push(`${dataToKb(url)}kb image`);\n else if (p.source?.data)\n result.extras.push(`${dataToKb(p.source.data)}kb image`);\n else result.extras.push(\"image\");\n } else if (p.source?.data) {\n result.extras.push(`${dataToKb(p.source.data)}kb image`);\n } else if (p.inlineData?.data) {\n result.extras.push(`${dataToKb(p.inlineData.data)}kb image`);\n }\n // Recurse into tool_result content\n if (p.type === \"tool_result\" && Array.isArray(p.content)) {\n const nested = extractLlmMessageContent(p.content);\n if (!result.text && nested.text) {\n result.text = nested.text;\n }\n result.extras.push(...nested.extras);\n }\n }\n\n return result;\n}\n\nfunction extractLlmMessageSummary(\n input: LlmMessageContent,\n options?: {\n trimInstructionPrefix?: boolean;\n extras?: string[];\n },\n): string | undefined {\n const result = {\n text: undefined as string | undefined,\n extras: [...(options?.extras ?? [])],\n };\n\n if (typeof input.content === \"string\") {\n result.text = input.content;\n } else if (typeof input.text === \"string\") {\n result.text = input.text;\n } else if (Array.isArray(input.parts)) {\n const summary = extractLlmMessageContent(input.parts);\n result.text = summary.text;\n result.extras.push(...summary.extras);\n } else if (Array.isArray(input.content)) {\n const summary = extractLlmMessageContent(input.content);\n result.text = summary.text;\n result.extras.push(...summary.extras);\n }\n\n if (options?.trimInstructionPrefix && result.text) {\n result.text = result.text.replace(/^[Ii]nstruction: /, \"\");\n }\n\n const text = result.text;\n if (!text && result.extras.length === 0) return undefined;\n\n let summary = text || \"\";\n if (result.extras.length > 0) {\n const extrasStr = result.extras.map((e) => `+{${e}}`).join(\" \");\n summary = summary ? `${summary} ${extrasStr}` : extrasStr;\n }\n return summary || undefined;\n}\n\n/**\n * Format a prompt summary from LLM messages for logging.\n * Returns format like: \"some text +{5.8kb image} +{schema} +{12 tools}\"\n */\nexport function extractLlmPromptSummary(\n messages: Array<{ role: string; content: unknown }>,\n options?: { toolCount?: number; hasSchema?: boolean },\n): string | undefined {\n try {\n const lastUserMsg = messages.filter((m) => m.role === \"user\").pop();\n if (!lastUserMsg) return undefined;\n\n return extractLlmMessageSummary(lastUserMsg, {\n trimInstructionPrefix: true,\n extras: [\n ...(options?.hasSchema ? [\"schema\"] : []),\n ...(options?.toolCount ? [`${options.toolCount} tools`] : []),\n ],\n });\n } catch {\n return undefined;\n }\n}\n\n/**\n * Extract a text summary from CUA-style messages.\n * Accepts various message formats (Anthropic, OpenAI, Google).\n */\nexport function extractLlmCuaPromptSummary(\n messages: unknown[],\n): string | undefined {\n try {\n const lastMsg = messages\n .filter((m) => {\n const msg = m as { role?: string; type?: string };\n return msg.role === \"user\" || msg.type === \"tool_result\";\n })\n .pop() as\n | { content?: unknown; parts?: unknown[]; text?: string }\n | undefined;\n\n if (!lastMsg) return undefined;\n\n return extractLlmMessageSummary(lastMsg);\n } catch {\n return undefined;\n }\n}\n\n/** Format a CUA response summary for logging */\nexport function extractLlmCuaResponseSummary(output: unknown): string {\n try {\n // Handle Google format or array\n const items: unknown[] =\n (output as { candidates?: [{ content?: { parts?: unknown[] } }] })\n ?.candidates?.[0]?.content?.parts ??\n (Array.isArray(output) ? output : []);\n\n const summary = items\n .map((item) => {\n const i = item as {\n type?: string;\n text?: string;\n name?: string;\n functionCall?: { name?: string };\n };\n if (i.text) return i.text;\n if (i.functionCall?.name) return i.functionCall.name;\n if (i.type === \"tool_use\" && i.name) return i.name;\n return i.type ?? \"[item]\";\n })\n .join(\" \");\n\n return summary;\n } catch {\n return \"[error]\";\n }\n}\n"]}