@copilotkit/runtime 1.81.0 → 1.83.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 (156) hide show
  1. package/dist/agent/index.cjs +18 -10
  2. package/dist/agent/index.cjs.map +1 -1
  3. package/dist/agent/index.d.cts +41 -1
  4. package/dist/agent/index.d.cts.map +1 -1
  5. package/dist/agent/index.d.mts +42 -2
  6. package/dist/agent/index.d.mts.map +1 -1
  7. package/dist/agent/index.mjs +18 -10
  8. package/dist/agent/index.mjs.map +1 -1
  9. package/dist/agent/url-download.cjs +504 -0
  10. package/dist/agent/url-download.cjs.map +1 -0
  11. package/dist/agent/url-download.d.cts +80 -0
  12. package/dist/agent/url-download.d.cts.map +1 -0
  13. package/dist/agent/url-download.d.mts +80 -0
  14. package/dist/agent/url-download.d.mts.map +1 -0
  15. package/dist/agent/url-download.mjs +501 -0
  16. package/dist/agent/url-download.mjs.map +1 -0
  17. package/dist/lib/runtime/copilot-runtime.cjs +2 -1
  18. package/dist/lib/runtime/copilot-runtime.cjs.map +1 -1
  19. package/dist/lib/runtime/copilot-runtime.d.cts +5 -0
  20. package/dist/lib/runtime/copilot-runtime.d.cts.map +1 -1
  21. package/dist/lib/runtime/copilot-runtime.d.mts +5 -0
  22. package/dist/lib/runtime/copilot-runtime.d.mts.map +1 -1
  23. package/dist/lib/runtime/copilot-runtime.mjs +2 -1
  24. package/dist/lib/runtime/copilot-runtime.mjs.map +1 -1
  25. package/dist/lib/runtime/telemetry-agent-runner.cjs +4 -1
  26. package/dist/lib/runtime/telemetry-agent-runner.cjs.map +1 -1
  27. package/dist/lib/runtime/telemetry-agent-runner.d.cts +7 -1
  28. package/dist/lib/runtime/telemetry-agent-runner.d.cts.map +1 -1
  29. package/dist/lib/runtime/telemetry-agent-runner.d.mts +7 -1
  30. package/dist/lib/runtime/telemetry-agent-runner.d.mts.map +1 -1
  31. package/dist/lib/runtime/telemetry-agent-runner.mjs +4 -1
  32. package/dist/lib/runtime/telemetry-agent-runner.mjs.map +1 -1
  33. package/dist/package.cjs +1 -1
  34. package/dist/package.mjs +1 -1
  35. package/dist/v2/index.cjs +12 -3
  36. package/dist/v2/index.d.cts +5 -3
  37. package/dist/v2/index.d.mts +5 -3
  38. package/dist/v2/index.mjs +6 -5
  39. package/dist/v2/runtime/core/channel-manager.cjs +2 -1
  40. package/dist/v2/runtime/core/channel-manager.cjs.map +1 -1
  41. package/dist/v2/runtime/core/channel-manager.mjs +2 -1
  42. package/dist/v2/runtime/core/channel-manager.mjs.map +1 -1
  43. package/dist/v2/runtime/core/fetch-handler.cjs +3 -3
  44. package/dist/v2/runtime/core/fetch-handler.cjs.map +1 -1
  45. package/dist/v2/runtime/core/fetch-handler.mjs +3 -3
  46. package/dist/v2/runtime/core/fetch-handler.mjs.map +1 -1
  47. package/dist/v2/runtime/core/package-info.cjs +1 -1
  48. package/dist/v2/runtime/core/package-info.mjs +1 -1
  49. package/dist/v2/runtime/core/runtime.cjs +12 -2
  50. package/dist/v2/runtime/core/runtime.cjs.map +1 -1
  51. package/dist/v2/runtime/core/runtime.d.cts +40 -1
  52. package/dist/v2/runtime/core/runtime.d.cts.map +1 -1
  53. package/dist/v2/runtime/core/runtime.d.mts +40 -1
  54. package/dist/v2/runtime/core/runtime.d.mts.map +1 -1
  55. package/dist/v2/runtime/core/runtime.mjs +12 -2
  56. package/dist/v2/runtime/core/runtime.mjs.map +1 -1
  57. package/dist/v2/runtime/handlers/get-runtime-info.cjs +6 -6
  58. package/dist/v2/runtime/handlers/get-runtime-info.cjs.map +1 -1
  59. package/dist/v2/runtime/handlers/get-runtime-info.mjs +6 -6
  60. package/dist/v2/runtime/handlers/get-runtime-info.mjs.map +1 -1
  61. package/dist/v2/runtime/handlers/handle-connect.cjs +9 -1
  62. package/dist/v2/runtime/handlers/handle-connect.cjs.map +1 -1
  63. package/dist/v2/runtime/handlers/handle-connect.mjs +9 -1
  64. package/dist/v2/runtime/handlers/handle-connect.mjs.map +1 -1
  65. package/dist/v2/runtime/handlers/handle-inspector-learning.cjs +1 -1
  66. package/dist/v2/runtime/handlers/handle-inspector-learning.mjs +1 -1
  67. package/dist/v2/runtime/handlers/handle-run.cjs +16 -2
  68. package/dist/v2/runtime/handlers/handle-run.cjs.map +1 -1
  69. package/dist/v2/runtime/handlers/handle-run.mjs +16 -2
  70. package/dist/v2/runtime/handlers/handle-run.mjs.map +1 -1
  71. package/dist/v2/runtime/handlers/handle-stop.cjs +14 -3
  72. package/dist/v2/runtime/handlers/handle-stop.cjs.map +1 -1
  73. package/dist/v2/runtime/handlers/handle-stop.mjs +14 -3
  74. package/dist/v2/runtime/handlers/handle-stop.mjs.map +1 -1
  75. package/dist/v2/runtime/handlers/handle-trajectory-connect.cjs +1 -1
  76. package/dist/v2/runtime/handlers/handle-trajectory-connect.mjs +1 -1
  77. package/dist/v2/runtime/handlers/intelligence/annotate.cjs +2 -2
  78. package/dist/v2/runtime/handlers/intelligence/annotate.mjs +2 -2
  79. package/dist/v2/runtime/handlers/intelligence/memories.cjs +1 -1
  80. package/dist/v2/runtime/handlers/intelligence/memories.mjs +1 -1
  81. package/dist/v2/runtime/handlers/intelligence/run.cjs +7 -4
  82. package/dist/v2/runtime/handlers/intelligence/run.cjs.map +1 -1
  83. package/dist/v2/runtime/handlers/intelligence/run.mjs +7 -4
  84. package/dist/v2/runtime/handlers/intelligence/run.mjs.map +1 -1
  85. package/dist/v2/runtime/handlers/intelligence/threads.cjs +137 -31
  86. package/dist/v2/runtime/handlers/intelligence/threads.cjs.map +1 -1
  87. package/dist/v2/runtime/handlers/intelligence/threads.mjs +138 -32
  88. package/dist/v2/runtime/handlers/intelligence/threads.mjs.map +1 -1
  89. package/dist/v2/runtime/handlers/shared/agent-utils.cjs +3 -3
  90. package/dist/v2/runtime/handlers/shared/agent-utils.mjs +3 -3
  91. package/dist/v2/runtime/handlers/shared/mcp-apps-servers.cjs +2 -1
  92. package/dist/v2/runtime/handlers/shared/mcp-apps-servers.cjs.map +1 -1
  93. package/dist/v2/runtime/handlers/shared/mcp-apps-servers.mjs +3 -1
  94. package/dist/v2/runtime/handlers/shared/mcp-apps-servers.mjs.map +1 -1
  95. package/dist/v2/runtime/handlers/shared/platform-error.cjs +1 -1
  96. package/dist/v2/runtime/handlers/shared/platform-error.mjs +1 -1
  97. package/dist/v2/runtime/handlers/shared/resolve-intelligence-user.cjs +22 -3
  98. package/dist/v2/runtime/handlers/shared/resolve-intelligence-user.cjs.map +1 -1
  99. package/dist/v2/runtime/handlers/shared/resolve-intelligence-user.mjs +22 -4
  100. package/dist/v2/runtime/handlers/shared/resolve-intelligence-user.mjs.map +1 -1
  101. package/dist/v2/runtime/handlers/shared/sse-response.cjs +20 -3
  102. package/dist/v2/runtime/handlers/shared/sse-response.cjs.map +1 -1
  103. package/dist/v2/runtime/handlers/shared/sse-response.mjs +20 -3
  104. package/dist/v2/runtime/handlers/shared/sse-response.mjs.map +1 -1
  105. package/dist/v2/runtime/handlers/shared/thread-access.cjs +138 -0
  106. package/dist/v2/runtime/handlers/shared/thread-access.cjs.map +1 -0
  107. package/dist/v2/runtime/handlers/shared/thread-access.d.cts +29 -0
  108. package/dist/v2/runtime/handlers/shared/thread-access.d.cts.map +1 -0
  109. package/dist/v2/runtime/handlers/shared/thread-access.d.mts +29 -0
  110. package/dist/v2/runtime/handlers/shared/thread-access.d.mts.map +1 -0
  111. package/dist/v2/runtime/handlers/shared/thread-access.mjs +133 -0
  112. package/dist/v2/runtime/handlers/shared/thread-access.mjs.map +1 -0
  113. package/dist/v2/runtime/handlers/sse/connect.cjs +2 -1
  114. package/dist/v2/runtime/handlers/sse/connect.cjs.map +1 -1
  115. package/dist/v2/runtime/handlers/sse/connect.mjs +2 -1
  116. package/dist/v2/runtime/handlers/sse/connect.mjs.map +1 -1
  117. package/dist/v2/runtime/handlers/sse/run.cjs +23 -6
  118. package/dist/v2/runtime/handlers/sse/run.cjs.map +1 -1
  119. package/dist/v2/runtime/handlers/sse/run.mjs +23 -6
  120. package/dist/v2/runtime/handlers/sse/run.mjs.map +1 -1
  121. package/dist/v2/runtime/index.d.cts +3 -2
  122. package/dist/v2/runtime/index.d.cts.map +1 -1
  123. package/dist/v2/runtime/index.d.mts +3 -2
  124. package/dist/v2/runtime/index.d.mts.map +1 -1
  125. package/dist/v2/runtime/intelligence-platform/client.cjs +17 -4
  126. package/dist/v2/runtime/intelligence-platform/client.cjs.map +1 -1
  127. package/dist/v2/runtime/intelligence-platform/client.d.cts +9 -37
  128. package/dist/v2/runtime/intelligence-platform/client.d.cts.map +1 -1
  129. package/dist/v2/runtime/intelligence-platform/client.d.mts +9 -37
  130. package/dist/v2/runtime/intelligence-platform/client.d.mts.map +1 -1
  131. package/dist/v2/runtime/intelligence-platform/client.mjs +17 -4
  132. package/dist/v2/runtime/intelligence-platform/client.mjs.map +1 -1
  133. package/dist/v2/runtime/runner/agent-runner.cjs +55 -0
  134. package/dist/v2/runtime/runner/agent-runner.cjs.map +1 -1
  135. package/dist/v2/runtime/runner/agent-runner.d.cts +90 -6
  136. package/dist/v2/runtime/runner/agent-runner.d.cts.map +1 -1
  137. package/dist/v2/runtime/runner/agent-runner.d.mts +90 -6
  138. package/dist/v2/runtime/runner/agent-runner.d.mts.map +1 -1
  139. package/dist/v2/runtime/runner/agent-runner.mjs +50 -1
  140. package/dist/v2/runtime/runner/agent-runner.mjs.map +1 -1
  141. package/dist/v2/runtime/runner/in-memory.cjs +205 -25
  142. package/dist/v2/runtime/runner/in-memory.cjs.map +1 -1
  143. package/dist/v2/runtime/runner/in-memory.d.cts +112 -15
  144. package/dist/v2/runtime/runner/in-memory.d.cts.map +1 -1
  145. package/dist/v2/runtime/runner/in-memory.d.mts +112 -15
  146. package/dist/v2/runtime/runner/in-memory.d.mts.map +1 -1
  147. package/dist/v2/runtime/runner/in-memory.mjs +206 -27
  148. package/dist/v2/runtime/runner/in-memory.mjs.map +1 -1
  149. package/dist/v2/runtime/runner/index.d.cts +2 -2
  150. package/dist/v2/runtime/runner/index.d.mts +2 -2
  151. package/dist/v2/runtime/runner/index.mjs +2 -2
  152. package/dist/v2/runtime/telemetry/telemetry-client.cjs +1 -1
  153. package/dist/v2/runtime/telemetry/telemetry-client.cjs.map +1 -1
  154. package/dist/v2/runtime/telemetry/telemetry-client.mjs +1 -1
  155. package/dist/v2/runtime/telemetry/telemetry-client.mjs.map +1 -1
  156. package/package.json +6 -6
@@ -0,0 +1,80 @@
1
+
2
+ import { Experimental_DownloadFunction } from "ai";
3
+
4
+ //#region src/agent/url-download.d.ts
5
+ /** Options for the default, public-network-only URL downloader. */
6
+ interface SafeUrlDownloadOptions {
7
+ /**
8
+ * Hostnames that may be downloaded. When omitted, any hostname is allowed.
9
+ * Every resolved address must be public in both cases, and every redirect
10
+ * target must match as well.
11
+ *
12
+ * - `cdn.example.com` matches exactly that host.
13
+ * - `*.example.com` matches any subdomain (`a.example.com`,
14
+ * `a.b.example.com`) but not `example.com` itself; list both if needed.
15
+ *
16
+ * Matching ignores case and a trailing dot. Unicode names match their
17
+ * punycode form, and an IPv6 address may be given with or without
18
+ * brackets. An entry with a scheme, port, path or user, and a wildcard over
19
+ * an IP address (`*.1.2.3.4`), are rejected when the downloader is created.
20
+ * An empty list refuses every server-side download; `data:` URLs and URLs
21
+ * that the model takes directly are not downloaded, so they still pass.
22
+ */
23
+ allowedHosts?: string[];
24
+ /** Largest response body to accept, in bytes (at least 1). Default: 20 MiB. */
25
+ maxBytes?: number;
26
+ /**
27
+ * Time limit for one download, including redirects, in ms. From 1 to
28
+ * 2147483647 (the largest delay `setTimeout` supports). Default: 30000.
29
+ */
30
+ timeoutMs?: number;
31
+ /** Largest number of redirects to follow; 0 follows none. Default: 3. */
32
+ maxRedirects?: number;
33
+ /**
34
+ * Largest number of distinct URLs to download for one model call (at
35
+ * least 1); a URL that appears twice is downloaded once. The AI SDK
36
+ * downloads the attachments of every user message again for each step of
37
+ * a multi-step run. Default: 20.
38
+ */
39
+ maxDownloads?: number;
40
+ /**
41
+ * Largest number of bytes to download for one model call, over all its
42
+ * URLs (at least 1). Default: 50 MiB.
43
+ */
44
+ maxTotalBytes?: number;
45
+ }
46
+ /** Options for {@link createSafeUrlDownload}. */
47
+ interface CreateSafeUrlDownloadOptions extends SafeUrlDownloadOptions {
48
+ /**
49
+ * Stops every download of this function when it aborts, for example the
50
+ * run's `ctx.abortSignal` in BuiltInAgent's factory mode. Without it, a
51
+ * download that is running when the run is aborted goes on until it ends
52
+ * or reaches `timeoutMs`.
53
+ */
54
+ signal?: AbortSignal;
55
+ }
56
+ /**
57
+ * Creates an AI SDK download function (`experimental_download`) that only
58
+ * fetches public internet addresses, with the same checks and limits as
59
+ * BuiltInAgent's default downloader. Pass it to `streamText` yourself when
60
+ * you use BuiltInAgent's AI SDK factory mode. Create it in the factory with
61
+ * the run's abort signal, so that an aborted run stops its downloads:
62
+ *
63
+ * ```ts
64
+ * import { createSafeUrlDownload } from "@copilotkit/runtime/v2";
65
+ *
66
+ * factory: (ctx) =>
67
+ * streamText({
68
+ * model,
69
+ * messages,
70
+ * abortSignal: ctx.abortSignal,
71
+ * experimental_download: createSafeUrlDownload({ signal: ctx.abortSignal }),
72
+ * }),
73
+ * ```
74
+ *
75
+ * Invalid options throw here, when the function is created.
76
+ */
77
+ declare function createSafeUrlDownload(options?: CreateSafeUrlDownloadOptions): Experimental_DownloadFunction;
78
+ //#endregion
79
+ export { CreateSafeUrlDownloadOptions, SafeUrlDownloadOptions, createSafeUrlDownload };
80
+ //# sourceMappingURL=url-download.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"url-download.d.cts","names":[],"sources":["../../src/agent/url-download.ts"],"mappings":";;;;;UAwCiB,sBAAA;EAAsB;;;;;;;;;;;AA42BvC;;;;;EA31BE,YAAA;EAk2BS;EAh2BT,QAAA;EAg2BoB;AAwBtB;;;EAn3BE,SAAA;EAo3BS;EAl3BT,YAAA;EAm3BC;;;;;;EA52BD,YAAA;;;;;EAKA,aAAA;AAAA;;UAs0Be,4BAAA,SAAqC,sBAAA;;;;;;;EAOpD,MAAA,GAAS,WAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;iBAwBK,qBAAA,CACd,OAAA,GAAS,4BAAA,GACR,6BAAA"}
@@ -0,0 +1,80 @@
1
+
2
+ import { Experimental_DownloadFunction } from "ai";
3
+
4
+ //#region src/agent/url-download.d.ts
5
+ /** Options for the default, public-network-only URL downloader. */
6
+ interface SafeUrlDownloadOptions {
7
+ /**
8
+ * Hostnames that may be downloaded. When omitted, any hostname is allowed.
9
+ * Every resolved address must be public in both cases, and every redirect
10
+ * target must match as well.
11
+ *
12
+ * - `cdn.example.com` matches exactly that host.
13
+ * - `*.example.com` matches any subdomain (`a.example.com`,
14
+ * `a.b.example.com`) but not `example.com` itself; list both if needed.
15
+ *
16
+ * Matching ignores case and a trailing dot. Unicode names match their
17
+ * punycode form, and an IPv6 address may be given with or without
18
+ * brackets. An entry with a scheme, port, path or user, and a wildcard over
19
+ * an IP address (`*.1.2.3.4`), are rejected when the downloader is created.
20
+ * An empty list refuses every server-side download; `data:` URLs and URLs
21
+ * that the model takes directly are not downloaded, so they still pass.
22
+ */
23
+ allowedHosts?: string[];
24
+ /** Largest response body to accept, in bytes (at least 1). Default: 20 MiB. */
25
+ maxBytes?: number;
26
+ /**
27
+ * Time limit for one download, including redirects, in ms. From 1 to
28
+ * 2147483647 (the largest delay `setTimeout` supports). Default: 30000.
29
+ */
30
+ timeoutMs?: number;
31
+ /** Largest number of redirects to follow; 0 follows none. Default: 3. */
32
+ maxRedirects?: number;
33
+ /**
34
+ * Largest number of distinct URLs to download for one model call (at
35
+ * least 1); a URL that appears twice is downloaded once. The AI SDK
36
+ * downloads the attachments of every user message again for each step of
37
+ * a multi-step run. Default: 20.
38
+ */
39
+ maxDownloads?: number;
40
+ /**
41
+ * Largest number of bytes to download for one model call, over all its
42
+ * URLs (at least 1). Default: 50 MiB.
43
+ */
44
+ maxTotalBytes?: number;
45
+ }
46
+ /** Options for {@link createSafeUrlDownload}. */
47
+ interface CreateSafeUrlDownloadOptions extends SafeUrlDownloadOptions {
48
+ /**
49
+ * Stops every download of this function when it aborts, for example the
50
+ * run's `ctx.abortSignal` in BuiltInAgent's factory mode. Without it, a
51
+ * download that is running when the run is aborted goes on until it ends
52
+ * or reaches `timeoutMs`.
53
+ */
54
+ signal?: AbortSignal;
55
+ }
56
+ /**
57
+ * Creates an AI SDK download function (`experimental_download`) that only
58
+ * fetches public internet addresses, with the same checks and limits as
59
+ * BuiltInAgent's default downloader. Pass it to `streamText` yourself when
60
+ * you use BuiltInAgent's AI SDK factory mode. Create it in the factory with
61
+ * the run's abort signal, so that an aborted run stops its downloads:
62
+ *
63
+ * ```ts
64
+ * import { createSafeUrlDownload } from "@copilotkit/runtime/v2";
65
+ *
66
+ * factory: (ctx) =>
67
+ * streamText({
68
+ * model,
69
+ * messages,
70
+ * abortSignal: ctx.abortSignal,
71
+ * experimental_download: createSafeUrlDownload({ signal: ctx.abortSignal }),
72
+ * }),
73
+ * ```
74
+ *
75
+ * Invalid options throw here, when the function is created.
76
+ */
77
+ declare function createSafeUrlDownload(options?: CreateSafeUrlDownloadOptions): Experimental_DownloadFunction;
78
+ //#endregion
79
+ export { CreateSafeUrlDownloadOptions, SafeUrlDownloadOptions, createSafeUrlDownload };
80
+ //# sourceMappingURL=url-download.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"url-download.d.mts","names":[],"sources":["../../src/agent/url-download.ts"],"mappings":";;;;;UAwCiB,sBAAA;EAAsB;;;;;;;;;;;AA42BvC;;;;;EA31BE,YAAA;EAk2BS;EAh2BT,QAAA;EAg2BoB;AAwBtB;;;EAn3BE,SAAA;EAo3BS;EAl3BT,YAAA;EAm3BC;;;;;;EA52BD,YAAA;;;;;EAKA,aAAA;AAAA;;UAs0Be,4BAAA,SAAqC,sBAAA;;;;;;;EAOpD,MAAA,GAAS,WAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;iBAwBK,qBAAA,CACd,OAAA,GAAS,4BAAA,GACR,6BAAA"}
@@ -0,0 +1,501 @@
1
+ import "reflect-metadata";
2
+ import { COPILOTKIT_VERSION } from "@copilotkit/shared";
3
+ import { DownloadError } from "ai";
4
+
5
+ //#region src/agent/url-download.ts
6
+ const DEFAULT_MAX_BYTES = 20 * 1024 * 1024;
7
+ const DEFAULT_TIMEOUT_MS = 3e4;
8
+ const DEFAULT_MAX_REDIRECTS = 3;
9
+ const DEFAULT_MAX_DOWNLOADS = 20;
10
+ const DEFAULT_MAX_TOTAL_BYTES = 50 * 1024 * 1024;
11
+ const HOST_REFUSED = "The URL host is not a public address, or it could not be resolved.";
12
+ const DOWNLOAD_FAILED = "The download failed.";
13
+ const USER_AGENT = `CopilotKit-Runtime/${COPILOTKIT_VERSION}`;
14
+ const REDIRECT_STATUSES = new Set([
15
+ 301,
16
+ 302,
17
+ 303,
18
+ 307,
19
+ 308
20
+ ]);
21
+ let nodeModules;
22
+ function loadNodeModules() {
23
+ nodeModules ??= Promise.all([
24
+ import("node:dns/promises"),
25
+ import("node:http"),
26
+ import("node:https"),
27
+ import("node:net")
28
+ ]).then(([dns, http, https, net]) => ({
29
+ dns,
30
+ http,
31
+ https,
32
+ net
33
+ })).catch((error) => {
34
+ nodeModules = void 0;
35
+ throw error;
36
+ });
37
+ return nodeModules;
38
+ }
39
+ let defaultPolicy;
40
+ function buildAddressPolicy(net) {
41
+ const nonPublicV4 = new net.BlockList();
42
+ for (const [address, prefix] of [
43
+ ["0.0.0.0", 8],
44
+ ["10.0.0.0", 8],
45
+ ["100.64.0.0", 10],
46
+ ["127.0.0.0", 8],
47
+ ["169.254.0.0", 16],
48
+ ["172.16.0.0", 12],
49
+ ["192.0.0.0", 24],
50
+ ["192.0.2.0", 24],
51
+ ["192.88.99.0", 24],
52
+ ["192.168.0.0", 16],
53
+ ["198.18.0.0", 15],
54
+ ["198.51.100.0", 24],
55
+ ["203.0.113.0", 24],
56
+ ["224.0.0.0", 4],
57
+ ["240.0.0.0", 4]
58
+ ]) nonPublicV4.addSubnet(address, prefix, "ipv4");
59
+ const globalV6 = new net.BlockList();
60
+ globalV6.addSubnet("2000::", 3, "ipv6");
61
+ const nonPublicV6 = new net.BlockList();
62
+ for (const [address, prefix] of [
63
+ ["2001::", 23],
64
+ ["2001:db8::", 32],
65
+ ["2002::", 16],
66
+ ["3fff::", 20]
67
+ ]) nonPublicV6.addSubnet(address, prefix, "ipv6");
68
+ return (address) => {
69
+ const family = net.isIP(address);
70
+ if (family === 4) return !nonPublicV4.check(address, "ipv4");
71
+ if (family !== 6 || address.includes("%")) return false;
72
+ return globalV6.check(address, "ipv6") && !nonPublicV6.check(address, "ipv6");
73
+ };
74
+ }
75
+ /**
76
+ * True when the server must not fetch this URL itself and returns `null` so
77
+ * the AI SDK handles it: the provider takes the URL as-is, or it is a `data:`
78
+ * URL, which the AI SDK decodes locally without any network request.
79
+ */
80
+ function leftToAiSdk({ url, isUrlSupportedByModel }) {
81
+ return isUrlSupportedByModel || url.protocol === "data:";
82
+ }
83
+ /** The URL without its query and fragment, which can hold credentials. */
84
+ function urlForLog(url) {
85
+ try {
86
+ const parsed = new URL(String(url));
87
+ return `${parsed.protocol}//${parsed.host}${parsed.pathname}`;
88
+ } catch {
89
+ return "(invalid URL)";
90
+ }
91
+ }
92
+ /** `text` with the query and fragment removed from every URL in it. */
93
+ function redactUrls(text) {
94
+ return text.replace(/\b([a-z][a-z0-9+.-]*:\/\/[^\s?#"'`<>]*)[?#][^\s"'`<>]*/gi, "$1");
95
+ }
96
+ const loggedErrors = /* @__PURE__ */ new WeakSet();
97
+ /**
98
+ * Returns the error for a failed or refused download and logs it on the
99
+ * server. `detail` goes only to the log: the client sees `message`, which
100
+ * never holds the URL's query, a resolved address or a raw network error.
101
+ * For a refused host, `message` is the same whether the name did not resolve
102
+ * or resolved to a non-public address, so that it does not reveal internal
103
+ * DNS names.
104
+ */
105
+ function refuse(url, message, detail, statusCode) {
106
+ console.warn(redactUrls(`[BuiltInAgent] URL download failed for ${urlForLog(url)}: ${message}${detail ? ` (${detail})` : ""}`));
107
+ const error = new DownloadError({
108
+ url: urlForLog(url),
109
+ message,
110
+ statusCode
111
+ });
112
+ loggedErrors.add(error);
113
+ return error;
114
+ }
115
+ /**
116
+ * @internal BuiltInAgent's `onError` for its `streamText` call. The AI SDK's
117
+ * default handler prints the whole error, which for a download error holds
118
+ * the URL with its query. This logs an error once, with the same detail
119
+ * (for a provider API error, its status code and response body) but with the
120
+ * query and fragment removed from every URL, and skips the download errors
121
+ * that were already logged here.
122
+ */
123
+ function logModelCallError(error) {
124
+ if (typeof error === "object" && error !== null && loggedErrors.has(error)) return;
125
+ const frames = error instanceof Error && error.stack ? error.stack.split("\n").filter((line) => /^\s+at /.test(line)).join("\n") : "";
126
+ console.error(redactUrls(`[BuiltInAgent] The model call failed: ${describeModelError(error)}${frames ? `\n${frames}` : ""}`));
127
+ }
128
+ const MAX_LOGGED_FIELD_LENGTH = 2e3;
129
+ function truncateForLog(text) {
130
+ return text.length > MAX_LOGGED_FIELD_LENGTH ? `${text.slice(0, MAX_LOGGED_FIELD_LENGTH)}… (${text.length} characters)` : text;
131
+ }
132
+ /**
133
+ * {@link describeError}, followed by the other fields of the error, such as
134
+ * the `statusCode`, `responseBody` and `url` of the AI SDK's APICallError. A
135
+ * value that is not an Error, such as the plain object that a provider
136
+ * stream sends as its error, is logged as JSON.
137
+ */
138
+ function describeModelError(error) {
139
+ if (!(error instanceof Error)) return truncateForLog(describeValue(error));
140
+ const fields = Object.entries(error).filter(([key]) => ![
141
+ "name",
142
+ "message",
143
+ "stack",
144
+ "cause",
145
+ "code"
146
+ ].includes(key)).map(([key, value]) => {
147
+ return `${key}: ${truncateForLog(value instanceof Error ? describeError(value) : typeof value === "string" ? value : describeValue(value))}`;
148
+ });
149
+ return `${error.name && error.name !== "Error" ? `${error.name}: ` : ""}${describeError(error)}${fields.length > 0 ? ` {${fields.join("; ")}}` : ""}`;
150
+ }
151
+ /** Message, error code and causes of an error, for the server log. */
152
+ function describeError(error, depth = 0) {
153
+ if (typeof error === "string") return error;
154
+ if (!(error instanceof Error)) return truncateForLog(describeValue(error));
155
+ const code = error.code;
156
+ const text = typeof code === "string" && !error.message.includes(code) ? `${code}: ${error.message}` : error.message;
157
+ return error.cause !== void 0 && depth < 3 ? `${text}; caused by ${describeError(error.cause, depth + 1)}` : text;
158
+ }
159
+ /**
160
+ * A printable form of a configuration value for an error message. Unlike
161
+ * `JSON.stringify`, it never throws (BigInt) and never gives `undefined`
162
+ * (Symbol, function).
163
+ */
164
+ function describeValue(value) {
165
+ if (typeof value === "bigint") return `${value}n`;
166
+ if (typeof value === "function") return "a function";
167
+ try {
168
+ const text = JSON.stringify(value);
169
+ if (text !== void 0) return text;
170
+ } catch {}
171
+ try {
172
+ return String(value);
173
+ } catch {
174
+ return Object.prototype.toString.call(value);
175
+ }
176
+ }
177
+ /**
178
+ * The form in which hostnames are compared: a URL hostname (lowercase ASCII,
179
+ * IDNA as punycode, IPv6 in canonical form) without IPv6 brackets and without
180
+ * one trailing dot.
181
+ */
182
+ function comparableHost(hostname) {
183
+ return hostname.replace(/^\[(.*)\]$/, "$1").replace(/\.$/, "");
184
+ }
185
+ /**
186
+ * Validates one `allowedHosts` entry and returns it in comparable form: an
187
+ * exact host, or `*.` followed by a host suffix.
188
+ */
189
+ function normalizeAllowedHost(entry) {
190
+ const invalid = (reason) => /* @__PURE__ */ new Error(`urlDownload.allowedHosts entry ${describeValue(entry)} is invalid: ${reason}`);
191
+ if (typeof entry !== "string" || entry === "") throw invalid("it must be a non-empty hostname");
192
+ if (/[\s/?#@\\]/.test(entry)) throw invalid("give only a hostname, without a scheme, path or user");
193
+ const wildcard = entry.startsWith("*.");
194
+ const host = wildcard ? entry.slice(2) : entry;
195
+ if (host === "" || host === "." || host.includes("*")) throw invalid("\"*\" is allowed only as a leading \"*.\" label");
196
+ if (/^[^:[\]]*:\d*$/.test(host) || /^\[.*\]:\d*$/.test(host)) throw invalid("give only a hostname, without a port");
197
+ const bare = host.replace(/^\[(.*)\]$/, "$1");
198
+ const authority = bare.includes(":") ? `[${bare}]` : host;
199
+ let parsed;
200
+ try {
201
+ parsed = new URL(`http://${authority}/`);
202
+ } catch {
203
+ throw invalid("it is not a valid hostname");
204
+ }
205
+ const normalized = comparableHost(parsed.hostname);
206
+ if (wildcard && (normalized.includes(":") || /^\d+\.\d+\.\d+\.\d+$/.test(normalized))) throw invalid("a wildcard needs a hostname suffix, not an IP address");
207
+ return (wildcard ? "*." : "") + normalized;
208
+ }
209
+ function normalizeAllowedHosts(entries) {
210
+ if (entries === void 0) return void 0;
211
+ if (!Array.isArray(entries)) throw new Error("urlDownload.allowedHosts must be an array of hostnames");
212
+ return entries.map(normalizeAllowedHost);
213
+ }
214
+ function hostAllowed(hostname, allowedHosts) {
215
+ if (!allowedHosts) return true;
216
+ const host = comparableHost(hostname);
217
+ return allowedHosts.some((pattern) => pattern.startsWith("*.") ? host.endsWith(pattern.slice(1)) && host.length > pattern.length - 1 : host === pattern);
218
+ }
219
+ function checkUrl(url, allowedHosts) {
220
+ if (url.protocol !== "http:" && url.protocol !== "https:") throw refuse(url, "Only http and https URLs can be downloaded.");
221
+ if (url.username !== "" || url.password !== "") throw refuse(url, "URLs with credentials cannot be downloaded.");
222
+ if (!hostAllowed(url.hostname, allowedHosts)) throw refuse(url, "The URL host is not in the allowed hosts list.");
223
+ }
224
+ /**
225
+ * Waits for `work`, or rejects with the abort reason when `signal` aborts.
226
+ * The handlers are attached to `work` first, so that a later rejection of
227
+ * `work` is always handled: an unhandled rejection ends a Node process in
228
+ * the default mode.
229
+ */
230
+ function withDeadline(work, signal) {
231
+ return new Promise((resolve, reject) => {
232
+ const onAbort = () => reject(signal.reason);
233
+ work.then(resolve, reject).finally(() => {
234
+ signal.removeEventListener("abort", onAbort);
235
+ });
236
+ if (signal.aborted) return onAbort();
237
+ signal.addEventListener("abort", onAbort, { once: true });
238
+ });
239
+ }
240
+ async function requestPinned(modules, url, addresses, signal, ca) {
241
+ const lookup = (_hostname, options, callback) => {
242
+ const wanted = typeof options === "number" ? options : options?.family;
243
+ const available = wanted === 4 || wanted === 6 ? addresses.filter((a) => a.family === wanted) : addresses;
244
+ if (available.length === 0) callback(refuse(url, "No checked address is available for this URL."), "", 4);
245
+ else if (typeof options === "object" && options?.all) callback(null, available);
246
+ else callback(null, available[0].address, available[0].family);
247
+ };
248
+ const isHttps = url.protocol === "https:";
249
+ const transport = isHttps ? modules.https : modules.http;
250
+ const agent = isHttps ? new modules.https.Agent({
251
+ keepAlive: false,
252
+ maxCachedSessions: 0
253
+ }) : new modules.http.Agent({ keepAlive: false });
254
+ const hostname = url.hostname.replace(/^\[|\]$/g, "");
255
+ return new Promise((resolve, reject) => {
256
+ const request = transport.request({
257
+ protocol: url.protocol,
258
+ hostname,
259
+ servername: isHttps && modules.net.isIP(hostname) === 0 ? hostname.replace(/\.$/, "") : void 0,
260
+ port: url.port || (isHttps ? 443 : 80),
261
+ path: url.pathname + url.search,
262
+ method: "GET",
263
+ headers: {
264
+ "accept-encoding": "identity",
265
+ "user-agent": USER_AGENT
266
+ },
267
+ lookup,
268
+ agent,
269
+ signal,
270
+ ...isHttps && ca !== void 0 ? { ca } : {}
271
+ }, (response) => {
272
+ response.once("close", () => agent.destroy());
273
+ resolve(response);
274
+ });
275
+ request.on("error", (error) => {
276
+ agent.destroy();
277
+ reject(error);
278
+ });
279
+ request.once("upgrade", (_response, socket) => {
280
+ socket.destroy();
281
+ agent.destroy();
282
+ reject(refuse(url, "Protocol upgrade refused."));
283
+ });
284
+ request.end();
285
+ });
286
+ }
287
+ async function readBody$1(url, response, maxBytes, budget) {
288
+ const tooLarge = () => refuse(url, `The response is larger than the ${maxBytes}-byte limit.`);
289
+ const overBudget = () => refuse(url, `The downloads are larger than the ${budget.limit}-byte total limit.`);
290
+ const declared = Number(response.headers["content-length"]);
291
+ if (Number.isFinite(declared) && declared > maxBytes) throw tooLarge();
292
+ if (Number.isFinite(declared) && declared > budget.remaining) throw overBudget();
293
+ const encoding = response.headers["content-encoding"];
294
+ if (encoding && encoding !== "identity") throw refuse(url, "Compressed responses are not accepted.");
295
+ const chunks = [];
296
+ let total = 0;
297
+ for await (const chunk of response) {
298
+ const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
299
+ total += buffer.byteLength;
300
+ if (total > maxBytes) throw tooLarge();
301
+ budget.remaining -= buffer.byteLength;
302
+ if (budget.remaining < 0) throw overBudget();
303
+ chunks.push(buffer);
304
+ }
305
+ return new Uint8Array(Buffer.concat(chunks, total));
306
+ }
307
+ async function downloadOne(original, options, internals, outer, budget) {
308
+ const modules = await loadNodeModules().catch((error) => {
309
+ throw refuse(original, "URL download needs Node.js networking modules, which are not available here.", `loading them failed: ${describeError(error)}. On a runtime without them, set urlDownload to "disabled" or to your own download function`);
310
+ });
311
+ defaultPolicy ??= buildAddressPolicy(modules.net);
312
+ const isPublic = internals.isPublicAddress ?? defaultPolicy;
313
+ const resolveHost = internals.resolveHost ?? ((hostname) => modules.dns.lookup(hostname, {
314
+ all: true,
315
+ verbatim: true
316
+ }));
317
+ let url = original;
318
+ const controller = new AbortController();
319
+ const timer = setTimeout(() => controller.abort(refuse(url, `The download timed out after ${options.timeoutMs} ms (timeoutMs).`)), options.timeoutMs);
320
+ const onOuterAbort = () => controller.abort(outer.reason);
321
+ if (outer.aborted) onOuterAbort();
322
+ else outer.addEventListener("abort", onOuterAbort, { once: true });
323
+ const { signal } = controller;
324
+ try {
325
+ for (let hop = 0;; hop++) {
326
+ signal.throwIfAborted();
327
+ checkUrl(url, options.allowedHosts);
328
+ const hostname = url.hostname.replace(/^\[|\]$/g, "");
329
+ const literalFamily = modules.net.isIP(hostname);
330
+ let addresses;
331
+ try {
332
+ signal.throwIfAborted();
333
+ addresses = literalFamily ? [{
334
+ address: hostname,
335
+ family: literalFamily
336
+ }] : await withDeadline(resolveHost(hostname), signal);
337
+ } catch (error) {
338
+ if (signal.aborted) throw signal.reason;
339
+ throw refuse(url, HOST_REFUSED, `DNS lookup failed: ${describeError(error)}`);
340
+ }
341
+ const verdicts = await Promise.all(addresses.map(async ({ address, family }) => (family === 4 || family === 6) && await isPublic(address) === true));
342
+ const rejected = addresses.filter((_address, i) => !verdicts[i]);
343
+ if (addresses.length === 0 || rejected.length > 0) throw refuse(url, HOST_REFUSED, addresses.length === 0 ? "DNS lookup returned no addresses" : `non-public address: ${rejected.map((a) => a.address).join(", ")}`);
344
+ let response;
345
+ try {
346
+ response = await requestPinned(modules, url, addresses, signal, internals.ca);
347
+ } catch (error) {
348
+ if (signal.aborted) throw signal.reason;
349
+ if (DownloadError.isInstance(error)) throw error;
350
+ throw refuse(url, DOWNLOAD_FAILED, describeError(error));
351
+ }
352
+ try {
353
+ const status = response.statusCode ?? 0;
354
+ if (REDIRECT_STATUSES.has(status)) {
355
+ if (hop >= options.maxRedirects) throw refuse(url, `Too many redirects: the limit is ${options.maxRedirects} (maxRedirects).`);
356
+ const location = response.headers.location;
357
+ if (!location) throw refuse(url, "Redirect without a location.");
358
+ let next;
359
+ try {
360
+ next = new URL(location, url);
361
+ } catch (error) {
362
+ throw refuse(url, "Redirect to an invalid URL.", `Location ${JSON.stringify(location.slice(0, 200))}: ${describeError(error)}`);
363
+ }
364
+ if (url.protocol === "https:" && next.protocol === "http:") throw refuse(url, "A redirect from https to http is refused.");
365
+ url = next;
366
+ continue;
367
+ }
368
+ if (status < 200 || status >= 300) throw refuse(url, `The server answered with HTTP status ${status}.`, response.statusMessage, status);
369
+ return {
370
+ data: await readBody$1(url, response, options.maxBytes, budget),
371
+ mediaType: response.headers["content-type"] || void 0
372
+ };
373
+ } catch (error) {
374
+ if (signal.aborted) throw signal.reason;
375
+ if (DownloadError.isInstance(error)) throw error;
376
+ throw refuse(url, DOWNLOAD_FAILED, describeError(error));
377
+ } finally {
378
+ response.destroy();
379
+ }
380
+ }
381
+ } finally {
382
+ clearTimeout(timer);
383
+ outer.removeEventListener("abort", onOuterAbort);
384
+ controller.abort();
385
+ }
386
+ }
387
+ const MAX_TIMEOUT_MS = 2147483647;
388
+ /** Returns `value` (or `fallback`) if it is an integer from `min` to `max`. */
389
+ function integerOption(name, value, fallback, min, max = Number.MAX_SAFE_INTEGER) {
390
+ const result = value ?? fallback;
391
+ if (!Number.isSafeInteger(result) || result < min || result > max) {
392
+ const range = max === Number.MAX_SAFE_INTEGER ? `an integer of at least ${min}` : `an integer from ${min} to ${max}`;
393
+ throw new Error(`urlDownload.${name} must be ${range}, got ${describeValue(value)}`);
394
+ }
395
+ return result;
396
+ }
397
+ const OPTION_NAMES = {
398
+ allowedHosts: true,
399
+ maxBytes: true,
400
+ timeoutMs: true,
401
+ maxRedirects: true,
402
+ maxDownloads: true,
403
+ maxTotalBytes: true
404
+ };
405
+ function checkOptionsObject(options) {
406
+ if (typeof options !== "object" || options === null || Array.isArray(options)) throw new Error(`urlDownload options must be an object, got ${describeValue(options)}`);
407
+ }
408
+ function checkOptionNames(options) {
409
+ checkOptionsObject(options);
410
+ for (const name of Object.keys(options)) if (!Object.prototype.hasOwnProperty.call(OPTION_NAMES, name)) throw new Error(`urlDownload has an unknown option ${describeValue(name)}; the valid options are ${Object.keys(OPTION_NAMES).join(", ")}`);
411
+ }
412
+ /** @internal Factory with test seams; use {@link createSafeUrlDownload}. */
413
+ function createGuardedUrlDownload(options = {}, internals = {}) {
414
+ checkOptionNames(options);
415
+ const resolved = {
416
+ allowedHosts: normalizeAllowedHosts(options.allowedHosts),
417
+ maxBytes: integerOption("maxBytes", options.maxBytes, DEFAULT_MAX_BYTES, 1),
418
+ timeoutMs: integerOption("timeoutMs", options.timeoutMs, DEFAULT_TIMEOUT_MS, 1, MAX_TIMEOUT_MS),
419
+ maxRedirects: integerOption("maxRedirects", options.maxRedirects, DEFAULT_MAX_REDIRECTS, 0),
420
+ maxDownloads: integerOption("maxDownloads", options.maxDownloads, DEFAULT_MAX_DOWNLOADS, 1),
421
+ maxTotalBytes: integerOption("maxTotalBytes", options.maxTotalBytes, DEFAULT_MAX_TOTAL_BYTES, 1)
422
+ };
423
+ const downloadAll = async (requests, runSignal) => {
424
+ const batch = new AbortController();
425
+ const onRunAbort = () => batch.abort(runSignal?.reason);
426
+ if (runSignal?.aborted) onRunAbort();
427
+ else runSignal?.addEventListener("abort", onRunAbort, { once: true });
428
+ try {
429
+ const pending = /* @__PURE__ */ new Map();
430
+ for (const request of requests) if (!leftToAiSdk(request)) pending.set(request.url.href, request.url);
431
+ if (pending.size > resolved.maxDownloads) throw refuse([...pending.values()][resolved.maxDownloads], `A model call can have at most ${resolved.maxDownloads} URL downloads; this one has ${pending.size}.`);
432
+ const budget = {
433
+ remaining: resolved.maxTotalBytes,
434
+ limit: resolved.maxTotalBytes
435
+ };
436
+ const downloads = new Map([...pending].map(([href, url]) => [href, downloadOne(url, resolved, internals, batch.signal, budget).catch((error) => {
437
+ batch.abort(error);
438
+ throw error;
439
+ })]));
440
+ return await Promise.all(requests.map((request) => leftToAiSdk(request) ? null : downloads.get(request.url.href)));
441
+ } finally {
442
+ runSignal?.removeEventListener("abort", onRunAbort);
443
+ batch.abort();
444
+ }
445
+ };
446
+ return Object.assign((requests) => downloadAll(requests), { forRun: (signal) => (requests) => downloadAll(requests, signal) });
447
+ }
448
+ /**
449
+ * @internal Resolves BuiltInAgent's `urlDownload` setting once, so that an
450
+ * invalid setting fails when the agent is constructed. The result gives the
451
+ * download function for one run; the default downloader stops when the run
452
+ * is aborted.
453
+ */
454
+ function resolveUrlDownloadSetting(setting) {
455
+ if (setting === "disabled") return () => disabledUrlDownload;
456
+ if (typeof setting === "function") return () => setting;
457
+ if (setting === void 0 || setting === null) return createGuardedUrlDownload().forRun;
458
+ if (typeof setting === "object" && !Array.isArray(setting)) return createGuardedUrlDownload(setting).forRun;
459
+ throw new Error(`urlDownload must be "disabled", an options object or a download function, got ${describeValue(setting)}`);
460
+ }
461
+ /**
462
+ * Creates an AI SDK download function (`experimental_download`) that only
463
+ * fetches public internet addresses, with the same checks and limits as
464
+ * BuiltInAgent's default downloader. Pass it to `streamText` yourself when
465
+ * you use BuiltInAgent's AI SDK factory mode. Create it in the factory with
466
+ * the run's abort signal, so that an aborted run stops its downloads:
467
+ *
468
+ * ```ts
469
+ * import { createSafeUrlDownload } from "@copilotkit/runtime/v2";
470
+ *
471
+ * factory: (ctx) =>
472
+ * streamText({
473
+ * model,
474
+ * messages,
475
+ * abortSignal: ctx.abortSignal,
476
+ * experimental_download: createSafeUrlDownload({ signal: ctx.abortSignal }),
477
+ * }),
478
+ * ```
479
+ *
480
+ * Invalid options throw here, when the function is created.
481
+ */
482
+ function createSafeUrlDownload(options = {}) {
483
+ checkOptionsObject(options);
484
+ const { signal, ...downloadOptions } = options;
485
+ if (signal !== void 0 && !(signal instanceof AbortSignal)) throw new Error(`urlDownload signal must be an AbortSignal, got ${describeValue(signal)}`);
486
+ const download = createGuardedUrlDownload(downloadOptions);
487
+ return signal ? download.forRun(signal) : download;
488
+ }
489
+ /**
490
+ * A download function that never fetches from the network. URLs that the
491
+ * model takes as-is and `data:` URLs are left to the AI SDK; any other URL,
492
+ * whatever its scheme, fails the run.
493
+ */
494
+ const disabledUrlDownload = async (requests) => requests.map((request) => {
495
+ if (leftToAiSdk(request)) return null;
496
+ throw refuse(request.url, "Server-side URL download is disabled (urlDownload: \"disabled\").");
497
+ });
498
+
499
+ //#endregion
500
+ export { createSafeUrlDownload, logModelCallError, resolveUrlDownloadSetting };
501
+ //# sourceMappingURL=url-download.mjs.map