@axlsdk/axl 0.20.1 → 0.21.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.
package/dist/index.d.cts CHANGED
@@ -2127,6 +2127,8 @@ type OpenAICompatibleOptions = {
2127
2127
  /** API key or a per-request resolver (expiring tokens). See {@link ApiKeySource}. */
2128
2128
  apiKey?: ApiKeySource;
2129
2129
  baseUrl?: string;
2130
+ /** Permit a non-loopback HTTP endpoint for this provider instance. */
2131
+ dangerouslyAllowInsecureHttp?: boolean;
2130
2132
  /** Override the profile's auth header shape (e.g. Azure Entra bearer tokens). */
2131
2133
  authHeader?: AuthHeader;
2132
2134
  rateLimit?: RateLimitConfig;
@@ -2223,6 +2225,49 @@ type OpenAIModelResponse = {
2223
2225
  usage?: OpenAIUsage;
2224
2226
  };
2225
2227
 
2228
+ /**
2229
+ * MCP (Model Context Protocol) types for tool discovery and execution.
2230
+ */
2231
+ /** A tool definition discovered from an MCP server. */
2232
+ type McpToolDefinition = {
2233
+ name: string;
2234
+ description: string;
2235
+ inputSchema: unknown;
2236
+ };
2237
+ /** Configuration for connecting to an MCP server. */
2238
+ type McpServerConfig = {
2239
+ name: string;
2240
+ /** Command to spawn for stdio transport (e.g. "npx -y @modelcontextprotocol/server-fs") */
2241
+ command?: string;
2242
+ /** Arguments for the command */
2243
+ args?: string[];
2244
+ /** HTTP/SSE endpoint URI for HTTP transport */
2245
+ uri?: string;
2246
+ /** Allow this MCP server to use non-loopback HTTP. Prefer HTTPS. */
2247
+ dangerouslyAllowInsecureHttp?: boolean;
2248
+ /** Environment variables to pass to the spawned process */
2249
+ env?: Record<string, string>;
2250
+ };
2251
+ /** Result from calling an MCP tool. */
2252
+ type McpToolResult = {
2253
+ content: Array<{
2254
+ type: 'text';
2255
+ text: string;
2256
+ } | {
2257
+ type: 'image';
2258
+ data: string;
2259
+ mimeType: string;
2260
+ }>;
2261
+ isError?: boolean;
2262
+ };
2263
+ /** A connected MCP server with its discovered tools. */
2264
+ type McpServer = {
2265
+ name: string;
2266
+ tools: McpToolDefinition[];
2267
+ callTool(toolName: string, args: unknown): Promise<McpToolResult>;
2268
+ close(): Promise<void>;
2269
+ };
2270
+
2226
2271
  /** A pending human decision awaiting resolution. */
2227
2272
  type PendingDecision = {
2228
2273
  executionId: string;
@@ -2470,6 +2515,11 @@ type ProviderConfig = {
2470
2515
  * the common case. See {@link ApiKeySource}. */
2471
2516
  apiKey?: ApiKeySource;
2472
2517
  baseUrl?: string;
2518
+ /**
2519
+ * Allow a non-loopback HTTP endpoint for this provider. HTTP can expose
2520
+ * prompts and credentials in transit; prefer HTTPS whenever possible.
2521
+ */
2522
+ dangerouslyAllowInsecureHttp?: boolean;
2473
2523
  /** OpenAI-compatible presets only: override the profile auth header shape. */
2474
2524
  authHeader?: AuthHeader;
2475
2525
  /**
@@ -2482,13 +2532,6 @@ type ProviderConfig = {
2482
2532
  */
2483
2533
  rateLimit?: RateLimitConfig;
2484
2534
  };
2485
- /** MCP server configuration */
2486
- type McpServerConfig$1 = {
2487
- name: string;
2488
- command?: string;
2489
- uri?: string;
2490
- env?: Record<string, string>;
2491
- };
2492
2535
  /** Trace configuration */
2493
2536
  type TraceConfig = {
2494
2537
  enabled?: boolean;
@@ -2600,7 +2643,7 @@ type AxlConfig = {
2600
2643
  defaultProvider?: string;
2601
2644
  defaultModel?: string;
2602
2645
  mcp?: {
2603
- servers?: McpServerConfig$1[];
2646
+ servers?: McpServerConfig[];
2604
2647
  };
2605
2648
  state?: StateConfig;
2606
2649
  trace?: TraceConfig;
@@ -2693,47 +2736,6 @@ declare class ProviderRegistry {
2693
2736
  clearFactories(): void;
2694
2737
  }
2695
2738
 
2696
- /**
2697
- * MCP (Model Context Protocol) types for tool discovery and execution.
2698
- */
2699
- /** A tool definition discovered from an MCP server. */
2700
- type McpToolDefinition = {
2701
- name: string;
2702
- description: string;
2703
- inputSchema: unknown;
2704
- };
2705
- /** Configuration for connecting to an MCP server. */
2706
- type McpServerConfig = {
2707
- name: string;
2708
- /** Command to spawn for stdio transport (e.g. "npx -y @modelcontextprotocol/server-fs") */
2709
- command?: string;
2710
- /** Arguments for the command */
2711
- args?: string[];
2712
- /** HTTP/SSE endpoint URI for HTTP transport */
2713
- uri?: string;
2714
- /** Environment variables to pass to the spawned process */
2715
- env?: Record<string, string>;
2716
- };
2717
- /** Result from calling an MCP tool. */
2718
- type McpToolResult = {
2719
- content: Array<{
2720
- type: 'text';
2721
- text: string;
2722
- } | {
2723
- type: 'image';
2724
- data: string;
2725
- mimeType: string;
2726
- }>;
2727
- isError?: boolean;
2728
- };
2729
- /** A connected MCP server with its discovered tools. */
2730
- type McpServer = {
2731
- name: string;
2732
- tools: McpToolDefinition[];
2733
- callTool(toolName: string, args: unknown): Promise<McpToolResult>;
2734
- close(): Promise<void>;
2735
- };
2736
-
2737
2739
  /**
2738
2740
  * Manages connections to multiple MCP servers.
2739
2741
  * Discovers tools, filters by agent config, and routes tool calls.
@@ -4434,7 +4436,14 @@ declare function registerConditions(conditions: string[]): Promise<void>;
4434
4436
  * attempt-N text never leaks into attempt-N+1).
4435
4437
  * - `ask_end` clears the per-ask accumulator (memory hygiene).
4436
4438
  *
4437
- * Example (browser, consuming Studio's WS firehose):
4439
+ * SECURITY: "browser-safe" here means this module has no Node runtime
4440
+ * dependency. It does not redact or authorize the raw `AxlEvent` source.
4441
+ * Prompts, system messages, tool data, and traces should remain on the trusted
4442
+ * backend; public applications should relay an output-only DTO produced from a
4443
+ * server-side curated view. Use this helper only when the browser is authorized
4444
+ * to receive the underlying event stream.
4445
+ *
4446
+ * Example (trusted operator browser, consuming an authorized Studio WS firehose):
4438
4447
  *
4439
4448
  * ```ts
4440
4449
  * import { stringStreamFromEvents } from '@axlsdk/axl';
@@ -4813,6 +4822,7 @@ declare class OpenAIProvider extends OpenAICompatibleProvider {
4813
4822
  constructor(options?: {
4814
4823
  apiKey?: ApiKeySource;
4815
4824
  baseUrl?: string;
4825
+ dangerouslyAllowInsecureHttp?: boolean;
4816
4826
  rateLimit?: RateLimitConfig;
4817
4827
  });
4818
4828
  protected computeCost(model: string, usage: ProviderResponse['usage'], _reportedCost: number | undefined, context?: DirectOpenAIPricingContext): number | undefined;
@@ -4835,6 +4845,7 @@ declare class OpenAIResponsesProvider implements Provider {
4835
4845
  constructor(options?: {
4836
4846
  apiKey?: ApiKeySource;
4837
4847
  baseUrl?: string;
4848
+ dangerouslyAllowInsecureHttp?: boolean;
4838
4849
  rateLimit?: RateLimitConfig;
4839
4850
  });
4840
4851
  /** Resolve the API key for one request (supports an expiring-token callback). */
@@ -4885,6 +4896,7 @@ declare class AnthropicProvider implements Provider {
4885
4896
  constructor(options?: {
4886
4897
  apiKey?: ApiKeySource;
4887
4898
  baseUrl?: string;
4899
+ dangerouslyAllowInsecureHttp?: boolean;
4888
4900
  rateLimit?: RateLimitConfig;
4889
4901
  });
4890
4902
  /** Resolve the API key for one request (supports an expiring-token callback). */
@@ -4956,6 +4968,7 @@ declare class GeminiProvider implements Provider {
4956
4968
  constructor(options?: {
4957
4969
  apiKey?: ApiKeySource;
4958
4970
  baseUrl?: string;
4971
+ dangerouslyAllowInsecureHttp?: boolean;
4959
4972
  rateLimit?: RateLimitConfig;
4960
4973
  });
4961
4974
  /** Resolve the API key for one request (supports an expiring-token callback). */
@@ -5509,6 +5522,7 @@ declare class OpenAIEmbedder implements Embedder {
5509
5522
  apiKey?: string;
5510
5523
  model?: string;
5511
5524
  baseUrl?: string;
5525
+ dangerouslyAllowInsecureHttp?: boolean;
5512
5526
  dimensions?: number;
5513
5527
  });
5514
5528
  embed(texts: string[], signal?: AbortSignal): Promise<EmbedResult>;
package/dist/index.d.ts CHANGED
@@ -2127,6 +2127,8 @@ type OpenAICompatibleOptions = {
2127
2127
  /** API key or a per-request resolver (expiring tokens). See {@link ApiKeySource}. */
2128
2128
  apiKey?: ApiKeySource;
2129
2129
  baseUrl?: string;
2130
+ /** Permit a non-loopback HTTP endpoint for this provider instance. */
2131
+ dangerouslyAllowInsecureHttp?: boolean;
2130
2132
  /** Override the profile's auth header shape (e.g. Azure Entra bearer tokens). */
2131
2133
  authHeader?: AuthHeader;
2132
2134
  rateLimit?: RateLimitConfig;
@@ -2223,6 +2225,49 @@ type OpenAIModelResponse = {
2223
2225
  usage?: OpenAIUsage;
2224
2226
  };
2225
2227
 
2228
+ /**
2229
+ * MCP (Model Context Protocol) types for tool discovery and execution.
2230
+ */
2231
+ /** A tool definition discovered from an MCP server. */
2232
+ type McpToolDefinition = {
2233
+ name: string;
2234
+ description: string;
2235
+ inputSchema: unknown;
2236
+ };
2237
+ /** Configuration for connecting to an MCP server. */
2238
+ type McpServerConfig = {
2239
+ name: string;
2240
+ /** Command to spawn for stdio transport (e.g. "npx -y @modelcontextprotocol/server-fs") */
2241
+ command?: string;
2242
+ /** Arguments for the command */
2243
+ args?: string[];
2244
+ /** HTTP/SSE endpoint URI for HTTP transport */
2245
+ uri?: string;
2246
+ /** Allow this MCP server to use non-loopback HTTP. Prefer HTTPS. */
2247
+ dangerouslyAllowInsecureHttp?: boolean;
2248
+ /** Environment variables to pass to the spawned process */
2249
+ env?: Record<string, string>;
2250
+ };
2251
+ /** Result from calling an MCP tool. */
2252
+ type McpToolResult = {
2253
+ content: Array<{
2254
+ type: 'text';
2255
+ text: string;
2256
+ } | {
2257
+ type: 'image';
2258
+ data: string;
2259
+ mimeType: string;
2260
+ }>;
2261
+ isError?: boolean;
2262
+ };
2263
+ /** A connected MCP server with its discovered tools. */
2264
+ type McpServer = {
2265
+ name: string;
2266
+ tools: McpToolDefinition[];
2267
+ callTool(toolName: string, args: unknown): Promise<McpToolResult>;
2268
+ close(): Promise<void>;
2269
+ };
2270
+
2226
2271
  /** A pending human decision awaiting resolution. */
2227
2272
  type PendingDecision = {
2228
2273
  executionId: string;
@@ -2470,6 +2515,11 @@ type ProviderConfig = {
2470
2515
  * the common case. See {@link ApiKeySource}. */
2471
2516
  apiKey?: ApiKeySource;
2472
2517
  baseUrl?: string;
2518
+ /**
2519
+ * Allow a non-loopback HTTP endpoint for this provider. HTTP can expose
2520
+ * prompts and credentials in transit; prefer HTTPS whenever possible.
2521
+ */
2522
+ dangerouslyAllowInsecureHttp?: boolean;
2473
2523
  /** OpenAI-compatible presets only: override the profile auth header shape. */
2474
2524
  authHeader?: AuthHeader;
2475
2525
  /**
@@ -2482,13 +2532,6 @@ type ProviderConfig = {
2482
2532
  */
2483
2533
  rateLimit?: RateLimitConfig;
2484
2534
  };
2485
- /** MCP server configuration */
2486
- type McpServerConfig$1 = {
2487
- name: string;
2488
- command?: string;
2489
- uri?: string;
2490
- env?: Record<string, string>;
2491
- };
2492
2535
  /** Trace configuration */
2493
2536
  type TraceConfig = {
2494
2537
  enabled?: boolean;
@@ -2600,7 +2643,7 @@ type AxlConfig = {
2600
2643
  defaultProvider?: string;
2601
2644
  defaultModel?: string;
2602
2645
  mcp?: {
2603
- servers?: McpServerConfig$1[];
2646
+ servers?: McpServerConfig[];
2604
2647
  };
2605
2648
  state?: StateConfig;
2606
2649
  trace?: TraceConfig;
@@ -2693,47 +2736,6 @@ declare class ProviderRegistry {
2693
2736
  clearFactories(): void;
2694
2737
  }
2695
2738
 
2696
- /**
2697
- * MCP (Model Context Protocol) types for tool discovery and execution.
2698
- */
2699
- /** A tool definition discovered from an MCP server. */
2700
- type McpToolDefinition = {
2701
- name: string;
2702
- description: string;
2703
- inputSchema: unknown;
2704
- };
2705
- /** Configuration for connecting to an MCP server. */
2706
- type McpServerConfig = {
2707
- name: string;
2708
- /** Command to spawn for stdio transport (e.g. "npx -y @modelcontextprotocol/server-fs") */
2709
- command?: string;
2710
- /** Arguments for the command */
2711
- args?: string[];
2712
- /** HTTP/SSE endpoint URI for HTTP transport */
2713
- uri?: string;
2714
- /** Environment variables to pass to the spawned process */
2715
- env?: Record<string, string>;
2716
- };
2717
- /** Result from calling an MCP tool. */
2718
- type McpToolResult = {
2719
- content: Array<{
2720
- type: 'text';
2721
- text: string;
2722
- } | {
2723
- type: 'image';
2724
- data: string;
2725
- mimeType: string;
2726
- }>;
2727
- isError?: boolean;
2728
- };
2729
- /** A connected MCP server with its discovered tools. */
2730
- type McpServer = {
2731
- name: string;
2732
- tools: McpToolDefinition[];
2733
- callTool(toolName: string, args: unknown): Promise<McpToolResult>;
2734
- close(): Promise<void>;
2735
- };
2736
-
2737
2739
  /**
2738
2740
  * Manages connections to multiple MCP servers.
2739
2741
  * Discovers tools, filters by agent config, and routes tool calls.
@@ -4434,7 +4436,14 @@ declare function registerConditions(conditions: string[]): Promise<void>;
4434
4436
  * attempt-N text never leaks into attempt-N+1).
4435
4437
  * - `ask_end` clears the per-ask accumulator (memory hygiene).
4436
4438
  *
4437
- * Example (browser, consuming Studio's WS firehose):
4439
+ * SECURITY: "browser-safe" here means this module has no Node runtime
4440
+ * dependency. It does not redact or authorize the raw `AxlEvent` source.
4441
+ * Prompts, system messages, tool data, and traces should remain on the trusted
4442
+ * backend; public applications should relay an output-only DTO produced from a
4443
+ * server-side curated view. Use this helper only when the browser is authorized
4444
+ * to receive the underlying event stream.
4445
+ *
4446
+ * Example (trusted operator browser, consuming an authorized Studio WS firehose):
4438
4447
  *
4439
4448
  * ```ts
4440
4449
  * import { stringStreamFromEvents } from '@axlsdk/axl';
@@ -4813,6 +4822,7 @@ declare class OpenAIProvider extends OpenAICompatibleProvider {
4813
4822
  constructor(options?: {
4814
4823
  apiKey?: ApiKeySource;
4815
4824
  baseUrl?: string;
4825
+ dangerouslyAllowInsecureHttp?: boolean;
4816
4826
  rateLimit?: RateLimitConfig;
4817
4827
  });
4818
4828
  protected computeCost(model: string, usage: ProviderResponse['usage'], _reportedCost: number | undefined, context?: DirectOpenAIPricingContext): number | undefined;
@@ -4835,6 +4845,7 @@ declare class OpenAIResponsesProvider implements Provider {
4835
4845
  constructor(options?: {
4836
4846
  apiKey?: ApiKeySource;
4837
4847
  baseUrl?: string;
4848
+ dangerouslyAllowInsecureHttp?: boolean;
4838
4849
  rateLimit?: RateLimitConfig;
4839
4850
  });
4840
4851
  /** Resolve the API key for one request (supports an expiring-token callback). */
@@ -4885,6 +4896,7 @@ declare class AnthropicProvider implements Provider {
4885
4896
  constructor(options?: {
4886
4897
  apiKey?: ApiKeySource;
4887
4898
  baseUrl?: string;
4899
+ dangerouslyAllowInsecureHttp?: boolean;
4888
4900
  rateLimit?: RateLimitConfig;
4889
4901
  });
4890
4902
  /** Resolve the API key for one request (supports an expiring-token callback). */
@@ -4956,6 +4968,7 @@ declare class GeminiProvider implements Provider {
4956
4968
  constructor(options?: {
4957
4969
  apiKey?: ApiKeySource;
4958
4970
  baseUrl?: string;
4971
+ dangerouslyAllowInsecureHttp?: boolean;
4959
4972
  rateLimit?: RateLimitConfig;
4960
4973
  });
4961
4974
  /** Resolve the API key for one request (supports an expiring-token callback). */
@@ -5509,6 +5522,7 @@ declare class OpenAIEmbedder implements Embedder {
5509
5522
  apiKey?: string;
5510
5523
  model?: string;
5511
5524
  baseUrl?: string;
5525
+ dangerouslyAllowInsecureHttp?: boolean;
5512
5526
  dimensions?: number;
5513
5527
  });
5514
5528
  embed(texts: string[], signal?: AbortSignal): Promise<EmbedResult>;
package/dist/index.js CHANGED
@@ -496,7 +496,7 @@ async function fetchWithRetry(input, init, opts) {
496
496
  for (let attempt = 0; ; attempt++) {
497
497
  let res;
498
498
  try {
499
- res = await fetch(input, init);
499
+ res = await fetch(input, { ...init, redirect: "manual" });
500
500
  } catch (err) {
501
501
  if (isAbortError2(err, init?.signal ?? void 0)) throw err;
502
502
  if (attempt >= maxRetries) {
@@ -702,6 +702,38 @@ function isBuiltinTablePricingEligible(profile, context) {
702
702
  return typeof effectiveTier === "string" && policy.supportedServiceTiers.includes(effectiveTier);
703
703
  }
704
704
 
705
+ // src/http-transport.ts
706
+ function assertSafeProviderBaseUrl(baseUrl, surface, dangerouslyAllowInsecureHttp = false) {
707
+ assertSafeHttpEndpoint(baseUrl, surface, dangerouslyAllowInsecureHttp, "prompts and credentials");
708
+ }
709
+ function assertSafeHttpEndpoint(endpoint, surface, dangerouslyAllowInsecureHttp = false, exposedData = "sensitive data") {
710
+ let url;
711
+ try {
712
+ url = new URL(endpoint);
713
+ } catch {
714
+ throw unsafeTransportError(surface, "a valid absolute HTTP(S) URL", exposedData);
715
+ }
716
+ if (url.protocol === "https:") return;
717
+ if (url.protocol !== "http:") {
718
+ throw unsafeTransportError(surface, "an HTTPS URL", exposedData);
719
+ }
720
+ if (dangerouslyAllowInsecureHttp || isLiteralLoopbackHost(url.hostname)) return;
721
+ throw unsafeTransportError(
722
+ surface,
723
+ "an HTTPS URL, or set dangerouslyAllowInsecureHttp: true only for a deliberately insecure endpoint",
724
+ exposedData
725
+ );
726
+ }
727
+ function isLiteralLoopbackHost(hostname) {
728
+ return hostname === "localhost" || hostname === "localhost." || /^127(?:\.\d{1,3}){3}$/.test(hostname) || hostname === "[::1]";
729
+ }
730
+ function unsafeTransportError(surface, remediation, exposedData) {
731
+ return new AxlError(
732
+ "UNSAFE_TRANSPORT",
733
+ `${surface} requires ${remediation}. Remote HTTP can expose ${exposedData} in transit.`
734
+ );
735
+ }
736
+
705
737
  // src/providers/openai-compatible.ts
706
738
  function resolvePerModel(value, model, fallback) {
707
739
  if (value === void 0) return fallback;
@@ -845,6 +877,11 @@ var OpenAICompatibleProvider = class {
845
877
  const envBase = p.envBaseUrl ? process.env[p.envBaseUrl] : void 0;
846
878
  const explicitBase = options.baseUrl ?? envBase;
847
879
  this.baseUrl = (explicitBase ?? p.defaultBaseUrl).replace(/\/$/, "");
880
+ assertSafeProviderBaseUrl(
881
+ this.baseUrl,
882
+ `${p.label ?? p.name} provider`,
883
+ options.dangerouslyAllowInsecureHttp
884
+ );
848
885
  this.governor = options.rateLimit ? new RateLimiter(options.rateLimit) : void 0;
849
886
  const label = p.label ?? p.name;
850
887
  if (p.requireExplicitBaseUrl && explicitBase === void 0) {
@@ -1745,6 +1782,11 @@ var OpenAIResponsesProvider = class {
1745
1782
  constructor(options = {}) {
1746
1783
  this.apiKeySource = options.apiKey ?? process.env.OPENAI_API_KEY ?? "";
1747
1784
  this.baseUrl = (options.baseUrl ?? process.env.OPENAI_BASE_URL ?? "https://api.openai.com/v1").replace(/\/$/, "");
1785
+ assertSafeProviderBaseUrl(
1786
+ this.baseUrl,
1787
+ "OpenAI Responses provider",
1788
+ options.dangerouslyAllowInsecureHttp
1789
+ );
1748
1790
  this.governor = options.rateLimit ? new RateLimiter(options.rateLimit) : void 0;
1749
1791
  if (typeof this.apiKeySource === "string" && !this.apiKeySource) {
1750
1792
  throw new Error("OpenAI API key is required. Set OPENAI_API_KEY or pass apiKey in options.");
@@ -2500,6 +2542,11 @@ var AnthropicProvider = class {
2500
2542
  constructor(options = {}) {
2501
2543
  this.apiKeySource = options.apiKey ?? process.env.ANTHROPIC_API_KEY ?? "";
2502
2544
  this.baseUrl = (options.baseUrl ?? "https://api.anthropic.com/v1").replace(/\/$/, "");
2545
+ assertSafeProviderBaseUrl(
2546
+ this.baseUrl,
2547
+ "Anthropic provider",
2548
+ options.dangerouslyAllowInsecureHttp
2549
+ );
2503
2550
  this.governor = options.rateLimit ? new RateLimiter(options.rateLimit) : void 0;
2504
2551
  if (typeof this.apiKeySource === "string" && !this.apiKeySource) {
2505
2552
  throw new Error(
@@ -3190,6 +3237,11 @@ var GeminiProvider = class {
3190
3237
  /\/$/,
3191
3238
  ""
3192
3239
  );
3240
+ assertSafeProviderBaseUrl(
3241
+ this.baseUrl,
3242
+ "Google provider",
3243
+ options.dangerouslyAllowInsecureHttp
3244
+ );
3193
3245
  this.governor = options.rateLimit ? new RateLimiter(options.rateLimit) : void 0;
3194
3246
  if (typeof this.apiKeySource === "string" && !this.apiKeySource) {
3195
3247
  throw new Error("Google API key is required. Set GOOGLE_API_KEY or pass apiKey in options.");
@@ -4077,6 +4129,7 @@ var builtinFactories = {
4077
4129
  return new OpenAIProvider({
4078
4130
  apiKey: opts.apiKey,
4079
4131
  baseUrl: opts.baseUrl,
4132
+ dangerouslyAllowInsecureHttp: opts.dangerouslyAllowInsecureHttp,
4080
4133
  rateLimit: opts.rateLimit
4081
4134
  });
4082
4135
  },
@@ -4089,6 +4142,7 @@ var builtinFactories = {
4089
4142
  return new OpenAIResponsesProvider({
4090
4143
  apiKey: opts.apiKey,
4091
4144
  baseUrl: opts.baseUrl,
4145
+ dangerouslyAllowInsecureHttp: opts.dangerouslyAllowInsecureHttp,
4092
4146
  rateLimit: opts.rateLimit
4093
4147
  });
4094
4148
  },
@@ -4097,6 +4151,7 @@ var builtinFactories = {
4097
4151
  return new AnthropicProvider({
4098
4152
  apiKey: opts.apiKey,
4099
4153
  baseUrl: opts.baseUrl,
4154
+ dangerouslyAllowInsecureHttp: opts.dangerouslyAllowInsecureHttp,
4100
4155
  rateLimit: opts.rateLimit
4101
4156
  });
4102
4157
  },
@@ -4105,6 +4160,7 @@ var builtinFactories = {
4105
4160
  return new GeminiProvider({
4106
4161
  apiKey: opts.apiKey,
4107
4162
  baseUrl: opts.baseUrl,
4163
+ dangerouslyAllowInsecureHttp: opts.dangerouslyAllowInsecureHttp,
4108
4164
  rateLimit: opts.rateLimit
4109
4165
  });
4110
4166
  }
@@ -4116,6 +4172,7 @@ function presetFactory(profile) {
4116
4172
  profile,
4117
4173
  apiKey: opts.apiKey,
4118
4174
  baseUrl: opts.baseUrl,
4175
+ dangerouslyAllowInsecureHttp: opts.dangerouslyAllowInsecureHttp,
4119
4176
  authHeader: opts.authHeader,
4120
4177
  rateLimit: opts.rateLimit
4121
4178
  });
@@ -11126,6 +11183,14 @@ var HttpMcpClient = class {
11126
11183
  this.config = config;
11127
11184
  this.name = config.name;
11128
11185
  this.baseUrl = (config.uri ?? "").replace(/\/$/, "");
11186
+ if (this.baseUrl) {
11187
+ assertSafeHttpEndpoint(
11188
+ this.baseUrl,
11189
+ `MCP server "${this.name}"`,
11190
+ config.dangerouslyAllowInsecureHttp,
11191
+ "tool arguments and results"
11192
+ );
11193
+ }
11129
11194
  }
11130
11195
  name;
11131
11196
  tools = [];
@@ -11155,7 +11220,9 @@ var HttpMcpClient = class {
11155
11220
  method: "POST",
11156
11221
  headers: { "Content-Type": "application/json" },
11157
11222
  body: JSON.stringify(request),
11158
- signal: AbortSignal.timeout(timeoutMs)
11223
+ signal: AbortSignal.timeout(timeoutMs),
11224
+ // Tool calls can be non-idempotent: never forward or retry their body.
11225
+ redirect: "manual"
11159
11226
  });
11160
11227
  if (!res.ok) {
11161
11228
  throw new Error(`MCP HTTP error (${res.status}): ${await res.text()}`);
@@ -13947,6 +14014,11 @@ var OpenAIEmbedder = class {
13947
14014
  }
13948
14015
  this.model = options.model ?? "text-embedding-3-small";
13949
14016
  this.baseUrl = options.baseUrl ?? "https://api.openai.com";
14017
+ assertSafeProviderBaseUrl(
14018
+ this.baseUrl,
14019
+ "OpenAI embedder",
14020
+ options.dangerouslyAllowInsecureHttp
14021
+ );
13950
14022
  this.dimensions = options.dimensions ?? 1536;
13951
14023
  }
13952
14024
  async embed(texts, signal) {