agents 0.30.1 → 0.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/README.md +2 -1
  2. package/dist/{agent-routing-CDbpVjYq.d.ts → agent-routing-wS1TimZ_.d.ts} +64 -603
  3. package/dist/agent-routing.d.ts +1 -1
  4. package/dist/agent-tool-types.d.ts +1 -1
  5. package/dist/{agent-tools-C8DH8Yii.d.ts → agent-tools-Bamxxb6Y.d.ts} +2 -2
  6. package/dist/agent-tools.d.ts +1 -1
  7. package/dist/{ai-iXw0uOGj.d.ts → ai-CDn3Abax.d.ts} +30 -4
  8. package/dist/{ai-sdk-DRPh2rRa.js → ai-sdk-Kon40i0q.js} +2 -36
  9. package/dist/ai-sdk-Kon40i0q.js.map +1 -0
  10. package/dist/ai-sdk-hW3vntnk.d.ts +72 -0
  11. package/dist/browser/ai.d.ts +1 -1
  12. package/dist/browser/ai.js +16 -3
  13. package/dist/browser/ai.js.map +1 -1
  14. package/dist/browser/index.d.ts +64 -16
  15. package/dist/browser/index.js +4 -4
  16. package/dist/browser/tools/ai-sdk.d.ts +7 -70
  17. package/dist/browser/tools/ai-sdk.js +4 -4
  18. package/dist/browser/tools/ai-sdk.js.map +1 -1
  19. package/dist/browser/tools/pi.d.ts +9 -15
  20. package/dist/browser/tools/pi.js +6 -14
  21. package/dist/browser/tools/pi.js.map +1 -1
  22. package/dist/browser/tools/tanstack-ai.d.ts +46 -23
  23. package/dist/browser/tools/tanstack-ai.js +8 -4
  24. package/dist/browser/tools/tanstack-ai.js.map +1 -1
  25. package/dist/{browser-DccPw_wW.js → browser-1eUbPvC2.js} +413 -14
  26. package/dist/browser-1eUbPvC2.js.map +1 -0
  27. package/dist/{browser-DlXhSAdf.d.ts → browser-D9RNpJuT.d.ts} +254 -20
  28. package/dist/browser-tool-BhjCcNVE.d.ts +71 -0
  29. package/dist/browser-tool-lGnvEBLJ.js +497 -0
  30. package/dist/browser-tool-lGnvEBLJ.js.map +1 -0
  31. package/dist/capability-id-B3J8Nok_.js +13 -0
  32. package/dist/capability-id-B3J8Nok_.js.map +1 -0
  33. package/dist/chat/index.d.ts +2 -2
  34. package/dist/chat-sdk/index.d.ts +3 -3
  35. package/dist/chat-sdk/index.js +1 -1
  36. package/dist/client-4OlMIJx-.js.map +1 -1
  37. package/dist/{client-BnYbNT3z.js → client-DMWujQJ1.js} +68 -244
  38. package/dist/client-DMWujQJ1.js.map +1 -0
  39. package/dist/{client-C27CtRZr.d.ts → client-wn4-yqGz.d.ts} +9 -7
  40. package/dist/client.d.ts +1 -1
  41. package/dist/{connector-DAXBOIIi.js → connector-CM-uuxKM.js} +96 -8
  42. package/dist/connector-CM-uuxKM.js.map +1 -0
  43. package/dist/{connector-20DJ6p4k.d.ts → connector-DZ71EjE-.d.ts} +109 -9
  44. package/dist/experimental/webmcp.js +1 -1
  45. package/dist/{handler-stateless-Bly_nSH3.js → handler-stateless-B5hU3dxK.js} +35 -2
  46. package/dist/handler-stateless-B5hU3dxK.js.map +1 -0
  47. package/dist/{handler-stateless-DxYpJ_XF.d.ts → handler-stateless-C90kD5_R.d.ts} +3 -47
  48. package/dist/harness/container/index.d.ts +15 -15
  49. package/dist/harness/opencode/index.js.map +1 -1
  50. package/dist/harness/pi/index.d.ts +4 -3
  51. package/dist/harness/pi/index.js +31 -10
  52. package/dist/harness/pi/index.js.map +1 -1
  53. package/dist/harness/think/index.d.ts +2 -1
  54. package/dist/{images-xaDv2Fqe.js → images-CfuRCjwq.js} +1 -5
  55. package/dist/images-CfuRCjwq.js.map +1 -0
  56. package/dist/{index-DCxk3OSJ.d.ts → index-8k4qsX1T.d.ts} +2 -28
  57. package/dist/index.d.ts +14 -14
  58. package/dist/index.js +2 -2
  59. package/dist/internal-hosts-Kfp5A392.d.ts +230 -0
  60. package/dist/internal-kmw70xwR.js.map +1 -1
  61. package/dist/invoker-BC1SZ3q1.js +26 -0
  62. package/dist/invoker-BC1SZ3q1.js.map +1 -0
  63. package/dist/invoker-DoLFPJZV.d.ts +21 -0
  64. package/dist/mcp/client/index.d.ts +15 -1
  65. package/dist/mcp/client/index.js +2 -2
  66. package/dist/mcp/client/x402.d.ts +7 -5
  67. package/dist/mcp/client/x402.js +34 -1
  68. package/dist/mcp/client/x402.js.map +1 -1
  69. package/dist/mcp/index.d.ts +561 -27
  70. package/dist/mcp/index.js +180 -3
  71. package/dist/mcp/index.js.map +1 -1
  72. package/dist/mcp/server/index.d.ts +1 -1
  73. package/dist/mcp/server/index.js +1 -1
  74. package/dist/models/ai-sdk/index.d.ts +2 -2
  75. package/dist/models/ai-sdk/index.js +1 -1
  76. package/dist/models/opencode/index.d.ts +2 -2
  77. package/dist/models/opencode/index.js +1 -1
  78. package/dist/models/pi-ai/index.d.ts +3 -28
  79. package/dist/models/pi-ai/index.js +31 -16
  80. package/dist/models/pi-ai/index.js.map +1 -1
  81. package/dist/protocol-BEgrJYC5.d.ts +29 -29
  82. package/dist/react.d.ts +2 -2
  83. package/dist/routing/index.d.ts +1 -1
  84. package/dist/serializable.d.ts +1 -1
  85. package/dist/{session-store-yvwq1f9x.js → session-7CDgVE0z.js} +455 -33
  86. package/dist/session-7CDgVE0z.js.map +1 -0
  87. package/dist/{session-store-_IK6dV-w.d.ts → session-store-B7Ca-u1t.d.ts} +8 -1
  88. package/dist/settings-Dk2il2Hf.js.map +1 -1
  89. package/dist/{src-DfLzdwlK.js → src-BGolXG_H.js} +18 -2
  90. package/dist/src-BGolXG_H.js.map +1 -0
  91. package/dist/sub-routing.d.ts +12 -12
  92. package/dist/tool-CTp72Jb_.d.ts +10 -10
  93. package/dist/tool-DoVberpN.d.ts +22 -22
  94. package/dist/tool-helpers-BodWi4gd.js +256 -0
  95. package/dist/tool-helpers-BodWi4gd.js.map +1 -0
  96. package/dist/{transport-CPh7YGiw.d.ts → transport-5moD2pW5.d.ts} +1 -43
  97. package/dist/types-D2naO3rA.d.ts +49 -0
  98. package/dist/voice/index.d.ts +1 -1
  99. package/dist/workflow-types.d.ts +1 -1
  100. package/dist/workflows.d.ts +1 -1
  101. package/dist/workflows.js +1 -1
  102. package/docs/browse-the-web.md +247 -413
  103. package/docs/harnesses/pi.md +27 -27
  104. package/docs/index.md +4 -4
  105. package/docs/mcp-client.md +2 -0
  106. package/docs/mcp-servers.md +25 -6
  107. package/docs/models-pi-ai.md +9 -11
  108. package/docs/models.md +1 -8
  109. package/docs/securing-mcp-servers.md +113 -302
  110. package/package.json +8 -3
  111. package/dist/ai-sdk-DRPh2rRa.js.map +0 -1
  112. package/dist/browser-DccPw_wW.js.map +0 -1
  113. package/dist/browser-tool-B1mhifin.js +0 -616
  114. package/dist/browser-tool-B1mhifin.js.map +0 -1
  115. package/dist/browser-tool-Cxjk5sgG.d.ts +0 -92
  116. package/dist/client-BnYbNT3z.js.map +0 -1
  117. package/dist/connector-DAXBOIIi.js.map +0 -1
  118. package/dist/handler-stateless-Bly_nSH3.js.map +0 -1
  119. package/dist/images-xaDv2Fqe.js.map +0 -1
  120. package/dist/invoker-CG0_p_Wq.d.ts +0 -20
  121. package/dist/invoker-CHMnoxIA.js +0 -57
  122. package/dist/invoker-CHMnoxIA.js.map +0 -1
  123. package/dist/session-store-yvwq1f9x.js.map +0 -1
  124. package/dist/src-DfLzdwlK.js.map +0 -1
  125. package/dist/tool-helpers-O5BDVEAY.js +0 -58
  126. package/dist/tool-helpers-O5BDVEAY.js.map +0 -1
@@ -109,35 +109,35 @@ type ContainerMessage = {
109
109
  };
110
110
  /** What an adapter reports while it runs. */
111
111
  type ContainerEvent =
112
- /** Live text for an assistant message that is still being written. */ | {
113
- readonly type: "text-delta";
114
- readonly messageId: string;
115
- readonly delta: string;
116
- } /** Live reasoning for an assistant message that is still being written. */
117
- | {
118
- readonly type: "reasoning-delta";
119
- readonly messageId: string;
120
- readonly delta: string;
121
- } /** A finished or updated transcript message. Stored. */
122
- | {
123
- readonly type: "message";
124
- readonly message: ContainerMessage;
125
- } /** Token and cost figures the adapter reports, as the adapter counts them. */
126
- | {
127
- readonly type: "usage";
128
- readonly inputTokens?: number;
129
- readonly outputTokens?: number;
130
- readonly costUsd?: number;
131
- } /** A diagnostic line. */
132
- | {
133
- readonly type: "log";
134
- readonly level: "info" | "warn" | "error";
135
- readonly message: string;
136
- } /** Anything adapter-specific, passed through untouched. */
137
- | {
138
- readonly type: "raw";
139
- readonly value: JsonValue;
140
- };
112
+ | /** Live text for an assistant message that is still being written. */ {
113
+ readonly type: "text-delta";
114
+ readonly messageId: string;
115
+ readonly delta: string;
116
+ } /** Live reasoning for an assistant message that is still being written. */
117
+ | {
118
+ readonly type: "reasoning-delta";
119
+ readonly messageId: string;
120
+ readonly delta: string;
121
+ } /** A finished or updated transcript message. Stored. */
122
+ | {
123
+ readonly type: "message";
124
+ readonly message: ContainerMessage;
125
+ } /** Token and cost figures the adapter reports, as the adapter counts them. */
126
+ | {
127
+ readonly type: "usage";
128
+ readonly inputTokens?: number;
129
+ readonly outputTokens?: number;
130
+ readonly costUsd?: number;
131
+ } /** A diagnostic line. */
132
+ | {
133
+ readonly type: "log";
134
+ readonly level: "info" | "warn" | "error";
135
+ readonly message: string;
136
+ } /** Anything adapter-specific, passed through untouched. */
137
+ | {
138
+ readonly type: "raw";
139
+ readonly value: JsonValue;
140
+ };
141
141
  /** How an operation ended, as the daemon reports it. */
142
142
  type ContainerOutcome =
143
143
  | {
package/dist/react.d.ts CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  C as MCPServersState,
3
3
  J as AgentToolRunPart,
4
4
  Y as AgentToolRunState
5
- } from "./agent-routing-CDbpVjYq.js";
5
+ } from "./agent-routing-wS1TimZ_.js";
6
6
  import { ClientParameters } from "./serializable.js";
7
7
  import { t as AgentTransport } from "./transport-protocol-ZTew5Wso.js";
8
8
  import {
@@ -15,7 +15,7 @@ import {
15
15
  p as RequiredAgentMethods,
16
16
  s as AgentStub,
17
17
  v as createStubProxy
18
- } from "./client-C27CtRZr.js";
18
+ } from "./client-wn4-yqGz.js";
19
19
  import { PartySocket } from "partysocket";
20
20
  import { usePartySocket } from "partysocket/react";
21
21
 
@@ -10,7 +10,7 @@ import {
10
10
  n as AgentOptions,
11
11
  r as RoutingRetryOptions,
12
12
  t as AgentGetOptions
13
- } from "../agent-routing-CDbpVjYq.js";
13
+ } from "../agent-routing-wS1TimZ_.js";
14
14
 
15
15
  //#region src/routing/routed-agents.d.ts
16
16
  /** A public entry in an {@link RoutedAgents}. */
@@ -1,4 +1,4 @@
1
- import { k as StreamingResponse } from "./agent-routing-CDbpVjYq.js";
1
+ import { k as StreamingResponse } from "./agent-routing-wS1TimZ_.js";
2
2
 
3
3
  //#region src/serializable.d.ts
4
4
  type SerializablePrimitive = undefined | null | string | number | boolean;
@@ -303,19 +303,29 @@ function isUnimplementedBindingMethod(error, method) {
303
303
  * `acquire()`, as in fully local dev.
304
304
  */
305
305
  async function acquireBrowserSession(browser, options = {}) {
306
+ const { outboundByHost, ...httpOptions } = options;
306
307
  if (browser.acquire) try {
307
308
  const { sessionId } = await browser.acquire({
308
309
  keepAlive: options.keepAliveMs,
309
310
  recording: options.recording,
310
- guardrails: options.guardrails
311
+ guardrails: options.guardrails,
312
+ ...outboundByHost ? { outboundByHost } : {}
311
313
  });
312
314
  return { sessionId };
313
315
  } catch (error) {
314
316
  if (!isUnimplementedBindingMethod(error, "acquire")) throw error;
315
317
  }
316
- const { sessionId } = await createBrowserSession(browser, options);
318
+ if (outboundByHost) warnInternalHostsUnavailable(Object.keys(outboundByHost));
319
+ const { sessionId } = await createBrowserSession(browser, httpOptions);
317
320
  return { sessionId };
318
321
  }
322
+ let warnedInternalHostsUnavailable = false;
323
+ /** Say once per isolate that internal hostnames need a deployed Worker. */
324
+ function warnInternalHostsUnavailable(hosts) {
325
+ if (warnedInternalHostsUnavailable) return;
326
+ warnedInternalHostsUnavailable = true;
327
+ console.warn(`[agents/browser] Internal hostnames (${hosts.join(", ")}) only work once deployed: this Browser Run binding has no acquire(), as in local dev, so the browser starts without them.`);
328
+ }
319
329
  /**
320
330
  * The HTTP status in a typed binding method's error. Browser Run's binding
321
331
  * errors carry it only in the message, e.g. `Not Found (status=404)`.
@@ -409,35 +419,6 @@ async function connectBrowserSession(browser, sessionId, options) {
409
419
  });
410
420
  }
411
421
  //#endregion
412
- //#region src/browser/connector-validation.ts
413
- function formatToolValidationError(connector, tool, errors) {
414
- const specific = errors.filter((error) => error.keyword !== "properties");
415
- return `Invalid arguments for ${connector}.${tool}${(specific.length > 0 ? specific : errors).map((error) => {
416
- const location = error.instanceLocation.replace(/^#\/?/, "").replaceAll("~1", "/").replaceAll("~0", "~").replaceAll("/", ".");
417
- return `${location ? ` at ${location}` : ""}: ${error.error}`;
418
- }).join(";")}`;
419
- }
420
- /**
421
- * Validate a connector tool's arguments against its input schema before it
422
- * runs, so the model gets a precise error instead of a failure deep inside
423
- * browser work. An omitted argument counts as `{}`: argumentless tools are
424
- * documented as `cdp.spec()`.
425
- */
426
- function validateConnectorArgs(connector, name, tool) {
427
- if (!tool.inputSchema) return tool;
428
- const schema = tool.inputSchema;
429
- const validator = new Validator(schema, "7", false);
430
- return {
431
- ...tool,
432
- execute: async (args, ctx) => {
433
- const input = args === void 0 ? {} : args;
434
- const result = validator.validate(input);
435
- if (!result.valid) throw new Error(formatToolValidationError(connector, name, result.errors));
436
- return await tool.execute(input, ctx);
437
- }
438
- };
439
- }
440
- //#endregion
441
422
  //#region src/browser/live-view.ts
442
423
  /**
443
424
  * Browser Run mints `devtoolsFrontendUrl`s (the Live View links) that are
@@ -654,6 +635,447 @@ var _queues = { _: /* @__PURE__ */ new WeakMap() };
654
635
  */
655
636
  const DEFAULT_SWEEP_IDLE_MS = 600 * 1e3;
656
637
  //#endregion
657
- export { connectUrl as S, listBrowserTargets as _, applyLiveViewMode as a, CdpProtocolError as b, BrowserRenderingError as c, connectBrowser as d, connectBrowserSession as f, isMissingBrowserSession as g, getBrowserRecording as h, LIVE_VIEW_URL_TTL_MS as i, acquireBrowserSession as l, deleteBrowserSession as m, DurableBrowserSessionStore as n, createLiveView as o, createBrowserSession as p, loadCdpSpec as r, validateConnectorArgs as s, DEFAULT_SWEEP_IDLE_MS as t, closeBrowserSession as u, CDP_METHOD_NOT_FOUND as v, CdpSession as x, CdpConnection as y };
638
+ //#region src/browser/session.ts
639
+ /**
640
+ * `BrowserSession`: one run's connection to a persistent `Browser`, with the
641
+ * rules that make CDP usable from model-written code.
642
+ *
643
+ * The model never manages CDP sessions. `sessionId: "active"` addresses the
644
+ * tab the scope last worked in, `attachToTarget` returns a handle that keeps
645
+ * working in later runs, and common protocol mistakes come back as
646
+ * instructions. When the session closes it saves the scope's active tab and
647
+ * reports what happened to the browser: a restart, a tab closed by someone
648
+ * else, a tab shared with another scope, tabs the page opened.
649
+ *
650
+ * `browserTool` opens one per run.
651
+ */
652
+ /** `sessionId` value that addresses the tab the agent is working in. */
653
+ const ACTIVE_PAGE_SESSION = "active";
654
+ /**
655
+ * `attachToTarget` returns `{ sessionId: "target:<targetId>" }`, a stable
656
+ * handle rather than a connection-scoped CDP session id, so it keeps working
657
+ * in later runs. `send` resolves it on the live socket.
658
+ */
659
+ const ATTACH_HANDLE_PREFIX = "target:";
660
+ /** Chrome's JSON-RPC code for a CDP session id it doesn't know. */
661
+ const CDP_SESSION_NOT_FOUND = -32001;
662
+ /**
663
+ * Screenshots are kept whole in the chat message for the UI, and a stored
664
+ * message must fit SQLite's 2 MB row (see `ROW_MAX_BYTES` in chat/sanitize.ts),
665
+ * or the image is compacted away. Failing early lets the model retake it
666
+ * smaller. Other results are cut to a preview before they're stored.
667
+ *
668
+ * @internal The tools also refuse to keep a returned screenshot over it.
669
+ */
670
+ const DEFAULT_MAX_RESULT_BYTES = 1e6;
671
+ /** `#liveParams`: nothing to detach. */
672
+ const DETACHED = Symbol("detached");
673
+ const MANAGED_BROWSER = "this browser is managed for you and persists between runs. To close a tab, send Target.closeTarget with its targetId.";
674
+ const HOST_ONLY = "it is for the host, not your code.";
675
+ const NO_TUNNELING = "send each command with browser.cdp instead, passing sessionId to reach a tab.";
676
+ /**
677
+ * Commands model code can't send, and why.
678
+ *
679
+ * - Ending the browser: the host owns its lifetime, so the model can't close
680
+ * it out from under the agent (and lose its logins).
681
+ * - Live View and handoff: a Live View link controls the whole browser, so it
682
+ * goes to a trusted person through `Browser.liveView()`, never to the model.
683
+ * - Tunnels: these carry raw protocol messages past this check.
684
+ */
685
+ const REFUSED_COMMANDS = /* @__PURE__ */ new Map([
686
+ ["Browser.close", MANAGED_BROWSER],
687
+ ["Browser.crash", MANAGED_BROWSER],
688
+ ["Browser.crashGpuProcess", MANAGED_BROWSER],
689
+ ["Cloudflare.getLiveView", HOST_ONLY],
690
+ ["Cloudflare.handoff", HOST_ONLY],
691
+ ["Target.sendMessageToTarget", NO_TUNNELING],
692
+ ["Target.exposeDevToolsProtocol", NO_TUNNELING]
693
+ ]);
694
+ const SEND_SCHEMA = {
695
+ type: "object",
696
+ properties: {
697
+ method: {
698
+ type: "string",
699
+ minLength: 1
700
+ },
701
+ params: { type: "object" },
702
+ sessionId: { type: "string" },
703
+ timeoutMs: {
704
+ type: "number",
705
+ exclusiveMinimum: 0
706
+ }
707
+ },
708
+ required: ["method"]
709
+ };
710
+ const ATTACH_SCHEMA = {
711
+ type: "object",
712
+ properties: {
713
+ targetId: {
714
+ type: "string",
715
+ minLength: 1
716
+ },
717
+ timeoutMs: {
718
+ type: "number",
719
+ exclusiveMinimum: 0
720
+ }
721
+ },
722
+ required: ["targetId"]
723
+ };
724
+ const DEBUG_LOG_SCHEMA = {
725
+ type: "object",
726
+ properties: { limit: {
727
+ type: "number",
728
+ minimum: 1
729
+ } }
730
+ };
731
+ var _browser = /* @__PURE__ */ new WeakMap();
732
+ var _scope = /* @__PURE__ */ new WeakMap();
733
+ var _maxResultBytes = /* @__PURE__ */ new WeakMap();
734
+ var _state = /* @__PURE__ */ new WeakMap();
735
+ var _connecting = /* @__PURE__ */ new WeakMap();
736
+ var _closed = /* @__PURE__ */ new WeakMap();
737
+ var _BrowserSession_brand = /* @__PURE__ */ new WeakSet();
738
+ /**
739
+ * One run's connection to a persistent browser, for one scope.
740
+ *
741
+ * It connects on its first call and stays connected until {@link close}.
742
+ * Concurrent first calls share one connect. Every method takes one options
743
+ * object, validated before anything touches the browser, because the input
744
+ * usually comes from model-written code.
745
+ *
746
+ * Create one per run with `browser.session({ scope })`, and close it when
747
+ * the run ends. The browser itself stays open.
748
+ *
749
+ * @experimental The API surface may change before stabilizing.
750
+ */
751
+ var BrowserSession = class {
752
+ constructor(browser, options = {}) {
753
+ _classPrivateMethodInitSpec(this, _BrowserSession_brand);
754
+ _classPrivateFieldInitSpec(this, _browser, void 0);
755
+ _classPrivateFieldInitSpec(this, _scope, void 0);
756
+ _classPrivateFieldInitSpec(this, _maxResultBytes, void 0);
757
+ _classPrivateFieldInitSpec(this, _state, void 0);
758
+ _classPrivateFieldInitSpec(this, _connecting, void 0);
759
+ _classPrivateFieldInitSpec(this, _closed, false);
760
+ _classPrivateFieldSet2(_browser, this, browser);
761
+ _classPrivateFieldSet2(_scope, this, options.scope);
762
+ _classPrivateFieldSet2(_maxResultBytes, this, options.maxResultBytes ?? 1e6);
763
+ }
764
+ /**
765
+ * Send a CDP command and resolve with its result, without the JSON-RPC
766
+ * envelope. `sessionId: "active"` runs it in the scope's tab.
767
+ */
768
+ async send(input) {
769
+ const { method, params, sessionId, timeoutMs } = validate("browser.cdp", SEND_SCHEMA, input);
770
+ const refused = REFUSED_COMMANDS.get(method);
771
+ if (refused) throw new Error(`${method} is not available: ${refused}`);
772
+ const state = await _assertClassBrand(_BrowserSession_brand, this, _connect).call(this);
773
+ const live = await _assertClassBrand(_BrowserSession_brand, this, _resolveSessionId).call(this, state, sessionId);
774
+ const liveParams = _assertClassBrand(_BrowserSession_brand, this, _liveParams).call(this, state, method, params);
775
+ if (liveParams === DETACHED) return {};
776
+ let result;
777
+ try {
778
+ result = await state.connected.cdp.send(method, liveParams, {
779
+ sessionId: live,
780
+ timeoutMs
781
+ });
782
+ } catch (error) {
783
+ throw await _assertClassBrand(_BrowserSession_brand, this, _teach).call(this, state, error, method, sessionId);
784
+ }
785
+ _assertClassBrand(_BrowserSession_brand, this, _observe).call(this, state, method, liveParams, result);
786
+ if (method === "Page.captureScreenshot") _assertClassBrand(_BrowserSession_brand, this, _assertFits).call(this, result);
787
+ return result;
788
+ }
789
+ /**
790
+ * Make an open tab the scope's active tab, and resolve with a `sessionId`
791
+ * handle for it that keeps working in later runs.
792
+ */
793
+ async attachToTarget(input) {
794
+ const { targetId, timeoutMs } = validate("browser.attachToTarget", ATTACH_SCHEMA, input);
795
+ const state = await _assertClassBrand(_BrowserSession_brand, this, _connect).call(this);
796
+ const target = targetId;
797
+ await _assertClassBrand(_BrowserSession_brand, this, _attach).call(this, state, target, timeoutMs);
798
+ _assertClassBrand(_BrowserSession_brand, this, _setActive).call(this, state, target);
799
+ return { sessionId: attachHandle(target) };
800
+ }
801
+ /** The Chrome DevTools Protocol description the browser serves. */
802
+ async spec() {
803
+ return (await _assertClassBrand(_BrowserSession_brand, this, _connect).call(this)).connected.spec();
804
+ }
805
+ /** Recent CDP traffic on this session's connection, newest last. */
806
+ async getDebugLog(input) {
807
+ const { limit } = validate("browser.getDebugLog", DEBUG_LOG_SCHEMA, input);
808
+ return (await _assertClassBrand(_BrowserSession_brand, this, _connect).call(this)).connected.cdp.getDebugLog(limit);
809
+ }
810
+ /** Forget the CDP traffic recorded so far. */
811
+ async clearDebugLog() {
812
+ (await _assertClassBrand(_BrowserSession_brand, this, _connect).call(this)).connected.cdp.clearDebugLog();
813
+ return null;
814
+ }
815
+ /**
816
+ * End the session: save the scope's active tab, work out what happened to
817
+ * the browser, and close the connection. The browser stays open.
818
+ *
819
+ * Resolves with the report, or `undefined` when the session never
820
+ * connected. Never rejects: failures to read the browser's state are
821
+ * logged and leave the report incomplete. Later calls resolve with
822
+ * `undefined`, and other methods reject.
823
+ */
824
+ async close() {
825
+ if (_classPrivateFieldGet2(_closed, this)) return void 0;
826
+ _classPrivateFieldSet2(_closed, this, true);
827
+ let state;
828
+ try {
829
+ state = _classPrivateFieldGet2(_state, this) ?? await _classPrivateFieldGet2(_connecting, this);
830
+ } catch {
831
+ return;
832
+ }
833
+ if (!state) return void 0;
834
+ _classPrivateFieldSet2(_state, this, void 0);
835
+ try {
836
+ const open = await _assertClassBrand(_BrowserSession_brand, this, _recordNewTabs).call(this, state);
837
+ const active = await _assertClassBrand(_BrowserSession_brand, this, _saveActiveTarget).call(this, state, open);
838
+ if (active && state.activeResolved) await _assertClassBrand(_BrowserSession_brand, this, _recordSharedTab).call(this, state, active);
839
+ } finally {
840
+ state.connected.cdp.disconnect();
841
+ }
842
+ return state.report;
843
+ }
844
+ };
845
+ /** Connect once. Concurrent first calls share one connect. */
846
+ function _connect() {
847
+ if (_classPrivateFieldGet2(_closed, this)) return Promise.reject(/* @__PURE__ */ new Error("This browser session is closed."));
848
+ if (_classPrivateFieldGet2(_state, this)) return Promise.resolve(_classPrivateFieldGet2(_state, this));
849
+ _classPrivateFieldGet2(_connecting, this) ?? _classPrivateFieldSet2(_connecting, this, _assertClassBrand(_BrowserSession_brand, this, _open).call(this).finally(() => {
850
+ _classPrivateFieldSet2(_connecting, this, void 0);
851
+ }));
852
+ return _classPrivateFieldGet2(_connecting, this);
853
+ }
854
+ async function _open() {
855
+ const connected = await _classPrivateFieldGet2(_browser, this).connect(_classPrivateFieldGet2(_scope, this) === void 0 ? void 0 : { scope: _classPrivateFieldGet2(_scope, this) });
856
+ let initialPages;
857
+ try {
858
+ initialPages = await _assertClassBrand(_BrowserSession_brand, this, _pages).call(this, connected.cdp);
859
+ } catch (error) {
860
+ connected.cdp.disconnect();
861
+ throw error;
862
+ }
863
+ const state = {
864
+ connected,
865
+ attached: /* @__PURE__ */ new Map(),
866
+ workedIn: /* @__PURE__ */ new Set(),
867
+ initialPages: new Set(initialPages.map((page) => page.targetId)),
868
+ activeResolved: false,
869
+ closed: /* @__PURE__ */ new Set(),
870
+ report: {
871
+ restarted: connected.restarted,
872
+ newTabs: [],
873
+ tabClosed: false,
874
+ tabShared: false
875
+ }
876
+ };
877
+ if (_classPrivateFieldGet2(_closed, this)) return state;
878
+ _classPrivateFieldSet2(_state, this, state);
879
+ return state;
880
+ }
881
+ /**
882
+ * A screenshot over the limit is too big to keep in the chat message
883
+ * (see `DEFAULT_MAX_RESULT_BYTES`), so fail with how to take a smaller one.
884
+ */
885
+ function _assertFits(result) {
886
+ const size = JSON.stringify(result ?? null).length;
887
+ if (size <= _classPrivateFieldGet2(_maxResultBytes, this)) return;
888
+ const megabytes = (size / 1e6).toFixed(1);
889
+ const limit = (_classPrivateFieldGet2(_maxResultBytes, this) / 1e6).toFixed(0);
890
+ throw new Error(`The screenshot result is ${megabytes} MB, over the ${limit} MB limit on a send result. Capture just the viewport (no captureBeyondViewport or clip larger than the window), or pass format: "jpeg" with quality: 60.`);
891
+ }
892
+ /**
893
+ * Add tabs the page opened during this session to the report. Returns the
894
+ * open tabs, or `undefined` when the browser couldn't be asked.
895
+ */
896
+ async function _recordNewTabs(state) {
897
+ let pages;
898
+ try {
899
+ pages = await _assertClassBrand(_BrowserSession_brand, this, _pages).call(this, state.connected.cdp);
900
+ } catch (error) {
901
+ _assertClassBrand(_BrowserSession_brand, this, _warn).call(this, "list the open tabs", error);
902
+ return;
903
+ }
904
+ const opened = /* @__PURE__ */ new Set();
905
+ let grew = true;
906
+ while (grew) {
907
+ grew = false;
908
+ for (const page of pages) {
909
+ const opener = page.openerId;
910
+ if (!opener || opened.has(page.targetId) || state.initialPages.has(page.targetId)) continue;
911
+ if (state.workedIn.has(opener) || opened.has(opener)) {
912
+ opened.add(page.targetId);
913
+ grew = true;
914
+ }
915
+ }
916
+ }
917
+ state.report.newTabs = pages.filter((page) => opened.has(page.targetId)).map(({ targetId, url, title }) => ({
918
+ targetId,
919
+ url,
920
+ title
921
+ }));
922
+ return new Set(pages.map((page) => page.targetId));
923
+ }
924
+ /**
925
+ * Save the tab this session settled on, forgetting one that has since
926
+ * closed, and return it. Without the list of open tabs, save the choice
927
+ * unchecked: the next session checks the stored tab is still open before
928
+ * using it.
929
+ */
930
+ async function _saveActiveTarget(state, open) {
931
+ const stored = state.connected.activeTargetId;
932
+ if (!state.activeResolved && stored && open && !open.has(stored) && !state.closed.has(stored)) state.report.tabClosed = true;
933
+ const candidate = state.activeResolved ? state.activeTargetId : stored;
934
+ const active = candidate && (!open || open.has(candidate)) ? candidate : void 0;
935
+ if (active === stored) return active;
936
+ try {
937
+ await state.connected.setActiveTarget(active);
938
+ } catch (error) {
939
+ _assertClassBrand(_BrowserSession_brand, this, _warn).call(this, "save the active tab", error);
940
+ }
941
+ return active;
942
+ }
943
+ /** Report when another scope is working in this session's tab too. */
944
+ async function _recordSharedTab(state, active) {
945
+ try {
946
+ if ((await state.connected.targetsInOtherScopes()).has(active)) state.report.tabShared = true;
947
+ } catch (error) {
948
+ _assertClassBrand(_BrowserSession_brand, this, _warn).call(this, "check whether the active tab is shared", error);
949
+ }
950
+ }
951
+ function _warn(action, error) {
952
+ console.warn(`[agents/browser] Failed to ${action} for browser "${_classPrivateFieldGet2(_browser, this).name}"`, error);
953
+ }
954
+ async function _pages(cdp) {
955
+ return ((await cdp.send("Target.getTargets"))?.targetInfos ?? []).filter((info) => info.type === "page");
956
+ }
957
+ async function _resolveSessionId(state, sessionId) {
958
+ if (sessionId === "active") return _assertClassBrand(_BrowserSession_brand, this, _attach).call(this, state, await _assertClassBrand(_BrowserSession_brand, this, _activeTarget).call(this, state));
959
+ if (isAttachHandle(sessionId)) return _assertClassBrand(_BrowserSession_brand, this, _attach).call(this, state, targetOfHandle(sessionId));
960
+ return sessionId;
961
+ }
962
+ /**
963
+ * Decide which tab `"active"` means, once per session: the scope's stored
964
+ * tab if it is still open, else a new blank tab. Never a tab the scope
965
+ * didn't open, even a blank one: it may be another scope's, or a popup.
966
+ */
967
+ async function _activeTarget(state) {
968
+ if (state.activeTargetId) return state.activeTargetId;
969
+ const { connected } = state;
970
+ const pages = await _assertClassBrand(_BrowserSession_brand, this, _pages).call(this, connected.cdp);
971
+ const stored = connected.activeTargetId;
972
+ let targetId = pages.find((page) => page.targetId === stored)?.targetId;
973
+ if (!targetId && stored && !state.closed.has(stored)) state.report.tabClosed = true;
974
+ if (!targetId) targetId = (await connected.cdp.send("Target.createTarget", { url: "about:blank" })).targetId;
975
+ _assertClassBrand(_BrowserSession_brand, this, _setActive).call(this, state, targetId);
976
+ return targetId;
977
+ }
978
+ function _setActive(state, targetId) {
979
+ state.activeTargetId = targetId;
980
+ state.activeResolved = true;
981
+ }
982
+ async function _attach(state, targetId, timeoutMs) {
983
+ const existing = state.attached.get(targetId);
984
+ if (existing) return existing;
985
+ const live = await state.connected.cdp.attachToTarget(targetId, { timeoutMs });
986
+ state.attached.set(targetId, live);
987
+ state.workedIn.add(targetId);
988
+ return live;
989
+ }
990
+ /** Track tab changes the model makes through raw Target commands. */
991
+ function _observe(state, method, params, result) {
992
+ const targetId = typeof params?.targetId === "string" ? params.targetId : void 0;
993
+ if (method === "Target.createTarget") {
994
+ const created = result?.targetId;
995
+ if (typeof created === "string") _assertClassBrand(_BrowserSession_brand, this, _setActive).call(this, state, created);
996
+ } else if (method === "Target.attachToTarget" && targetId) {
997
+ _assertClassBrand(_BrowserSession_brand, this, _setActive).call(this, state, targetId);
998
+ state.workedIn.add(targetId);
999
+ } else if (method === "Target.closeTarget" && targetId) {
1000
+ state.attached.delete(targetId);
1001
+ state.closed.add(targetId);
1002
+ if (state.activeTargetId === targetId) state.activeTargetId = void 0;
1003
+ } else if (method === "Target.detachFromTarget") {
1004
+ for (const [target, live] of state.attached) if (target === targetId || live === params?.sessionId) state.attached.delete(target);
1005
+ }
1006
+ }
1007
+ /**
1008
+ * Swap a handle in `Target.detachFromTarget`'s `sessionId` param for the
1009
+ * live CDP session id. Returns {@link DETACHED} when the handle's tab isn't
1010
+ * attached on this socket, so there is nothing to detach.
1011
+ */
1012
+ function _liveParams(state, method, params) {
1013
+ const handle = params?.sessionId;
1014
+ if (method !== "Target.detachFromTarget" || typeof handle !== "string") return params;
1015
+ if (!isAttachHandle(handle)) return params;
1016
+ const live = state.attached.get(targetOfHandle(handle));
1017
+ return live ? {
1018
+ ...params,
1019
+ sessionId: live
1020
+ } : DETACHED;
1021
+ }
1022
+ /**
1023
+ * Turn the common protocol mistakes into instructions: an expired CDP
1024
+ * session id, an event sent as a command, and a page-scoped command
1025
+ * without a session.
1026
+ */
1027
+ async function _teach(state, error, method, sessionId) {
1028
+ if (!(error instanceof CdpProtocolError)) return error;
1029
+ if (error.code === CDP_SESSION_NOT_FOUND && sessionId && sessionId !== "active" && !isAttachHandle(sessionId)) return /* @__PURE__ */ new Error(`${error.message}. CDP session ids don't carry over between runs. Use sessionId: "active" for the current tab, or the handle from browser.attachToTarget({ targetId }) for another tab.`);
1030
+ if (error.code !== -32601) return error;
1031
+ if (await _assertClassBrand(_BrowserSession_brand, this, _isEvent).call(this, state, method)) return /* @__PURE__ */ new Error(`${error.message}. '${method}' is a CDP *event*, not a command, so it cannot be sent. To wait for page state, poll instead (e.g. Runtime.evaluate of document.readyState until "complete").`);
1032
+ if (!sessionId) return /* @__PURE__ */ new Error(`${error.message}. '${method}' is page-scoped: pass sessionId: "active" to run it in the current tab: browser.cdp({ method: "${method}", params, sessionId: "active" }).`);
1033
+ return error;
1034
+ }
1035
+ async function _isEvent(state, method) {
1036
+ try {
1037
+ const spec = await state.connected.spec();
1038
+ const domain = method.split(".")[0];
1039
+ return spec.domains.some((d) => d.name === domain && d.events.some((e) => e.event === method));
1040
+ } catch {
1041
+ return false;
1042
+ }
1043
+ }
1044
+ function attachHandle(targetId) {
1045
+ return `${ATTACH_HANDLE_PREFIX}${targetId}`;
1046
+ }
1047
+ function isAttachHandle(sessionId) {
1048
+ return sessionId?.startsWith(ATTACH_HANDLE_PREFIX) ?? false;
1049
+ }
1050
+ function targetOfHandle(handle) {
1051
+ return handle.slice(7);
1052
+ }
1053
+ const validators = /* @__PURE__ */ new WeakMap();
1054
+ /**
1055
+ * Check a method's input against its schema before it touches the browser,
1056
+ * so the model gets a precise error. An omitted input counts as `{}`.
1057
+ *
1058
+ * @internal Also used by `browser-functions.ts`.
1059
+ */
1060
+ function validate(name, schema, input) {
1061
+ let validator = validators.get(schema);
1062
+ if (!validator) {
1063
+ validator = new Validator(schema, "7", false);
1064
+ validators.set(schema, validator);
1065
+ }
1066
+ const value = input ?? {};
1067
+ const result = validator.validate(value);
1068
+ if (!result.valid) throw new Error(formatValidationError(name, result.errors));
1069
+ return value;
1070
+ }
1071
+ function formatValidationError(name, errors) {
1072
+ const specific = errors.filter((error) => error.keyword !== "properties");
1073
+ return `Invalid arguments for ${name}${(specific.length > 0 ? specific : errors).map((error) => {
1074
+ const location = error.instanceLocation.replace(/^#\/?/, "").replaceAll("~1", "/").replaceAll("~0", "~").replaceAll("/", ".");
1075
+ return `${location ? ` at ${location}` : ""}: ${error.error}`;
1076
+ }).join(";")}`;
1077
+ }
1078
+ //#endregion
1079
+ export { CdpProtocolError as C, CdpConnection as S, connectUrl as T, deleteBrowserSession as _, DEFAULT_SWEEP_IDLE_MS as a, listBrowserTargets as b, LIVE_VIEW_URL_TTL_MS as c, BrowserRenderingError as d, acquireBrowserSession as f, createBrowserSession as g, connectBrowserSession as h, validate as i, applyLiveViewMode as l, connectBrowser as m, BrowserSession as n, DurableBrowserSessionStore as o, closeBrowserSession as p, DEFAULT_MAX_RESULT_BYTES as r, loadCdpSpec as s, ACTIVE_PAGE_SESSION as t, createLiveView as u, getBrowserRecording as v, CdpSession as w, CDP_METHOD_NOT_FOUND as x, isMissingBrowserSession as y };
658
1080
 
659
- //# sourceMappingURL=session-store-yvwq1f9x.js.map
1081
+ //# sourceMappingURL=session-7CDgVE0z.js.map