@browserbasehq/orca 3.2.0-preview.3 → 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 (171) hide show
  1. package/dist/cjs/lib/utils.d.ts +1 -0
  2. package/dist/cjs/lib/utils.js +4 -0
  3. package/dist/cjs/lib/utils.js.map +1 -1
  4. package/dist/cjs/lib/v3/agent/AnthropicCUAClient.js +5 -7
  5. package/dist/cjs/lib/v3/agent/AnthropicCUAClient.js.map +1 -1
  6. package/dist/cjs/lib/v3/agent/GoogleCUAClient.js +5 -7
  7. package/dist/cjs/lib/v3/agent/GoogleCUAClient.js.map +1 -1
  8. package/dist/cjs/lib/v3/agent/OpenAICUAClient.js +5 -7
  9. package/dist/cjs/lib/v3/agent/OpenAICUAClient.js.map +1 -1
  10. package/dist/cjs/lib/v3/agent/tools/act.js +1 -10
  11. package/dist/cjs/lib/v3/agent/tools/act.js.map +1 -1
  12. package/dist/cjs/lib/v3/agent/tools/ariaTree.js +1 -12
  13. package/dist/cjs/lib/v3/agent/tools/ariaTree.js.map +1 -1
  14. package/dist/cjs/lib/v3/agent/tools/braveSearch.js.map +1 -1
  15. package/dist/cjs/lib/v3/agent/tools/browserbaseSearch.js.map +1 -1
  16. package/dist/cjs/lib/v3/agent/tools/click.js.map +1 -1
  17. package/dist/cjs/lib/v3/agent/tools/clickAndHold.js.map +1 -1
  18. package/dist/cjs/lib/v3/agent/tools/dragAndDrop.js.map +1 -1
  19. package/dist/cjs/lib/v3/agent/tools/extract.js +1 -10
  20. package/dist/cjs/lib/v3/agent/tools/extract.js.map +1 -1
  21. package/dist/cjs/lib/v3/agent/tools/fillFormVision.js.map +1 -1
  22. package/dist/cjs/lib/v3/agent/tools/fillform.js +1 -10
  23. package/dist/cjs/lib/v3/agent/tools/fillform.js.map +1 -1
  24. package/dist/cjs/lib/v3/agent/tools/index.d.ts +2 -2
  25. package/dist/cjs/lib/v3/agent/tools/index.js +53 -5
  26. package/dist/cjs/lib/v3/agent/tools/index.js.map +1 -1
  27. package/dist/cjs/lib/v3/agent/tools/keys.d.ts +1 -1
  28. package/dist/cjs/lib/v3/agent/tools/keys.js.map +1 -1
  29. package/dist/cjs/lib/v3/agent/tools/type.js.map +1 -1
  30. package/dist/cjs/lib/v3/api.js +9 -2
  31. package/dist/cjs/lib/v3/api.js.map +1 -1
  32. package/dist/cjs/lib/v3/flowlogger/EventEmitter.d.ts +7 -0
  33. package/dist/cjs/lib/v3/flowlogger/EventEmitter.js +30 -0
  34. package/dist/cjs/lib/v3/flowlogger/EventEmitter.js.map +1 -0
  35. package/dist/cjs/lib/v3/flowlogger/EventSink.d.ts +44 -0
  36. package/dist/cjs/lib/v3/flowlogger/EventSink.js +217 -0
  37. package/dist/cjs/lib/v3/flowlogger/EventSink.js.map +1 -0
  38. package/dist/cjs/lib/v3/flowlogger/EventStore.d.ts +26 -0
  39. package/dist/cjs/lib/v3/flowlogger/EventStore.js +135 -0
  40. package/dist/cjs/lib/v3/flowlogger/EventStore.js.map +1 -0
  41. package/dist/cjs/lib/v3/flowlogger/FlowLogger.d.ts +99 -0
  42. package/dist/cjs/lib/v3/flowlogger/FlowLogger.js +591 -0
  43. package/dist/cjs/lib/v3/flowlogger/FlowLogger.js.map +1 -0
  44. package/dist/cjs/lib/v3/flowlogger/prettify.d.ts +6 -0
  45. package/dist/cjs/lib/v3/flowlogger/prettify.js +395 -0
  46. package/dist/cjs/lib/v3/flowlogger/prettify.js.map +1 -0
  47. package/dist/cjs/lib/v3/handlers/handlerUtils/actHandlerUtils.js +43 -57
  48. package/dist/cjs/lib/v3/handlers/handlerUtils/actHandlerUtils.js.map +1 -1
  49. package/dist/cjs/lib/v3/handlers/v3AgentHandler.d.ts +0 -4
  50. package/dist/cjs/lib/v3/handlers/v3AgentHandler.js +2 -32
  51. package/dist/cjs/lib/v3/handlers/v3AgentHandler.js.map +1 -1
  52. package/dist/cjs/lib/v3/handlers/v3CuaAgentHandler.js +9 -13
  53. package/dist/cjs/lib/v3/handlers/v3CuaAgentHandler.js.map +1 -1
  54. package/dist/cjs/lib/v3/llm/aisdk.js +11 -17
  55. package/dist/cjs/lib/v3/llm/aisdk.js.map +1 -1
  56. package/dist/cjs/lib/v3/types/public/options.d.ts +7 -0
  57. package/dist/cjs/lib/v3/types/public/options.js.map +1 -1
  58. package/dist/cjs/lib/v3/understudy/cdp.d.ts +3 -12
  59. package/dist/cjs/lib/v3/understudy/cdp.js +134 -21
  60. package/dist/cjs/lib/v3/understudy/cdp.js.map +1 -1
  61. package/dist/cjs/lib/v3/understudy/page.js +28 -18
  62. package/dist/cjs/lib/v3/understudy/page.js.map +1 -1
  63. package/dist/cjs/lib/v3/v3.d.ts +7 -2
  64. package/dist/cjs/lib/v3/v3.js +178 -159
  65. package/dist/cjs/lib/v3/v3.js.map +1 -1
  66. package/dist/cjs/tests/integration/flowLogger.spec.d.ts +1 -0
  67. package/dist/cjs/tests/integration/flowLogger.spec.js +714 -0
  68. package/dist/cjs/tests/integration/flowLogger.spec.js.map +1 -0
  69. package/dist/cjs/tests/integration/testUtils.d.ts +33 -0
  70. package/dist/cjs/tests/integration/testUtils.js +144 -0
  71. package/dist/cjs/tests/integration/testUtils.js.map +1 -1
  72. package/dist/cjs/tests/integration/timeouts.spec.js +112 -2
  73. package/dist/cjs/tests/integration/timeouts.spec.js.map +1 -1
  74. package/dist/cjs/tests/unit/flowlogger-capturing-cdp.test.d.ts +1 -0
  75. package/dist/cjs/tests/unit/flowlogger-capturing-cdp.test.js +95 -0
  76. package/dist/cjs/tests/unit/flowlogger-capturing-cdp.test.js.map +1 -0
  77. package/dist/cjs/tests/unit/flowlogger-capturing-llm.test.d.ts +1 -0
  78. package/dist/cjs/tests/unit/flowlogger-capturing-llm.test.js +43 -0
  79. package/dist/cjs/tests/unit/flowlogger-capturing-llm.test.js.map +1 -0
  80. package/dist/cjs/tests/unit/flowlogger-eventstore.test.d.ts +1 -0
  81. package/dist/cjs/tests/unit/flowlogger-eventstore.test.js +250 -0
  82. package/dist/cjs/tests/unit/flowlogger-eventstore.test.js.map +1 -0
  83. package/dist/esm/lib/utils.d.ts +1 -0
  84. package/dist/esm/lib/utils.js +3 -0
  85. package/dist/esm/lib/utils.js.map +1 -1
  86. package/dist/esm/lib/v3/agent/AnthropicCUAClient.js +5 -7
  87. package/dist/esm/lib/v3/agent/AnthropicCUAClient.js.map +1 -1
  88. package/dist/esm/lib/v3/agent/GoogleCUAClient.js +5 -7
  89. package/dist/esm/lib/v3/agent/GoogleCUAClient.js.map +1 -1
  90. package/dist/esm/lib/v3/agent/OpenAICUAClient.js +5 -7
  91. package/dist/esm/lib/v3/agent/OpenAICUAClient.js.map +1 -1
  92. package/dist/esm/lib/v3/agent/tools/act.js +1 -10
  93. package/dist/esm/lib/v3/agent/tools/act.js.map +1 -1
  94. package/dist/esm/lib/v3/agent/tools/ariaTree.js +1 -12
  95. package/dist/esm/lib/v3/agent/tools/ariaTree.js.map +1 -1
  96. package/dist/esm/lib/v3/agent/tools/braveSearch.js.map +1 -1
  97. package/dist/esm/lib/v3/agent/tools/browserbaseSearch.js.map +1 -1
  98. package/dist/esm/lib/v3/agent/tools/click.js.map +1 -1
  99. package/dist/esm/lib/v3/agent/tools/clickAndHold.js.map +1 -1
  100. package/dist/esm/lib/v3/agent/tools/dragAndDrop.js.map +1 -1
  101. package/dist/esm/lib/v3/agent/tools/extract.js +1 -10
  102. package/dist/esm/lib/v3/agent/tools/extract.js.map +1 -1
  103. package/dist/esm/lib/v3/agent/tools/fillFormVision.js.map +1 -1
  104. package/dist/esm/lib/v3/agent/tools/fillform.js +1 -10
  105. package/dist/esm/lib/v3/agent/tools/fillform.js.map +1 -1
  106. package/dist/esm/lib/v3/agent/tools/index.d.ts +2 -2
  107. package/dist/esm/lib/v3/agent/tools/index.js +53 -5
  108. package/dist/esm/lib/v3/agent/tools/index.js.map +1 -1
  109. package/dist/esm/lib/v3/agent/tools/keys.d.ts +1 -1
  110. package/dist/esm/lib/v3/agent/tools/keys.js.map +1 -1
  111. package/dist/esm/lib/v3/agent/tools/type.js.map +1 -1
  112. package/dist/esm/lib/v3/api.js +9 -2
  113. package/dist/esm/lib/v3/api.js.map +1 -1
  114. package/dist/esm/lib/v3/flowlogger/EventEmitter.d.ts +7 -0
  115. package/dist/esm/lib/v3/flowlogger/EventEmitter.js +26 -0
  116. package/dist/esm/lib/v3/flowlogger/EventEmitter.js.map +1 -0
  117. package/dist/esm/lib/v3/flowlogger/EventSink.d.ts +44 -0
  118. package/dist/esm/lib/v3/flowlogger/EventSink.js +206 -0
  119. package/dist/esm/lib/v3/flowlogger/EventSink.js.map +1 -0
  120. package/dist/esm/lib/v3/flowlogger/EventStore.d.ts +26 -0
  121. package/dist/esm/lib/v3/flowlogger/EventStore.js +127 -0
  122. package/dist/esm/lib/v3/flowlogger/EventStore.js.map +1 -0
  123. package/dist/esm/lib/v3/flowlogger/FlowLogger.d.ts +99 -0
  124. package/dist/esm/lib/v3/flowlogger/FlowLogger.js +583 -0
  125. package/dist/esm/lib/v3/flowlogger/FlowLogger.js.map +1 -0
  126. package/dist/esm/lib/v3/flowlogger/prettify.d.ts +6 -0
  127. package/dist/esm/lib/v3/flowlogger/prettify.js +389 -0
  128. package/dist/esm/lib/v3/flowlogger/prettify.js.map +1 -0
  129. package/dist/esm/lib/v3/handlers/handlerUtils/actHandlerUtils.js +43 -57
  130. package/dist/esm/lib/v3/handlers/handlerUtils/actHandlerUtils.js.map +1 -1
  131. package/dist/esm/lib/v3/handlers/v3AgentHandler.d.ts +0 -4
  132. package/dist/esm/lib/v3/handlers/v3AgentHandler.js +2 -32
  133. package/dist/esm/lib/v3/handlers/v3AgentHandler.js.map +1 -1
  134. package/dist/esm/lib/v3/handlers/v3CuaAgentHandler.js +9 -13
  135. package/dist/esm/lib/v3/handlers/v3CuaAgentHandler.js.map +1 -1
  136. package/dist/esm/lib/v3/llm/aisdk.js +11 -17
  137. package/dist/esm/lib/v3/llm/aisdk.js.map +1 -1
  138. package/dist/esm/lib/v3/types/public/options.d.ts +7 -0
  139. package/dist/esm/lib/v3/types/public/options.js.map +1 -1
  140. package/dist/esm/lib/v3/understudy/cdp.d.ts +3 -12
  141. package/dist/esm/lib/v3/understudy/cdp.js +134 -21
  142. package/dist/esm/lib/v3/understudy/cdp.js.map +1 -1
  143. package/dist/esm/lib/v3/understudy/page.js +28 -18
  144. package/dist/esm/lib/v3/understudy/page.js.map +1 -1
  145. package/dist/esm/lib/v3/v3.d.ts +7 -2
  146. package/dist/esm/lib/v3/v3.js +178 -159
  147. package/dist/esm/lib/v3/v3.js.map +1 -1
  148. package/dist/esm/tests/integration/flowLogger.spec.d.ts +1 -0
  149. package/dist/esm/tests/integration/flowLogger.spec.js +712 -0
  150. package/dist/esm/tests/integration/flowLogger.spec.js.map +1 -0
  151. package/dist/esm/tests/integration/testUtils.d.ts +33 -0
  152. package/dist/esm/tests/integration/testUtils.js +138 -0
  153. package/dist/esm/tests/integration/testUtils.js.map +1 -1
  154. package/dist/esm/tests/integration/timeouts.spec.js +112 -2
  155. package/dist/esm/tests/integration/timeouts.spec.js.map +1 -1
  156. package/dist/esm/tests/unit/flowlogger-capturing-cdp.test.d.ts +1 -0
  157. package/dist/esm/tests/unit/flowlogger-capturing-cdp.test.js +93 -0
  158. package/dist/esm/tests/unit/flowlogger-capturing-cdp.test.js.map +1 -0
  159. package/dist/esm/tests/unit/flowlogger-capturing-llm.test.d.ts +1 -0
  160. package/dist/esm/tests/unit/flowlogger-capturing-llm.test.js +41 -0
  161. package/dist/esm/tests/unit/flowlogger-capturing-llm.test.js.map +1 -0
  162. package/dist/esm/tests/unit/flowlogger-eventstore.test.d.ts +1 -0
  163. package/dist/esm/tests/unit/flowlogger-eventstore.test.js +248 -0
  164. package/dist/esm/tests/unit/flowlogger-eventstore.test.js.map +1 -0
  165. package/package.json +3 -1
  166. package/dist/cjs/lib/v3/flowLogger.d.ts +0 -139
  167. package/dist/cjs/lib/v3/flowLogger.js +0 -881
  168. package/dist/cjs/lib/v3/flowLogger.js.map +0 -1
  169. package/dist/esm/lib/v3/flowLogger.d.ts +0 -139
  170. package/dist/esm/lib/v3/flowLogger.js +0 -868
  171. package/dist/esm/lib/v3/flowLogger.js.map +0 -1
@@ -0,0 +1,93 @@
1
+ import { EventEmitter } from "node:events";
2
+ import { describe, it, expect } from "vitest";
3
+ import { CdpConnection } from "../../lib/v3/understudy/cdp.js";
4
+ import { InMemoryEventSink } from "../../lib/v3/flowlogger/EventSink.js";
5
+ import { EventEmitterWithWildcardSupport } from "../../lib/v3/flowlogger/EventEmitter.js";
6
+ import { EventStore } from "../../lib/v3/flowlogger/EventStore.js";
7
+ import { FlowEvent, FlowLogger } from "../../lib/v3/flowlogger/FlowLogger.js";
8
+ function attachEventStoreToBus(store, bus) {
9
+ const onFlowEvent = (event) => {
10
+ if (event instanceof FlowEvent) {
11
+ void store.emit(event);
12
+ }
13
+ };
14
+ bus.on("*", onFlowEvent);
15
+ return () => {
16
+ bus.off("*", onFlowEvent);
17
+ };
18
+ }
19
+ class FakeSocket extends EventEmitter {
20
+ sentPayloads = [];
21
+ readyState = 1;
22
+ send(payload) {
23
+ this.sentPayloads.push(payload);
24
+ }
25
+ close() {
26
+ this.readyState = 3;
27
+ this.emit("close", 1000, "");
28
+ }
29
+ }
30
+ function createConnection(socket) {
31
+ // The production constructor is private; tests instantiate it directly so
32
+ // they can drive raw websocket messages without a real browser.
33
+ const ConnectionCtor = CdpConnection;
34
+ return new ConnectionCtor(socket);
35
+ }
36
+ function requireEvent(events, predicate, description) {
37
+ const match = events.find(predicate);
38
+ expect(match, `missing ${description}`).toBeDefined();
39
+ return match;
40
+ }
41
+ describe("flow logger cdp context", () => {
42
+ it("preserves the active parent chain when a session event handler issues a nested CDP call", async () => {
43
+ const sessionId = "session-test";
44
+ const socket = new FakeSocket();
45
+ const eventBus = new EventEmitterWithWildcardSupport();
46
+ const sink = new InMemoryEventSink();
47
+ const eventStore = new EventStore(sessionId, undefined, sink);
48
+ const detachBus = attachEventStoreToBus(eventStore, eventBus);
49
+ const conn = createConnection(socket);
50
+ conn.flowLoggerContext = FlowLogger.init(sessionId, eventBus);
51
+ // Seed the target/session mapping the same way a real attach flow would
52
+ // before any session-scoped messages are dispatched.
53
+ conn.onMessage(JSON.stringify({
54
+ method: "Target.attachedToTarget",
55
+ params: {
56
+ sessionId: "target-session",
57
+ targetInfo: { targetId: "target-1" },
58
+ },
59
+ }));
60
+ const session = conn.getSession("target-session");
61
+ expect(session).toBeDefined();
62
+ session.on("Runtime.consoleAPICalled", () => {
63
+ // This nested send used to lose its parent chain because the callback ran
64
+ // after the original ALS scope had already unwound.
65
+ void session.send("Runtime.evaluate", {
66
+ expression: "2 + 2",
67
+ });
68
+ });
69
+ await FlowLogger.runWithLogging({
70
+ context: conn.flowLoggerContext,
71
+ eventType: "SyntheticParentEvent",
72
+ }, async () => {
73
+ void session.send("Page.navigate", {
74
+ url: "https://example.com",
75
+ });
76
+ }, []);
77
+ conn.onMessage(JSON.stringify({
78
+ method: "Runtime.consoleAPICalled",
79
+ sessionId: "target-session",
80
+ params: { type: "log" },
81
+ }));
82
+ // The nested Runtime.evaluate call should still attach under the synthetic
83
+ // parent event even though it was triggered by a later session callback.
84
+ const events = await eventStore.query({});
85
+ const parentEvent = requireEvent(events, (event) => event.eventType === "SyntheticParentEvent", "SyntheticParentEvent");
86
+ const nestedCallEvent = requireEvent(events, (event) => event.eventType === "CdpCallEvent" &&
87
+ String(event.data.method) === "Runtime.evaluate", "nested Runtime.evaluate CdpCallEvent");
88
+ expect(nestedCallEvent.eventParentIds).toEqual([parentEvent.eventId]);
89
+ detachBus();
90
+ await eventStore.destroy();
91
+ });
92
+ });
93
+ //# sourceMappingURL=flowlogger-capturing-cdp.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flowlogger-capturing-cdp.test.js","sourceRoot":"","sources":["../../../../tests/unit/flowlogger-capturing-cdp.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { EventEmitter } from \"node:events\";\nimport { describe, it, expect } from \"vitest\";\nimport { CdpConnection } from \"../../lib/v3/understudy/cdp.js\";\nimport { InMemoryEventSink } from \"../../lib/v3/flowlogger/EventSink.js\";\nimport { EventEmitterWithWildcardSupport } from \"../../lib/v3/flowlogger/EventEmitter.js\";\nimport { EventStore } from \"../../lib/v3/flowlogger/EventStore.js\";\nimport { FlowEvent, FlowLogger } from \"../../lib/v3/flowlogger/FlowLogger.js\";\n\nfunction attachEventStoreToBus(\n store: EventStore,\n bus: EventEmitterWithWildcardSupport,\n): () => void {\n const onFlowEvent = (event: unknown) => {\n if (event instanceof FlowEvent) {\n void store.emit(event);\n }\n };\n\n bus.on(\"*\", onFlowEvent);\n return () => {\n bus.off(\"*\", onFlowEvent);\n };\n}\n\nclass FakeSocket extends EventEmitter {\n sentPayloads: string[] = [];\n readyState = 1;\n\n send(payload: string): void {\n this.sentPayloads.push(payload);\n }\n\n close(): void {\n this.readyState = 3;\n this.emit(\"close\", 1000, \"\");\n }\n}\n\nfunction createConnection(socket: FakeSocket): CdpConnection {\n // The production constructor is private; tests instantiate it directly so\n // they can drive raw websocket messages without a real browser.\n const ConnectionCtor = CdpConnection as unknown as {\n new (ws: FakeSocket): CdpConnection;\n };\n return new ConnectionCtor(socket);\n}\n\nfunction requireEvent(\n events: FlowEvent[],\n predicate: (event: FlowEvent) => boolean,\n description: string,\n): FlowEvent {\n const match = events.find(predicate);\n expect(match, `missing ${description}`).toBeDefined();\n return match as FlowEvent;\n}\n\ndescribe(\"flow logger cdp context\", () => {\n it(\"preserves the active parent chain when a session event handler issues a nested CDP call\", async () => {\n const sessionId = \"session-test\";\n const socket = new FakeSocket();\n const eventBus = new EventEmitterWithWildcardSupport();\n const sink = new InMemoryEventSink();\n const eventStore = new EventStore(sessionId, undefined, sink);\n\n const detachBus = attachEventStoreToBus(eventStore, eventBus);\n\n const conn = createConnection(socket);\n conn.flowLoggerContext = FlowLogger.init(sessionId, eventBus);\n\n // Seed the target/session mapping the same way a real attach flow would\n // before any session-scoped messages are dispatched.\n (conn as unknown as { onMessage(json: string): void }).onMessage(\n JSON.stringify({\n method: \"Target.attachedToTarget\",\n params: {\n sessionId: \"target-session\",\n targetInfo: { targetId: \"target-1\" },\n },\n }),\n );\n\n const session = conn.getSession(\"target-session\");\n expect(session).toBeDefined();\n\n session!.on(\"Runtime.consoleAPICalled\", () => {\n // This nested send used to lose its parent chain because the callback ran\n // after the original ALS scope had already unwound.\n void session!.send(\"Runtime.evaluate\", {\n expression: \"2 + 2\",\n });\n });\n\n await FlowLogger.runWithLogging(\n {\n context: conn.flowLoggerContext,\n eventType: \"SyntheticParentEvent\",\n },\n async () => {\n void session!.send(\"Page.navigate\", {\n url: \"https://example.com\",\n });\n },\n [],\n );\n\n (conn as unknown as { onMessage(json: string): void }).onMessage(\n JSON.stringify({\n method: \"Runtime.consoleAPICalled\",\n sessionId: \"target-session\",\n params: { type: \"log\" },\n }),\n );\n\n // The nested Runtime.evaluate call should still attach under the synthetic\n // parent event even though it was triggered by a later session callback.\n const events = await eventStore.query({});\n const parentEvent = requireEvent(\n events,\n (event) => event.eventType === \"SyntheticParentEvent\",\n \"SyntheticParentEvent\",\n );\n const nestedCallEvent = requireEvent(\n events,\n (event) =>\n event.eventType === \"CdpCallEvent\" &&\n String(event.data.method) === \"Runtime.evaluate\",\n \"nested Runtime.evaluate CdpCallEvent\",\n );\n\n expect(nestedCallEvent.eventParentIds).toEqual([parentEvent.eventId]);\n\n detachBus();\n await eventStore.destroy();\n });\n});\n"]}
@@ -0,0 +1,41 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { FlowLogger } from "../../lib/v3/flowlogger/FlowLogger.js";
3
+ describe("flow logger llm logging", () => {
4
+ it("no-ops direct llm logging calls when no flow context is active", () => {
5
+ // These helpers are called from multiple model adapters, so they must stay
6
+ // safe even when a test or utility invokes them outside any ALS flow scope.
7
+ expect(() => FlowLogger.logLlmRequest({
8
+ requestId: "req-1",
9
+ model: "mock-model",
10
+ prompt: "hello",
11
+ })).not.toThrow();
12
+ expect(() => FlowLogger.logLlmResponse({
13
+ requestId: "req-1",
14
+ model: "mock-model",
15
+ output: "world",
16
+ inputTokens: 1,
17
+ outputTokens: 1,
18
+ })).not.toThrow();
19
+ });
20
+ it("does not throw from llm middleware when no flow context is active", async () => {
21
+ const middleware = FlowLogger.createLlmLoggingMiddleware("mock-model");
22
+ // Missing flow context should degrade to a silent no-op and preserve the
23
+ // underlying model result.
24
+ await expect(middleware.wrapGenerate({
25
+ doGenerate: async () => ({
26
+ text: "done",
27
+ usage: {
28
+ inputTokens: 1,
29
+ outputTokens: 1,
30
+ totalTokens: 2,
31
+ },
32
+ }),
33
+ params: {
34
+ prompt: [],
35
+ },
36
+ })).resolves.toMatchObject({
37
+ text: "done",
38
+ });
39
+ });
40
+ });
41
+ //# sourceMappingURL=flowlogger-capturing-llm.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flowlogger-capturing-llm.test.js","sourceRoot":"","sources":["../../../../tests/unit/flowlogger-capturing-llm.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,uCAAuC,CAAC;AAEnE,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE;IACvC,EAAE,CAAC,gEAAgE,EAAE,GAAG,EAAE;QACxE,2EAA2E;QAC3E,4EAA4E;QAC5E,MAAM,CAAC,GAAG,EAAE,CACV,UAAU,CAAC,aAAa,CAAC;YACvB,SAAS,EAAE,OAAO;YAClB,KAAK,EAAE,YAAY;YACnB,MAAM,EAAE,OAAO;SAChB,CAAC,CACH,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QAEhB,MAAM,CAAC,GAAG,EAAE,CACV,UAAU,CAAC,cAAc,CAAC;YACxB,SAAS,EAAE,OAAO;YAClB,KAAK,EAAE,YAAY;YACnB,MAAM,EAAE,OAAO;YACf,WAAW,EAAE,CAAC;YACd,YAAY,EAAE,CAAC;SAChB,CAAC,CACH,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mEAAmE,EAAE,KAAK,IAAI,EAAE;QACjF,MAAM,UAAU,GAAG,UAAU,CAAC,0BAA0B,CAAC,YAAY,CAAC,CAAC;QAEvE,yEAAyE;QACzE,2BAA2B;QAC3B,MAAM,MAAM,CACV,UAAU,CAAC,YAAY,CAAC;YACtB,UAAU,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;gBACvB,IAAI,EAAE,MAAM;gBACZ,KAAK,EAAE;oBACL,WAAW,EAAE,CAAC;oBACd,YAAY,EAAE,CAAC;oBACf,WAAW,EAAE,CAAC;iBACf;aACF,CAAC;YACF,MAAM,EAAE;gBACN,MAAM,EAAE,EAAE;aACX;SACO,CAAC,CACZ,CAAC,QAAQ,CAAC,aAAa,CAAC;YACvB,IAAI,EAAE,MAAM;SACb,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["import { describe, expect, it } from \"vitest\";\nimport { FlowLogger } from \"../../lib/v3/flowlogger/FlowLogger.js\";\n\ndescribe(\"flow logger llm logging\", () => {\n it(\"no-ops direct llm logging calls when no flow context is active\", () => {\n // These helpers are called from multiple model adapters, so they must stay\n // safe even when a test or utility invokes them outside any ALS flow scope.\n expect(() =>\n FlowLogger.logLlmRequest({\n requestId: \"req-1\",\n model: \"mock-model\",\n prompt: \"hello\",\n }),\n ).not.toThrow();\n\n expect(() =>\n FlowLogger.logLlmResponse({\n requestId: \"req-1\",\n model: \"mock-model\",\n output: \"world\",\n inputTokens: 1,\n outputTokens: 1,\n }),\n ).not.toThrow();\n });\n\n it(\"does not throw from llm middleware when no flow context is active\", async () => {\n const middleware = FlowLogger.createLlmLoggingMiddleware(\"mock-model\");\n\n // Missing flow context should degrade to a silent no-op and preserve the\n // underlying model result.\n await expect(\n middleware.wrapGenerate({\n doGenerate: async () => ({\n text: \"done\",\n usage: {\n inputTokens: 1,\n outputTokens: 1,\n totalTokens: 2,\n },\n }),\n params: {\n prompt: [],\n },\n } as never),\n ).resolves.toMatchObject({\n text: \"done\",\n });\n });\n});\n"]}
@@ -0,0 +1,248 @@
1
+ import { afterEach, describe, expect, it } from "vitest";
2
+ import { EventStore } from "../../lib/v3/flowlogger/EventStore.js";
3
+ import { EventEmitterWithWildcardSupport } from "../../lib/v3/flowlogger/EventEmitter.js";
4
+ import { FlowEvent } from "../../lib/v3/flowlogger/FlowLogger.js";
5
+ function attachEventStoreToBus(store, bus) {
6
+ const onFlowEvent = (event) => {
7
+ if (event instanceof FlowEvent) {
8
+ void store.emit(event);
9
+ }
10
+ };
11
+ bus.on("*", onFlowEvent);
12
+ return () => {
13
+ bus.off("*", onFlowEvent);
14
+ };
15
+ }
16
+ function createVerboseStoreHarness() {
17
+ const writes = [];
18
+ process.stderr.write = ((chunk, cb) => {
19
+ writes.push(String(chunk));
20
+ cb?.(null);
21
+ return true;
22
+ });
23
+ const store = new EventStore("session-test", { verbose: 2 });
24
+ const bus = new EventEmitterWithWildcardSupport();
25
+ const detachBus = attachEventStoreToBus(store, bus);
26
+ return { writes, store, bus, detachBus };
27
+ }
28
+ describe("flow logger event store", () => {
29
+ const stderrWrite = process.stderr.write.bind(process.stderr);
30
+ afterEach(() => {
31
+ process.stderr.write = stderrWrite;
32
+ });
33
+ it("queries recent events from the default in-memory sink", async () => {
34
+ const store = new EventStore("session-test");
35
+ await store.emit(new FlowEvent({
36
+ eventType: "StagehandExtractEvent",
37
+ sessionId: "session-test",
38
+ eventId: "stagehand-1234",
39
+ eventCreatedAt: "2026-03-16T21:45:00.000Z",
40
+ data: { params: ["grab title"] },
41
+ }));
42
+ const events = await store.query({});
43
+ expect(events).toHaveLength(1);
44
+ expect(events[0].eventType).toBe("StagehandExtractEvent");
45
+ await store.destroy();
46
+ });
47
+ it("drops payloads from the default in-memory sink", async () => {
48
+ const store = new EventStore("session-test");
49
+ await store.emit(new FlowEvent({
50
+ eventType: "LlmRequestEvent",
51
+ sessionId: "session-test",
52
+ eventId: "llm-1234",
53
+ eventCreatedAt: "2026-03-16T21:45:00.000Z",
54
+ data: {
55
+ prompt: [{ type: "image_url", image_url: { url: "huge" } }],
56
+ output: "huge",
57
+ },
58
+ }));
59
+ const [event] = await store.query({});
60
+ expect(event.eventType).toBe("LlmRequestEvent");
61
+ expect(event.eventId).toBe("llm-1234");
62
+ expect(event.data).toEqual({});
63
+ await store.destroy();
64
+ });
65
+ it("renders semantic hierarchy tags for non-cdp stderr events only", async () => {
66
+ // Intercept stderr so the pretty sink can be asserted without polluting the
67
+ // real test runner output.
68
+ const { writes, store, bus, detachBus } = createVerboseStoreHarness();
69
+ const stepEvent = new FlowEvent({
70
+ eventType: "StagehandExtractEvent",
71
+ sessionId: "session-test",
72
+ eventId: "stagehand-1234",
73
+ eventCreatedAt: "2026-03-16T21:45:00.000Z",
74
+ data: { params: ["grab title"] },
75
+ });
76
+ const cdpEvent = new FlowEvent({
77
+ eventType: "CdpCallEvent",
78
+ sessionId: "session-test",
79
+ eventId: "cdp-call-5678",
80
+ eventCreatedAt: "2026-03-16T21:45:00.100Z",
81
+ eventParentIds: [stepEvent.eventId],
82
+ data: {
83
+ method: "Runtime.evaluate",
84
+ params: { expression: "2 + 2" },
85
+ targetId: "1234567890ABCDEF1234567890ABCDEF",
86
+ },
87
+ });
88
+ // The stderr sink intentionally suppresses CDP noise even though the event
89
+ // still exists for in-memory and file-backed sinks.
90
+ bus.emit(stepEvent.eventType, stepEvent);
91
+ bus.emit(cdpEvent.eventType, cdpEvent);
92
+ await new Promise((resolve) => setTimeout(resolve, 0));
93
+ expect(writes).toHaveLength(1);
94
+ expect(writes[0]).toContain("[🆂 #1234 EXTRACT]");
95
+ expect(writes[0]).toContain("Stagehand.extract");
96
+ expect(writes[0]).not.toContain("Runtime.evaluate");
97
+ detachBus();
98
+ await store.destroy();
99
+ });
100
+ it("renders generic stagehand events without crashing the stderr sink", async () => {
101
+ const { writes, store, bus, detachBus } = createVerboseStoreHarness();
102
+ // `StagehandEvent` has no action suffix, so this guards the formatter path
103
+ // that cannot assume a method name exists.
104
+ bus.emit("StagehandEvent", new FlowEvent({
105
+ eventType: "StagehandEvent",
106
+ sessionId: "session-test",
107
+ eventId: "stagehand-0001",
108
+ eventCreatedAt: "2026-03-16T21:45:00.000Z",
109
+ data: { params: ["noop"] },
110
+ }));
111
+ await new Promise((resolve) => setTimeout(resolve, 0));
112
+ expect(writes).toHaveLength(1);
113
+ expect(writes[0]).toContain("[🆂 #0001");
114
+ expect(writes[0]).toContain("Stagehand(");
115
+ detachBus();
116
+ await store.destroy();
117
+ });
118
+ it("colorizes pretty stderr output with ansi escapes when enabled", async () => {
119
+ const previousForceColor = process.env.FORCE_COLOR;
120
+ const previousNoColor = process.env.NO_COLOR;
121
+ delete process.env.NO_COLOR;
122
+ process.env.FORCE_COLOR = "1";
123
+ const { writes, store, bus, detachBus } = createVerboseStoreHarness();
124
+ try {
125
+ bus.emit("StagehandActEvent", new FlowEvent({
126
+ eventType: "StagehandActEvent",
127
+ sessionId: "session-test",
128
+ eventId: "stagehand-0002",
129
+ eventCreatedAt: "2026-03-16T21:45:00.000Z",
130
+ data: { params: ["click submit"] },
131
+ }));
132
+ await new Promise((resolve) => setTimeout(resolve, 0));
133
+ expect(writes).toHaveLength(1);
134
+ expect(writes[0]).toContain("\u001B[");
135
+ }
136
+ finally {
137
+ if (previousNoColor === undefined) {
138
+ delete process.env.NO_COLOR;
139
+ }
140
+ else {
141
+ process.env.NO_COLOR = previousNoColor;
142
+ }
143
+ if (previousForceColor === undefined) {
144
+ delete process.env.FORCE_COLOR;
145
+ }
146
+ else {
147
+ process.env.FORCE_COLOR = previousForceColor;
148
+ }
149
+ detachBus();
150
+ await store.destroy();
151
+ }
152
+ });
153
+ it("keeps agent ancestry and start ids for completion events after many child events", async () => {
154
+ const { writes, store, bus, detachBus } = createVerboseStoreHarness();
155
+ const agentEvent = new FlowEvent({
156
+ eventType: "AgentExecuteEvent",
157
+ sessionId: "session-test",
158
+ eventId: "agent-1234",
159
+ eventCreatedAt: "2026-03-16T21:45:00.000Z",
160
+ data: { params: [{ instruction: "click the button" }] },
161
+ });
162
+ const actEvent = new FlowEvent({
163
+ eventType: "StagehandActEvent",
164
+ sessionId: "session-test",
165
+ eventId: "stagehand-2222",
166
+ eventCreatedAt: "2026-03-16T21:45:00.001Z",
167
+ eventParentIds: [agentEvent.eventId],
168
+ data: { params: ["click the button"] },
169
+ });
170
+ const clickEvent = new FlowEvent({
171
+ eventType: "UnderstudyClickEvent",
172
+ sessionId: "session-test",
173
+ eventId: "action-3333",
174
+ eventCreatedAt: "2026-03-16T21:45:00.002Z",
175
+ eventParentIds: [agentEvent.eventId, actEvent.eventId],
176
+ data: { target: "xpath=/button[1]" },
177
+ });
178
+ bus.emit(agentEvent.eventType, agentEvent);
179
+ bus.emit(actEvent.eventType, actEvent);
180
+ bus.emit(clickEvent.eventType, clickEvent);
181
+ // Flood the retained history with child events so the completion lines have
182
+ // to recover their displayed ancestry from the queryable sink.
183
+ for (let index = 0; index < 150; index += 1) {
184
+ bus.emit("CdpCallEvent", new FlowEvent({
185
+ eventType: "CdpCallEvent",
186
+ sessionId: "session-test",
187
+ eventId: `cdp-${String(index).padStart(4, "0")}`,
188
+ eventCreatedAt: `2026-03-16T21:45:00.${String(index + 10).padStart(3, "0")}Z`,
189
+ eventParentIds: [
190
+ agentEvent.eventId,
191
+ actEvent.eventId,
192
+ clickEvent.eventId,
193
+ ],
194
+ data: {
195
+ method: "Runtime.evaluate",
196
+ params: { expression: `${index}` },
197
+ targetId: "1234567890ABCDEF1234567890ABCDEF",
198
+ },
199
+ }));
200
+ }
201
+ bus.emit("UnderstudyClickCompletedEvent", new FlowEvent({
202
+ eventType: "UnderstudyClickCompletedEvent",
203
+ sessionId: "session-test",
204
+ eventId: "done-4444",
205
+ eventCreatedAt: "2026-03-16T21:45:01.000Z",
206
+ eventParentIds: [
207
+ agentEvent.eventId,
208
+ actEvent.eventId,
209
+ clickEvent.eventId,
210
+ ],
211
+ data: { durationMs: 250 },
212
+ }));
213
+ bus.emit("StagehandActCompletedEvent", new FlowEvent({
214
+ eventType: "StagehandActCompletedEvent",
215
+ sessionId: "session-test",
216
+ eventId: "done-5555",
217
+ eventCreatedAt: "2026-03-16T21:45:01.001Z",
218
+ eventParentIds: [agentEvent.eventId, actEvent.eventId],
219
+ data: { durationMs: 500 },
220
+ }));
221
+ bus.emit("AgentExecuteCompletedEvent", new FlowEvent({
222
+ eventType: "AgentExecuteCompletedEvent",
223
+ sessionId: "session-test",
224
+ eventId: "done-6666",
225
+ eventCreatedAt: "2026-03-16T21:45:01.002Z",
226
+ eventParentIds: [agentEvent.eventId],
227
+ data: { durationMs: 750 },
228
+ }));
229
+ await new Promise((resolve) => setTimeout(resolve, 0));
230
+ // Completion lines should reference the original started-event ids, not the
231
+ // synthetic completed-event ids emitted at the end of the lifecycle.
232
+ const clickCompletedLine = writes.find((line) => line.includes("CLICK completed"));
233
+ const actCompletedLine = writes.find((line) => line.includes("ACT completed"));
234
+ const agentCompletedLine = writes.find((line) => line.includes("Agent.execute() completed"));
235
+ expect(clickCompletedLine).toContain("[🅰 #1234]");
236
+ expect(clickCompletedLine).toContain("[🆂 #2222 ACT]");
237
+ expect(clickCompletedLine).toContain("[🆄 #3333 CLICK]");
238
+ expect(clickCompletedLine).not.toContain("#4444");
239
+ expect(actCompletedLine).toContain("[🅰 #1234]");
240
+ expect(actCompletedLine).toContain("[🆂 #2222 ACT]");
241
+ expect(actCompletedLine).not.toContain("#5555");
242
+ expect(agentCompletedLine).toContain("[🅰 #1234]");
243
+ expect(agentCompletedLine).not.toContain("#6666");
244
+ detachBus();
245
+ await store.destroy();
246
+ });
247
+ });
248
+ //# sourceMappingURL=flowlogger-eventstore.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flowlogger-eventstore.test.js","sourceRoot":"","sources":["../../../../tests/unit/flowlogger-eventstore.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { afterEach, describe, expect, it } from \"vitest\";\nimport { EventStore } from \"../../lib/v3/flowlogger/EventStore.js\";\nimport { EventEmitterWithWildcardSupport } from \"../../lib/v3/flowlogger/EventEmitter.js\";\nimport { FlowEvent } from \"../../lib/v3/flowlogger/FlowLogger.js\";\n\nfunction attachEventStoreToBus(\n store: EventStore,\n bus: EventEmitterWithWildcardSupport,\n): () => void {\n const onFlowEvent = (event: unknown) => {\n if (event instanceof FlowEvent) {\n void store.emit(event);\n }\n };\n\n bus.on(\"*\", onFlowEvent);\n return () => {\n bus.off(\"*\", onFlowEvent);\n };\n}\n\nfunction createVerboseStoreHarness(): {\n writes: string[];\n store: EventStore;\n bus: EventEmitterWithWildcardSupport;\n detachBus: () => void;\n} {\n const writes: string[] = [];\n process.stderr.write = ((\n chunk: string,\n cb?: (error?: Error | null) => void,\n ) => {\n writes.push(String(chunk));\n cb?.(null);\n return true;\n }) as typeof process.stderr.write;\n\n const store = new EventStore(\"session-test\", { verbose: 2 } as never);\n const bus = new EventEmitterWithWildcardSupport();\n const detachBus = attachEventStoreToBus(store, bus);\n\n return { writes, store, bus, detachBus };\n}\n\ndescribe(\"flow logger event store\", () => {\n const stderrWrite = process.stderr.write.bind(process.stderr);\n\n afterEach(() => {\n process.stderr.write = stderrWrite;\n });\n\n it(\"queries recent events from the default in-memory sink\", async () => {\n const store = new EventStore(\"session-test\");\n\n await store.emit(\n new FlowEvent({\n eventType: \"StagehandExtractEvent\",\n sessionId: \"session-test\",\n eventId: \"stagehand-1234\",\n eventCreatedAt: \"2026-03-16T21:45:00.000Z\",\n data: { params: [\"grab title\"] },\n }),\n );\n\n const events = await store.query({});\n expect(events).toHaveLength(1);\n expect(events[0].eventType).toBe(\"StagehandExtractEvent\");\n\n await store.destroy();\n });\n\n it(\"drops payloads from the default in-memory sink\", async () => {\n const store = new EventStore(\"session-test\");\n\n await store.emit(\n new FlowEvent({\n eventType: \"LlmRequestEvent\",\n sessionId: \"session-test\",\n eventId: \"llm-1234\",\n eventCreatedAt: \"2026-03-16T21:45:00.000Z\",\n data: {\n prompt: [{ type: \"image_url\", image_url: { url: \"huge\" } }],\n output: \"huge\",\n },\n }),\n );\n\n const [event] = await store.query({});\n expect(event.eventType).toBe(\"LlmRequestEvent\");\n expect(event.eventId).toBe(\"llm-1234\");\n expect(event.data).toEqual({});\n\n await store.destroy();\n });\n\n it(\"renders semantic hierarchy tags for non-cdp stderr events only\", async () => {\n // Intercept stderr so the pretty sink can be asserted without polluting the\n // real test runner output.\n const { writes, store, bus, detachBus } = createVerboseStoreHarness();\n\n const stepEvent = new FlowEvent({\n eventType: \"StagehandExtractEvent\",\n sessionId: \"session-test\",\n eventId: \"stagehand-1234\",\n eventCreatedAt: \"2026-03-16T21:45:00.000Z\",\n data: { params: [\"grab title\"] },\n });\n const cdpEvent = new FlowEvent({\n eventType: \"CdpCallEvent\",\n sessionId: \"session-test\",\n eventId: \"cdp-call-5678\",\n eventCreatedAt: \"2026-03-16T21:45:00.100Z\",\n eventParentIds: [stepEvent.eventId],\n data: {\n method: \"Runtime.evaluate\",\n params: { expression: \"2 + 2\" },\n targetId: \"1234567890ABCDEF1234567890ABCDEF\",\n },\n });\n\n // The stderr sink intentionally suppresses CDP noise even though the event\n // still exists for in-memory and file-backed sinks.\n bus.emit(stepEvent.eventType, stepEvent);\n bus.emit(cdpEvent.eventType, cdpEvent);\n await new Promise((resolve) => setTimeout(resolve, 0));\n\n expect(writes).toHaveLength(1);\n expect(writes[0]).toContain(\"[🆂 #1234 EXTRACT]\");\n expect(writes[0]).toContain(\"Stagehand.extract\");\n expect(writes[0]).not.toContain(\"Runtime.evaluate\");\n\n detachBus();\n await store.destroy();\n });\n\n it(\"renders generic stagehand events without crashing the stderr sink\", async () => {\n const { writes, store, bus, detachBus } = createVerboseStoreHarness();\n\n // `StagehandEvent` has no action suffix, so this guards the formatter path\n // that cannot assume a method name exists.\n bus.emit(\n \"StagehandEvent\",\n new FlowEvent({\n eventType: \"StagehandEvent\",\n sessionId: \"session-test\",\n eventId: \"stagehand-0001\",\n eventCreatedAt: \"2026-03-16T21:45:00.000Z\",\n data: { params: [\"noop\"] },\n }),\n );\n await new Promise((resolve) => setTimeout(resolve, 0));\n\n expect(writes).toHaveLength(1);\n expect(writes[0]).toContain(\"[🆂 #0001\");\n expect(writes[0]).toContain(\"Stagehand(\");\n\n detachBus();\n await store.destroy();\n });\n\n it(\"colorizes pretty stderr output with ansi escapes when enabled\", async () => {\n const previousForceColor = process.env.FORCE_COLOR;\n const previousNoColor = process.env.NO_COLOR;\n delete process.env.NO_COLOR;\n process.env.FORCE_COLOR = \"1\";\n\n const { writes, store, bus, detachBus } = createVerboseStoreHarness();\n\n try {\n bus.emit(\n \"StagehandActEvent\",\n new FlowEvent({\n eventType: \"StagehandActEvent\",\n sessionId: \"session-test\",\n eventId: \"stagehand-0002\",\n eventCreatedAt: \"2026-03-16T21:45:00.000Z\",\n data: { params: [\"click submit\"] },\n }),\n );\n await new Promise((resolve) => setTimeout(resolve, 0));\n\n expect(writes).toHaveLength(1);\n expect(writes[0]).toContain(\"\\u001B[\");\n } finally {\n if (previousNoColor === undefined) {\n delete process.env.NO_COLOR;\n } else {\n process.env.NO_COLOR = previousNoColor;\n }\n\n if (previousForceColor === undefined) {\n delete process.env.FORCE_COLOR;\n } else {\n process.env.FORCE_COLOR = previousForceColor;\n }\n\n detachBus();\n await store.destroy();\n }\n });\n\n it(\"keeps agent ancestry and start ids for completion events after many child events\", async () => {\n const { writes, store, bus, detachBus } = createVerboseStoreHarness();\n\n const agentEvent = new FlowEvent({\n eventType: \"AgentExecuteEvent\",\n sessionId: \"session-test\",\n eventId: \"agent-1234\",\n eventCreatedAt: \"2026-03-16T21:45:00.000Z\",\n data: { params: [{ instruction: \"click the button\" }] },\n });\n const actEvent = new FlowEvent({\n eventType: \"StagehandActEvent\",\n sessionId: \"session-test\",\n eventId: \"stagehand-2222\",\n eventCreatedAt: \"2026-03-16T21:45:00.001Z\",\n eventParentIds: [agentEvent.eventId],\n data: { params: [\"click the button\"] },\n });\n const clickEvent = new FlowEvent({\n eventType: \"UnderstudyClickEvent\",\n sessionId: \"session-test\",\n eventId: \"action-3333\",\n eventCreatedAt: \"2026-03-16T21:45:00.002Z\",\n eventParentIds: [agentEvent.eventId, actEvent.eventId],\n data: { target: \"xpath=/button[1]\" },\n });\n\n bus.emit(agentEvent.eventType, agentEvent);\n bus.emit(actEvent.eventType, actEvent);\n bus.emit(clickEvent.eventType, clickEvent);\n\n // Flood the retained history with child events so the completion lines have\n // to recover their displayed ancestry from the queryable sink.\n for (let index = 0; index < 150; index += 1) {\n bus.emit(\n \"CdpCallEvent\",\n new FlowEvent({\n eventType: \"CdpCallEvent\",\n sessionId: \"session-test\",\n eventId: `cdp-${String(index).padStart(4, \"0\")}`,\n eventCreatedAt: `2026-03-16T21:45:00.${String(index + 10).padStart(3, \"0\")}Z`,\n eventParentIds: [\n agentEvent.eventId,\n actEvent.eventId,\n clickEvent.eventId,\n ],\n data: {\n method: \"Runtime.evaluate\",\n params: { expression: `${index}` },\n targetId: \"1234567890ABCDEF1234567890ABCDEF\",\n },\n }),\n );\n }\n\n bus.emit(\n \"UnderstudyClickCompletedEvent\",\n new FlowEvent({\n eventType: \"UnderstudyClickCompletedEvent\",\n sessionId: \"session-test\",\n eventId: \"done-4444\",\n eventCreatedAt: \"2026-03-16T21:45:01.000Z\",\n eventParentIds: [\n agentEvent.eventId,\n actEvent.eventId,\n clickEvent.eventId,\n ],\n data: { durationMs: 250 },\n }),\n );\n bus.emit(\n \"StagehandActCompletedEvent\",\n new FlowEvent({\n eventType: \"StagehandActCompletedEvent\",\n sessionId: \"session-test\",\n eventId: \"done-5555\",\n eventCreatedAt: \"2026-03-16T21:45:01.001Z\",\n eventParentIds: [agentEvent.eventId, actEvent.eventId],\n data: { durationMs: 500 },\n }),\n );\n bus.emit(\n \"AgentExecuteCompletedEvent\",\n new FlowEvent({\n eventType: \"AgentExecuteCompletedEvent\",\n sessionId: \"session-test\",\n eventId: \"done-6666\",\n eventCreatedAt: \"2026-03-16T21:45:01.002Z\",\n eventParentIds: [agentEvent.eventId],\n data: { durationMs: 750 },\n }),\n );\n await new Promise((resolve) => setTimeout(resolve, 0));\n\n // Completion lines should reference the original started-event ids, not the\n // synthetic completed-event ids emitted at the end of the lifecycle.\n const clickCompletedLine = writes.find((line) =>\n line.includes(\"CLICK completed\"),\n );\n const actCompletedLine = writes.find((line) =>\n line.includes(\"ACT completed\"),\n );\n const agentCompletedLine = writes.find((line) =>\n line.includes(\"Agent.execute() completed\"),\n );\n\n expect(clickCompletedLine).toContain(\"[🅰 #1234]\");\n expect(clickCompletedLine).toContain(\"[🆂 #2222 ACT]\");\n expect(clickCompletedLine).toContain(\"[🆄 #3333 CLICK]\");\n expect(clickCompletedLine).not.toContain(\"#4444\");\n\n expect(actCompletedLine).toContain(\"[🅰 #1234]\");\n expect(actCompletedLine).toContain(\"[🆂 #2222 ACT]\");\n expect(actCompletedLine).not.toContain(\"#5555\");\n\n expect(agentCompletedLine).toContain(\"[🅰 #1234]\");\n expect(agentCompletedLine).not.toContain(\"#6666\");\n\n detachBus();\n await store.destroy();\n });\n});\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@browserbasehq/orca",
3
- "version": "3.2.0-preview.3",
3
+ "version": "3.2.0-preview.4",
4
4
  "description": "An AI web browsing framework focused on simplicity and extensibility.",
5
5
  "type": "module",
6
6
  "main": "./dist/cjs/index.js",
@@ -71,6 +71,7 @@
71
71
  "@anthropic-ai/sdk": "0.39.0",
72
72
  "@browserbasehq/sdk": "^2.7.0",
73
73
  "@google/genai": "^1.22.0",
74
+ "@langchain/openai": "^0.4.4",
74
75
  "@modelcontextprotocol/sdk": "^1.17.2",
75
76
  "ai": "^5.0.133",
76
77
  "devtools-protocol": "^0.0.1464554",
@@ -96,6 +97,7 @@
96
97
  "@ai-sdk/perplexity": "^2.0.13",
97
98
  "@ai-sdk/togetherai": "^1.0.23",
98
99
  "@ai-sdk/xai": "^2.0.26",
100
+ "@langchain/core": "^0.3.80",
99
101
  "bufferutil": "^4.0.9",
100
102
  "chrome-launcher": "^1.2.0",
101
103
  "ollama-ai-provider-v2": "^1.5.0",
@@ -1,139 +0,0 @@
1
- import fs from "node:fs";
2
- import pino from "pino";
3
- import type { LanguageModelMiddleware } from "ai";
4
- import type { V3Options } from "./types/public/index.js";
5
- interface FlowLoggerMetrics {
6
- taskStartTime?: number;
7
- stepStartTime?: number;
8
- actionStartTime?: number;
9
- llmRequests: number;
10
- llmInputTokens: number;
11
- llmOutputTokens: number;
12
- cdpEvents: number;
13
- }
14
- export interface FlowLoggerContext {
15
- logger: pino.Logger;
16
- metrics: FlowLoggerMetrics;
17
- sessionId: string;
18
- sessionDir: string;
19
- configDir: string;
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
- };
35
- }
36
- /**
37
- * Get the config directory. Returns empty string if logging is disabled.
38
- */
39
- export declare function getConfigDir(): string;
40
- /**
41
- * Format a prompt preview from LLM messages for logging.
42
- * Returns format like: "some text... +{5.8kb image} +{schema} +{12 tools}"
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 {
59
- /**
60
- * 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
- */
75
- static logAgentTaskStarted({ invocation, args, }: {
76
- invocation: string;
77
- args?: unknown | unknown[];
78
- }): void;
79
- /**
80
- * Log task completion with metrics summary.
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;
97
- private static logCdpEvent;
98
- static logCdpCallEvent(data: {
99
- method: string;
100
- params?: object;
101
- targetId?: string | null;
102
- }, ctx?: FlowLoggerContext | null): void;
103
- static logCdpMessageEvent(data: {
104
- method: string;
105
- params?: unknown;
106
- targetId?: string | null;
107
- }, ctx?: FlowLoggerContext | null): void;
108
- static logLlmRequest({ requestId, model, prompt, }: {
109
- requestId: string;
110
- model: string;
111
- operation: string;
112
- prompt?: string;
113
- }, explicitCtx?: FlowLoggerContext | null): void;
114
- static logLlmResponse({ requestId, model, output, inputTokens, outputTokens, }: {
115
- requestId: string;
116
- model: string;
117
- operation: string;
118
- output?: string;
119
- inputTokens?: number;
120
- outputTokens?: number;
121
- }, explicitCtx?: FlowLoggerContext | null): void;
122
- /**
123
- * Create middleware for wrapping language models with LLM call logging.
124
- * Returns a no-op middleware when logging is disabled.
125
- */
126
- static createLlmLoggingMiddleware(modelId: string): Pick<LanguageModelMiddleware, "wrapGenerate">;
127
- }
128
- /**
129
- * Method decorator for logging understudy actions with automatic start/complete.
130
- * Logs all arguments automatically. No-op when CONFIG_DIR is empty.
131
- */
132
- export declare function logAction(actionType: string): <T extends (...args: never[]) => Promise<unknown>>(originalMethod: T) => T;
133
- /**
134
- * Method decorator for logging Stagehand step events (act, extract, observe).
135
- * Only adds logging - does NOT wrap with withInstanceLogContext (caller handles that).
136
- * No-op when CONFIG_DIR is empty.
137
- */
138
- export declare function logStagehandStep(invocation: string, label: string): <T extends (...args: never[]) => Promise<unknown>>(originalMethod: T) => T;
139
- export {};