@omnicross/core 0.2.0 → 0.3.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 (119) hide show
  1. package/dist/{BuiltinToolExecutor-CS2WpXhM.d.cts → BuiltinToolExecutor-BHgH-EaZ.d.cts} +25 -2
  2. package/dist/{BuiltinToolExecutor-BluWyeob.d.ts → BuiltinToolExecutor-Bi1LmiTP.d.ts} +25 -2
  3. package/dist/{CompletionService-BiJqftc-.d.cts → CompletionService-BniP7j88.d.cts} +2 -2
  4. package/dist/{CompletionService-NXN_Av5W.d.ts → CompletionService-BqrKPwfA.d.ts} +2 -2
  5. package/dist/{ProviderProxy-CgIcCVwk.d.cts → ProviderProxy-Bz_nkOwq.d.cts} +1 -1
  6. package/dist/{ProviderProxy-DYoY5XoT.d.ts → ProviderProxy-Ckr6oTrE.d.ts} +1 -1
  7. package/dist/auth/GeminiCodeAssistProjectResolver.cjs +2 -2
  8. package/dist/auth/GeminiCodeAssistProjectResolver.js +1 -1
  9. package/dist/{chunk-FJNKXOWE.js → chunk-2C3TTBS7.js} +4 -4
  10. package/dist/{chunk-NZYN7C3P.cjs → chunk-2RCCLQYV.cjs} +53 -53
  11. package/dist/{chunk-CDHS2QDC.js → chunk-4PFWFODB.js} +53 -53
  12. package/dist/{chunk-OST5RJOJ.cjs → chunk-4Z3ZLLC2.cjs} +13 -7
  13. package/dist/chunk-7RJI3NDI.cjs +236 -0
  14. package/dist/chunk-BTBEJRGL.cjs +781 -0
  15. package/dist/chunk-DBBR6RHF.js +236 -0
  16. package/dist/chunk-DXWFBBSK.js +781 -0
  17. package/dist/chunk-E4QHVXV5.cjs +118 -0
  18. package/dist/chunk-L7O2YQ5O.js +386 -0
  19. package/dist/{chunk-WSJE42SG.js → chunk-LKDAN4D7.js} +3684 -2462
  20. package/dist/{chunk-DEIUR2TH.js → chunk-LQYS2N47.js} +12 -8
  21. package/dist/chunk-MZEGQSKQ.js +118 -0
  22. package/dist/chunk-PTU7SXM3.cjs +386 -0
  23. package/dist/{chunk-CTKM773J.cjs → chunk-UPQIWJIE.cjs} +12 -8
  24. package/dist/{chunk-CFSGYFOZ.js → chunk-VL5TUDTM.js} +7 -1
  25. package/dist/{chunk-7B56AJBB.cjs → chunk-VSYQ6XYN.cjs} +2233 -1011
  26. package/dist/{chunk-TVYA5JSQ.cjs → chunk-ZAPN7XA6.cjs} +5 -5
  27. package/dist/completion/BuiltinToolExecutor.cjs +2 -2
  28. package/dist/completion/BuiltinToolExecutor.d.cts +3 -1
  29. package/dist/completion/BuiltinToolExecutor.d.ts +3 -1
  30. package/dist/completion/BuiltinToolExecutor.js +1 -1
  31. package/dist/completion/CompletionService.cjs +11 -10
  32. package/dist/completion/CompletionService.d.cts +6 -3
  33. package/dist/completion/CompletionService.d.ts +6 -3
  34. package/dist/completion/CompletionService.js +10 -9
  35. package/dist/completion.cjs +11 -10
  36. package/dist/completion.d.cts +6 -3
  37. package/dist/completion.d.ts +6 -3
  38. package/dist/completion.js +10 -9
  39. package/dist/egress-I46O_p5L.d.cts +126 -0
  40. package/dist/egress-I46O_p5L.d.ts +126 -0
  41. package/dist/frontends-Doz0RaWu.d.cts +97 -0
  42. package/dist/frontends-Doz0RaWu.d.ts +97 -0
  43. package/dist/image-generation.cjs +2 -2
  44. package/dist/image-generation.d.cts +7 -4
  45. package/dist/image-generation.d.ts +7 -4
  46. package/dist/image-generation.js +1 -1
  47. package/dist/index.cjs +25 -10
  48. package/dist/index.d.cts +12 -8
  49. package/dist/index.d.ts +12 -8
  50. package/dist/index.js +24 -9
  51. package/dist/openai-operation.d.cts +4 -1
  52. package/dist/openai-operation.d.ts +4 -1
  53. package/dist/outbound-api/routeResolver.d.cts +9 -5
  54. package/dist/outbound-api/routeResolver.d.ts +9 -5
  55. package/dist/outbound-api/subscriptionRegistryPort.d.cts +4 -1
  56. package/dist/outbound-api/subscriptionRegistryPort.d.ts +4 -1
  57. package/dist/outbound-api/types.d.cts +8 -4
  58. package/dist/outbound-api/types.d.ts +8 -4
  59. package/dist/outbound-api.cjs +25 -10
  60. package/dist/outbound-api.d.cts +117 -8
  61. package/dist/outbound-api.d.ts +117 -8
  62. package/dist/outbound-api.js +24 -9
  63. package/dist/pipeline/AccountAllowanceScheduling.d.cts +8 -4
  64. package/dist/pipeline/AccountAllowanceScheduling.d.ts +8 -4
  65. package/dist/pipeline/upstreamFetch.cjs +2 -2
  66. package/dist/pipeline/upstreamFetch.js +1 -1
  67. package/dist/ports.d.cts +8 -4
  68. package/dist/ports.d.ts +8 -4
  69. package/dist/provider-proxy/ProviderProxy.cjs +11 -10
  70. package/dist/provider-proxy/ProviderProxy.d.cts +5 -2
  71. package/dist/provider-proxy/ProviderProxy.d.ts +5 -2
  72. package/dist/provider-proxy/ProviderProxy.js +10 -9
  73. package/dist/provider-proxy/ingress/providerProxyShared.cjs +13 -10
  74. package/dist/provider-proxy/ingress/providerProxyShared.d.cts +22 -3
  75. package/dist/provider-proxy/ingress/providerProxyShared.d.ts +22 -3
  76. package/dist/provider-proxy/ingress/providerProxyShared.js +12 -9
  77. package/dist/provider-proxy/types.d.cts +4 -1
  78. package/dist/provider-proxy/types.d.ts +4 -1
  79. package/dist/provider-proxy.cjs +11 -10
  80. package/dist/provider-proxy.d.cts +10 -6
  81. package/dist/provider-proxy.d.ts +10 -6
  82. package/dist/provider-proxy.js +10 -9
  83. package/dist/proxy-UZTtjPZx.d.cts +18 -0
  84. package/dist/proxy-UZTtjPZx.d.ts +18 -0
  85. package/dist/{routeResolver-rpKQLyDO.d.cts → routeResolver-Da0yvkL1.d.cts} +2 -2
  86. package/dist/{routeResolver-CTCcSHWu.d.ts → routeResolver-STwMz_G4.d.ts} +2 -2
  87. package/dist/runtime-5NCT3J3T.cjs +8 -0
  88. package/dist/runtime-JTHUWCBM.js +8 -0
  89. package/dist/runtime-t8AZacFF.d.cts +233 -0
  90. package/dist/runtime-t8AZacFF.d.ts +233 -0
  91. package/dist/search/api.cjs +766 -0
  92. package/dist/search/api.d.cts +385 -0
  93. package/dist/search/api.d.ts +385 -0
  94. package/dist/search/api.js +766 -0
  95. package/dist/search/http.cjs +37 -0
  96. package/dist/search/http.d.cts +323 -0
  97. package/dist/search/http.d.ts +323 -0
  98. package/dist/search/http.js +37 -0
  99. package/dist/search.cjs +57 -0
  100. package/dist/search.d.cts +113 -0
  101. package/dist/search.d.ts +113 -0
  102. package/dist/search.js +57 -0
  103. package/dist/transformer/transformers/AnthropicTransformer.cjs +3 -3
  104. package/dist/transformer/transformers/AnthropicTransformer.js +2 -2
  105. package/dist/transformer/transformers.cjs +7 -7
  106. package/dist/transformer/transformers.js +6 -6
  107. package/dist/transformer.cjs +6 -6
  108. package/dist/transformer.js +5 -5
  109. package/dist/{types-DsHBBk3h.d.cts → types-BSIJdsyl.d.cts} +15 -0
  110. package/dist/{types-CbglB73l.d.cts → types-Be-yt_6T.d.cts} +1 -1
  111. package/dist/{types-CVRge76p.d.ts → types-By9Tg6-I.d.ts} +15 -0
  112. package/dist/types-CbCZqLGg.d.cts +127 -0
  113. package/dist/types-CbCZqLGg.d.ts +127 -0
  114. package/dist/{types-jjU24eYG.d.cts → types-D-oHYusb.d.cts} +73 -4
  115. package/dist/{types-Bd72H4SB.d.ts → types-Dm4_36V4.d.ts} +1 -1
  116. package/dist/{types-5T223WYQ.d.ts → types-Dvlpjn0d.d.ts} +73 -4
  117. package/package.json +6 -3
  118. package/dist/{chunk-6OC3ORW6.js → chunk-EUZRH544.js} +3 -3
  119. package/dist/{chunk-SQMAEDNE.cjs → chunk-POUTD5AM.cjs} +2 -2
@@ -1765,7 +1765,10 @@ async function readJsonBody(request2, options) {
1765
1765
 
1766
1766
  // src/image-generation/openai-images/types.ts
1767
1767
  var DEFAULT_IMAGE_API_LIMITS = Object.freeze({
1768
- maxJsonBytes: 1024 * 1024,
1768
+ // Codex's built-in image tool sends edits as JSON data URLs rather than
1769
+ // multipart files. Leave room for the Base64 expansion of the bounded
1770
+ // aggregate input budget plus the small JSON/options envelope.
1771
+ maxJsonBytes: 96 * 1024 * 1024,
1769
1772
  maxMultipartBytes: 64 * 1024 * 1024,
1770
1773
  maxFileBytes: 50 * 1024 * 1024,
1771
1774
  maxTotalInputBytes: 64 * 1024 * 1024,
@@ -2326,7 +2329,7 @@ async function readMultipartEdit(request2, scope, limits, signal) {
2326
2329
  function invalid4(param = "image") {
2327
2330
  throw new ImageGenerationError("invalid_image_request", { param });
2328
2331
  }
2329
- function closedInput(value, maxRemoteUrlBytes) {
2332
+ function closedInput(value, limits) {
2330
2333
  if (!value || typeof value !== "object" || Array.isArray(value)) invalid4();
2331
2334
  const record2 = value;
2332
2335
  const keys = Object.keys(record2);
@@ -2334,8 +2337,9 @@ function closedInput(value, maxRemoteUrlBytes) {
2334
2337
  const key = keys[0];
2335
2338
  if (key !== "file_id" && key !== "image_url") invalid4();
2336
2339
  const item = record2[key];
2337
- const maxBytes = key === "file_id" ? 256 : maxRemoteUrlBytes;
2338
- if (typeof item !== "string" || !item || Buffer.byteLength(item, "utf8") > maxBytes) invalid4();
2340
+ if (typeof item !== "string" || !item) invalid4();
2341
+ const maxBytes = key === "file_id" ? 256 : item.toLowerCase().startsWith("data:") ? Math.ceil(limits.maxFileBytes / 3) * 4 + 64 : limits.maxRemoteUrlBytes;
2342
+ if (Buffer.byteLength(item, "utf8") > maxBytes) invalid4();
2339
2343
  return { [key]: item };
2340
2344
  }
2341
2345
  function decodedBase64Length(value) {
@@ -2407,7 +2411,7 @@ async function resolveReference(referenceId, runtime, scope) {
2407
2411
  return asset;
2408
2412
  }
2409
2413
  async function resolveImageInput(value, runtime, scope, signal) {
2410
- const input = closedInput(value, runtime.limits.maxRemoteUrlBytes);
2414
+ const input = closedInput(value, runtime.limits);
2411
2415
  if ("file_id" in input) return resolveReference(input.file_id, runtime, scope);
2412
2416
  if (input.image_url.toLowerCase().startsWith("data:")) {
2413
2417
  return resolveDataUrl(input.image_url, runtime, scope, signal);
@@ -2432,10 +2436,10 @@ async function resolveImageInput(value, runtime, scope, signal) {
2432
2436
  materializer
2433
2437
  });
2434
2438
  }
2435
- function parseImageInputList(value, maxRemoteUrlBytes) {
2439
+ function parseImageInputList(value, limits) {
2436
2440
  const list = Array.isArray(value) ? value : [value];
2437
2441
  if (list.length < 1 || list.length > 16) invalid4();
2438
- for (const item of list) closedInput(item, maxRemoteUrlBytes);
2442
+ for (const item of list) closedInput(item, limits);
2439
2443
  return list;
2440
2444
  }
2441
2445
 
@@ -2481,7 +2485,7 @@ function createImageEditHandler(deps) {
2481
2485
  });
2482
2486
  const inputs = parseImageInputList(
2483
2487
  record2.images ?? record2.image,
2484
- runtime.limits.maxRemoteUrlBytes
2488
+ runtime.limits
2485
2489
  );
2486
2490
  const resolveObservedInput = async (input) => {
2487
2491
  const reference = isReferenceInput(input);
@@ -0,0 +1,118 @@
1
+ // src/search/frontends.ts
2
+ var SEARCH_FRONTEND_NAMES = Object.freeze([
3
+ "codex",
4
+ "responses",
5
+ "anthropic"
6
+ ]);
7
+ var SEARCH_FRONTEND_MODES = Object.freeze([
8
+ "native",
9
+ "managed",
10
+ "off"
11
+ ]);
12
+ var DEFAULT_SEARCH_FRONTEND_MODES = Object.freeze({
13
+ codex: "off",
14
+ responses: "native",
15
+ anthropic: "native"
16
+ });
17
+ var SEARCH_UNSUPPORTED_CAPABILITY_CODE = "unsupported_capability";
18
+ function searchErrorHttpStatus(code) {
19
+ switch (code) {
20
+ case "rate_limited":
21
+ return 429;
22
+ case "timeout":
23
+ return 504;
24
+ case "cancelled":
25
+ return 499;
26
+ case "config_missing":
27
+ return 503;
28
+ case "auth_failed":
29
+ case "upstream_unavailable":
30
+ case "parse_failed":
31
+ case "policy_denied":
32
+ return 502;
33
+ default:
34
+ return 502;
35
+ }
36
+ }
37
+ function isSearchFrontendMode(value) {
38
+ return typeof value === "string" && SEARCH_FRONTEND_MODES.includes(value);
39
+ }
40
+ function record(value) {
41
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
42
+ }
43
+ function normalizeSearchFrontendModes(value) {
44
+ const raw = record(value) ?? {};
45
+ const modes = {
46
+ ...DEFAULT_SEARCH_FRONTEND_MODES
47
+ };
48
+ for (const name of SEARCH_FRONTEND_NAMES) {
49
+ const candidate = raw[name];
50
+ if (isSearchFrontendMode(candidate)) modes[name] = candidate;
51
+ }
52
+ return Object.freeze(modes);
53
+ }
54
+ function validateSearchFrontendModes(value, path = "$.search.modes") {
55
+ if (value === void 0) return [];
56
+ const raw = record(value);
57
+ if (!raw) return [`${path}: expected an object`];
58
+ const errors = [];
59
+ for (const [key, candidate] of Object.entries(raw)) {
60
+ if (!SEARCH_FRONTEND_NAMES.includes(key)) {
61
+ errors.push(`${path}.${key}: unknown frontend (expected ${SEARCH_FRONTEND_NAMES.join(", ")})`);
62
+ continue;
63
+ }
64
+ if (isSearchFrontendMode(candidate)) continue;
65
+ errors.push(
66
+ `${path}.${key}: not a mode (got ${typeof candidate}; expected ${SEARCH_FRONTEND_MODES.join(", ")})`
67
+ );
68
+ }
69
+ return errors;
70
+ }
71
+
72
+ // src/search/webSearchBackendCompat.ts
73
+ import {
74
+ searchErrorToLegacyWebSearchResponse,
75
+ toLegacyWebSearchResponse
76
+ } from "@omnicross/contracts/search-compat";
77
+ import { toSearchErrorShape } from "@omnicross/contracts/search-types";
78
+ function searchRuntimeAsWebSearchBackend(runtime, options = {}) {
79
+ return {
80
+ async search(query, providerId, searchOptions) {
81
+ try {
82
+ const response = await runtime.search({
83
+ query,
84
+ provider: providerId,
85
+ // `WebSearchOptions` is a strict subset of `SearchOptions` with
86
+ // identical field names — asserted in the contracts tests.
87
+ ...searchOptions === void 0 ? {} : { options: searchOptions }
88
+ });
89
+ return toLegacyWebSearchResponse(response);
90
+ } catch (error) {
91
+ return searchErrorToLegacyWebSearchResponse(query, toSearchErrorShape(error));
92
+ }
93
+ },
94
+ isProviderEnabled(id) {
95
+ return runtime.listProviders().some((descriptor) => descriptor.id === id);
96
+ },
97
+ async readUrl(url, readOptions) {
98
+ if (options.readUrl !== void 0) return options.readUrl(url, readOptions);
99
+ return {
100
+ success: false,
101
+ url,
102
+ error: "URL reading is not available through the search runtime adapter"
103
+ };
104
+ }
105
+ };
106
+ }
107
+
108
+ export {
109
+ SEARCH_FRONTEND_NAMES,
110
+ SEARCH_FRONTEND_MODES,
111
+ DEFAULT_SEARCH_FRONTEND_MODES,
112
+ SEARCH_UNSUPPORTED_CAPABILITY_CODE,
113
+ searchErrorHttpStatus,
114
+ isSearchFrontendMode,
115
+ normalizeSearchFrontendModes,
116
+ validateSearchFrontendModes,
117
+ searchRuntimeAsWebSearchBackend
118
+ };
@@ -0,0 +1,386 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class;
2
+
3
+ var _chunkBTBEJRGLcjs = require('./chunk-BTBEJRGL.cjs');
4
+
5
+ // src/search/orchestrator.ts
6
+ var _searchtypes = require('@omnicross/contracts/search-types');
7
+ var _crypto = require('crypto');
8
+
9
+ // src/search/normalize.ts
10
+ var DEFAULT_NORMALIZED_MAX_RESULTS = 5;
11
+ var SERP_REDIRECT_RULES = [
12
+ { domain: "google.com", paths: ["/search", "/goto"] },
13
+ { domain: "bing.com", paths: ["/search"] },
14
+ { domain: "duckduckgo.com", paths: ["/html/", "/l/"] },
15
+ { domain: "baidu.com", paths: ["/s"] }
16
+ ];
17
+ function isDirectResultUrl(rawUrl) {
18
+ let url;
19
+ try {
20
+ url = new URL(rawUrl);
21
+ } catch (e) {
22
+ return false;
23
+ }
24
+ if (url.protocol !== "http:" && url.protocol !== "https:") return false;
25
+ const host = url.hostname.toLowerCase();
26
+ for (const rule of SERP_REDIRECT_RULES) {
27
+ if (host !== rule.domain && !host.endsWith(`.${rule.domain}`)) continue;
28
+ if (rule.paths.includes(url.pathname)) return false;
29
+ }
30
+ return true;
31
+ }
32
+ function normalizedResultLimit(maxResults) {
33
+ const requested = maxResults === void 0 || !Number.isFinite(maxResults) ? DEFAULT_NORMALIZED_MAX_RESULTS : Math.floor(maxResults);
34
+ return Math.max(1, requested);
35
+ }
36
+ function normalizeSearchResults(results, maxResults) {
37
+ const limit = normalizedResultLimit(maxResults);
38
+ const seenUrls = /* @__PURE__ */ new Set();
39
+ const normalized = [];
40
+ for (const result of results) {
41
+ if (result === null || typeof result !== "object") continue;
42
+ const title = typeof result.title === "string" ? result.title.trim() : "";
43
+ const url = typeof result.url === "string" ? result.url.trim() : "";
44
+ if (title.length === 0 || !isDirectResultUrl(url)) continue;
45
+ if (seenUrls.has(url)) continue;
46
+ seenUrls.add(url);
47
+ normalized.push({
48
+ title,
49
+ url,
50
+ content: typeof result.content === "string" ? result.content.trim() : ""
51
+ });
52
+ if (normalized.length >= limit) break;
53
+ }
54
+ return normalized;
55
+ }
56
+
57
+ // src/search/orchestrator.ts
58
+ var QUERY_HASH_LENGTH = 12;
59
+ function hashSearchQuery(query) {
60
+ return _crypto.createHash.call(void 0, "sha256").update(query).digest("hex").slice(0, QUERY_HASH_LENGTH);
61
+ }
62
+ var SearchOrchestrator = class {
63
+
64
+
65
+
66
+ constructor(registry, options = {}) {
67
+ this.registry = registry;
68
+ this.defaultPolicy = _nullishCoalesce(options.policy, () => ( {}));
69
+ this.onEvent = options.onEvent;
70
+ }
71
+ /**
72
+ * Run one search.
73
+ *
74
+ * @param request - the query, an optional pinned provider, and per-request
75
+ * options. `options` is passed to the provider untouched: providers own
76
+ * their own timeouts and the orchestrator adds no second timeout layer.
77
+ * @param policyOverride - per-request policy, merged field-by-field over the
78
+ * orchestrator's default.
79
+ * @throws {SearchProviderError} when no provider produced a response.
80
+ */
81
+ async search(request, policyOverride) {
82
+ const policy = { ...this.defaultPolicy, ...policyOverride };
83
+ const requestId = _crypto.randomUUID.call(void 0, );
84
+ const queryHash = hashSearchQuery(request.query);
85
+ const startedAt = Date.now();
86
+ const attempts = [];
87
+ const emitComplete = (providerId, resultCount) => {
88
+ this.emit({
89
+ type: "search_complete",
90
+ requestId,
91
+ queryHash,
92
+ ...providerId === void 0 ? {} : { providerId },
93
+ resultCount,
94
+ fallbackCount: fallbackCountOf(attempts),
95
+ durationMs: Date.now() - startedAt
96
+ });
97
+ };
98
+ let plan;
99
+ try {
100
+ plan = this.planCandidates(request, policy);
101
+ } catch (error) {
102
+ emitComplete(void 0, 0);
103
+ throw error;
104
+ }
105
+ if (plan.skippedPreferred !== void 0) {
106
+ this.emit({
107
+ type: "search_attempt",
108
+ requestId,
109
+ queryHash,
110
+ providerId: plan.skippedPreferred.providerId,
111
+ outcome: "failed",
112
+ errorCode: plan.skippedPreferred.errorCode,
113
+ durationMs: 0
114
+ });
115
+ }
116
+ let lastError;
117
+ for (const candidate of plan.candidates) {
118
+ const attemptStartedAt = Date.now();
119
+ try {
120
+ const produced = await candidate.provider.search(request.query, request.options);
121
+ const durationMs = Date.now() - attemptStartedAt;
122
+ const results = normalizeSearchResults(produced, _optionalChain([request, 'access', _ => _.options, 'optionalAccess', _2 => _2.maxResults]));
123
+ attempts.push({
124
+ providerId: candidate.id,
125
+ outcome: "success",
126
+ resultCount: results.length,
127
+ durationMs
128
+ });
129
+ this.emit({
130
+ type: "search_attempt",
131
+ requestId,
132
+ queryHash,
133
+ providerId: candidate.id,
134
+ outcome: "success",
135
+ resultCount: results.length,
136
+ durationMs
137
+ });
138
+ emitComplete(candidate.id, results.length);
139
+ return {
140
+ query: request.query,
141
+ providerId: candidate.id,
142
+ results,
143
+ attempts,
144
+ fallbackCount: fallbackCountOf(attempts)
145
+ };
146
+ } catch (error) {
147
+ const durationMs = Date.now() - attemptStartedAt;
148
+ const shape = _searchtypes.toSearchErrorShape.call(void 0, error);
149
+ const isCancelled = shape.code === "cancelled" || _optionalChain([request, 'access', _3 => _3.options, 'optionalAccess', _4 => _4.signal, 'optionalAccess', _5 => _5.aborted]) === true;
150
+ const errorCode = isCancelled ? "cancelled" : shape.code;
151
+ attempts.push({
152
+ providerId: candidate.id,
153
+ outcome: "failed",
154
+ errorCode,
155
+ durationMs
156
+ });
157
+ this.emit({
158
+ type: "search_attempt",
159
+ requestId,
160
+ queryHash,
161
+ providerId: candidate.id,
162
+ outcome: "failed",
163
+ errorCode,
164
+ durationMs
165
+ });
166
+ if (isCancelled) {
167
+ emitComplete(void 0, 0);
168
+ throw shape.code === "cancelled" ? error : new (0, _searchtypes.SearchProviderError)("cancelled", "search was cancelled by the caller", {
169
+ providerId: candidate.id,
170
+ retryable: false,
171
+ cause: error
172
+ });
173
+ }
174
+ lastError = asSearchProviderError(error, shape.code, shape.message, candidate.id);
175
+ }
176
+ }
177
+ emitComplete(void 0, 0);
178
+ throw exhaustionError(attempts, lastError);
179
+ }
180
+ /** Resolve the candidate list for one request. */
181
+ planCandidates(request, policy) {
182
+ if (request.provider !== void 0) {
183
+ const pinned = this.registry.get(request.provider);
184
+ if (pinned === void 0) {
185
+ throw new (0, _searchtypes.SearchProviderError)(
186
+ "upstream_unavailable",
187
+ `search provider '${request.provider}' is not registered in this runtime`,
188
+ { providerId: request.provider, retryable: false }
189
+ );
190
+ }
191
+ if (!isAllowed(pinned.id, policy)) {
192
+ throw new (0, _searchtypes.SearchProviderError)(
193
+ "policy_denied",
194
+ `search provider '${request.provider}' is not allowed by the active search policy`,
195
+ { providerId: request.provider, retryable: false }
196
+ );
197
+ }
198
+ return { candidates: [pinned] };
199
+ }
200
+ const allowed = this.registry.list().filter((entry) => isAllowed(entry.id, policy));
201
+ let ordered = allowed;
202
+ let skippedPreferred;
203
+ if (policy.preferred !== void 0) {
204
+ const preferred = allowed.find((entry) => entry.id === policy.preferred);
205
+ if (preferred === void 0) {
206
+ skippedPreferred = {
207
+ providerId: policy.preferred,
208
+ errorCode: this.registry.has(policy.preferred) ? "policy_denied" : "upstream_unavailable"
209
+ };
210
+ } else {
211
+ ordered = [preferred, ...allowed.filter((entry) => entry.id !== preferred.id)];
212
+ }
213
+ }
214
+ if (policy.fallbackEnabled === false) ordered = ordered.slice(0, 1);
215
+ if (policy.maxAttempts !== void 0) {
216
+ ordered = ordered.slice(0, Math.max(0, Math.floor(policy.maxAttempts)));
217
+ }
218
+ return { candidates: ordered, ...skippedPreferred === void 0 ? {} : { skippedPreferred } };
219
+ }
220
+ /** Deliver one event. A listener that throws must never fail a search. */
221
+ emit(event) {
222
+ if (this.onEvent === void 0) return;
223
+ try {
224
+ this.onEvent(event);
225
+ } catch (e2) {
226
+ }
227
+ }
228
+ };
229
+ function fallbackCountOf(attempts) {
230
+ return Math.max(0, attempts.length - 1);
231
+ }
232
+ function isAllowed(id, policy) {
233
+ return policy.allowed === void 0 || policy.allowed.includes(id);
234
+ }
235
+ function asSearchProviderError(error, code, message, providerId) {
236
+ if (error instanceof _searchtypes.SearchProviderError) return error;
237
+ return new (0, _searchtypes.SearchProviderError)(code, message, { providerId, cause: error });
238
+ }
239
+ function exhaustionError(attempts, lastError) {
240
+ if (attempts.length === 1 && lastError !== void 0) return lastError;
241
+ if (attempts.length === 0) {
242
+ return new (0, _searchtypes.SearchProviderError)(
243
+ "upstream_unavailable",
244
+ "no eligible search provider was available (0 attempts)",
245
+ { retryable: false }
246
+ );
247
+ }
248
+ const trail = attempts.map((attempt) => `${attempt.providerId}:${_nullishCoalesce(attempt.errorCode, () => ( "unknown"))}`).join(",");
249
+ return new (0, _searchtypes.SearchProviderError)(
250
+ _nullishCoalesce(_optionalChain([lastError, 'optionalAccess', _6 => _6.code]), () => ( "upstream_unavailable")),
251
+ `search failed after ${attempts.length} attempt(s)`,
252
+ { retryable: _optionalChain([lastError, 'optionalAccess', _7 => _7.retryable]), details: { attempts: trail }, cause: lastError }
253
+ );
254
+ }
255
+
256
+ // src/search/registry.ts
257
+ var SearchRegistryError = class _SearchRegistryError extends Error {
258
+ constructor(message) {
259
+ super(message);
260
+ this.name = "SearchRegistryError";
261
+ Object.setPrototypeOf(this, _SearchRegistryError.prototype);
262
+ }
263
+ };
264
+ var SearchProviderRegistry = (_class = class {
265
+ __init() {this.entries = /* @__PURE__ */ new Map()}
266
+
267
+ __init2() {this.nextSequence = 0}
268
+ constructor(options = {}) {;_class.prototype.__init.call(this);_class.prototype.__init2.call(this);
269
+ this.allowBuiltinOverride = options.allowBuiltinOverride === true;
270
+ }
271
+ /**
272
+ * Register one provider.
273
+ *
274
+ * @param contribution - the provider with its origin, transport, and
275
+ * capabilities declared.
276
+ * @param context - who is registering, for a Phase-2 host. Retained as-is;
277
+ * no rule reads it today, and the parameter exists so adding one later is
278
+ * not a signature change for every caller.
279
+ * @throws {SearchRegistryError} on a blank id, a duplicate id, or a host
280
+ * contribution colliding with a builtin without `allowBuiltinOverride`.
281
+ */
282
+ register(contribution, context) {
283
+ const id = contribution.id;
284
+ if (typeof id !== "string" || id.trim().length === 0) {
285
+ throw new SearchRegistryError("a search provider contribution needs a non-blank id");
286
+ }
287
+ const existing = this.entries.get(id);
288
+ let sequence = this.nextSequence;
289
+ if (existing !== void 0) {
290
+ const isPermittedOverride = this.allowBuiltinOverride && contribution.source === "host" && existing.contribution.source === "builtin";
291
+ if (!isPermittedOverride) {
292
+ throw new SearchRegistryError(
293
+ existing.contribution.source === "builtin" && contribution.source === "host" ? `search provider '${id}' is a builtin; overriding it requires allowBuiltinOverride` : `search provider '${id}' is already registered`
294
+ );
295
+ }
296
+ sequence = existing.sequence;
297
+ } else {
298
+ this.nextSequence += 1;
299
+ }
300
+ this.entries.set(id, { contribution, context, sequence });
301
+ }
302
+ /** Whether an id is currently registered. */
303
+ has(id) {
304
+ return this.entries.has(id);
305
+ }
306
+ /** The contribution registered under `id`, if any. */
307
+ get(id) {
308
+ return _optionalChain([this, 'access', _8 => _8.entries, 'access', _9 => _9.get, 'call', _10 => _10(id), 'optionalAccess', _11 => _11.contribution]);
309
+ }
310
+ /**
311
+ * Remove a provider.
312
+ *
313
+ * The Phase-2 host-disconnect hook: when a host goes away its contributions
314
+ * go with it, and the id becomes free to register again.
315
+ *
316
+ * @returns whether something was removed.
317
+ */
318
+ unregister(id) {
319
+ return this.entries.delete(id);
320
+ }
321
+ /**
322
+ * Every registered contribution, in candidate order.
323
+ *
324
+ * `priorityHint` ascending; contributions without a hint come AFTER every
325
+ * hinted one (an absent hint is "no opinion", not "highest priority"); ties
326
+ * keep registration order. The builtin HTTP contributions carry no hints, so
327
+ * today this is exactly registration order.
328
+ */
329
+ list() {
330
+ return [...this.entries.values()].sort((a, b) => {
331
+ const aHint = a.contribution.priorityHint;
332
+ const bHint = b.contribution.priorityHint;
333
+ if (aHint !== bHint) {
334
+ if (aHint === void 0) return 1;
335
+ if (bHint === void 0) return -1;
336
+ return aHint - bHint;
337
+ }
338
+ return a.sequence - b.sequence;
339
+ }).map((entry) => entry.contribution);
340
+ }
341
+ }, _class);
342
+
343
+ // src/search/runtime.ts
344
+ function createSearchRuntime(options = {}) {
345
+ const registry = new SearchProviderRegistry({
346
+ allowBuiltinOverride: options.allowBuiltinOverride === true
347
+ });
348
+ for (const contribution of _nullishCoalesce(options.contributions, () => ( _chunkBTBEJRGLcjs.builtinHttpSearchContributions.call(void 0, )))) {
349
+ registry.register(contribution);
350
+ }
351
+ const orchestrator = new SearchOrchestrator(registry, {
352
+ ...options.policy === void 0 ? {} : { policy: options.policy },
353
+ ...options.onEvent === void 0 ? {} : { onEvent: options.onEvent }
354
+ });
355
+ return {
356
+ search(request) {
357
+ return orchestrator.search(request);
358
+ },
359
+ registerContribution(contribution, context) {
360
+ registry.register(contribution, context);
361
+ },
362
+ unregisterContribution(id) {
363
+ return registry.unregister(id);
364
+ },
365
+ listProviders() {
366
+ return registry.list().map((contribution) => ({
367
+ id: contribution.id,
368
+ source: contribution.source,
369
+ kind: contribution.kind,
370
+ capabilities: { ...contribution.capabilities }
371
+ }));
372
+ }
373
+ };
374
+ }
375
+
376
+
377
+
378
+
379
+
380
+
381
+
382
+
383
+
384
+
385
+
386
+ exports.DEFAULT_NORMALIZED_MAX_RESULTS = DEFAULT_NORMALIZED_MAX_RESULTS; exports.isDirectResultUrl = isDirectResultUrl; exports.normalizedResultLimit = normalizedResultLimit; exports.normalizeSearchResults = normalizeSearchResults; exports.hashSearchQuery = hashSearchQuery; exports.SearchOrchestrator = SearchOrchestrator; exports.SearchRegistryError = SearchRegistryError; exports.SearchProviderRegistry = SearchProviderRegistry; exports.createSearchRuntime = createSearchRuntime;
@@ -1765,7 +1765,10 @@ async function readJsonBody(request2, options) {
1765
1765
 
1766
1766
  // src/image-generation/openai-images/types.ts
1767
1767
  var DEFAULT_IMAGE_API_LIMITS = Object.freeze({
1768
- maxJsonBytes: 1024 * 1024,
1768
+ // Codex's built-in image tool sends edits as JSON data URLs rather than
1769
+ // multipart files. Leave room for the Base64 expansion of the bounded
1770
+ // aggregate input budget plus the small JSON/options envelope.
1771
+ maxJsonBytes: 96 * 1024 * 1024,
1769
1772
  maxMultipartBytes: 64 * 1024 * 1024,
1770
1773
  maxFileBytes: 50 * 1024 * 1024,
1771
1774
  maxTotalInputBytes: 64 * 1024 * 1024,
@@ -2326,7 +2329,7 @@ async function readMultipartEdit(request2, scope, limits, signal) {
2326
2329
  function invalid4(param = "image") {
2327
2330
  throw new ImageGenerationError("invalid_image_request", { param });
2328
2331
  }
2329
- function closedInput(value, maxRemoteUrlBytes) {
2332
+ function closedInput(value, limits) {
2330
2333
  if (!value || typeof value !== "object" || Array.isArray(value)) invalid4();
2331
2334
  const record2 = value;
2332
2335
  const keys = Object.keys(record2);
@@ -2334,8 +2337,9 @@ function closedInput(value, maxRemoteUrlBytes) {
2334
2337
  const key = keys[0];
2335
2338
  if (key !== "file_id" && key !== "image_url") invalid4();
2336
2339
  const item = record2[key];
2337
- const maxBytes = key === "file_id" ? 256 : maxRemoteUrlBytes;
2338
- if (typeof item !== "string" || !item || Buffer.byteLength(item, "utf8") > maxBytes) invalid4();
2340
+ if (typeof item !== "string" || !item) invalid4();
2341
+ const maxBytes = key === "file_id" ? 256 : item.toLowerCase().startsWith("data:") ? Math.ceil(limits.maxFileBytes / 3) * 4 + 64 : limits.maxRemoteUrlBytes;
2342
+ if (Buffer.byteLength(item, "utf8") > maxBytes) invalid4();
2339
2343
  return { [key]: item };
2340
2344
  }
2341
2345
  function decodedBase64Length(value) {
@@ -2407,7 +2411,7 @@ async function resolveReference(referenceId, runtime, scope) {
2407
2411
  return asset;
2408
2412
  }
2409
2413
  async function resolveImageInput(value, runtime, scope, signal) {
2410
- const input = closedInput(value, runtime.limits.maxRemoteUrlBytes);
2414
+ const input = closedInput(value, runtime.limits);
2411
2415
  if ("file_id" in input) return resolveReference(input.file_id, runtime, scope);
2412
2416
  if (input.image_url.toLowerCase().startsWith("data:")) {
2413
2417
  return resolveDataUrl(input.image_url, runtime, scope, signal);
@@ -2432,10 +2436,10 @@ async function resolveImageInput(value, runtime, scope, signal) {
2432
2436
  materializer
2433
2437
  });
2434
2438
  }
2435
- function parseImageInputList(value, maxRemoteUrlBytes) {
2439
+ function parseImageInputList(value, limits) {
2436
2440
  const list = Array.isArray(value) ? value : [value];
2437
2441
  if (list.length < 1 || list.length > 16) invalid4();
2438
- for (const item of list) closedInput(item, maxRemoteUrlBytes);
2442
+ for (const item of list) closedInput(item, limits);
2439
2443
  return list;
2440
2444
  }
2441
2445
 
@@ -2481,7 +2485,7 @@ function createImageEditHandler(deps) {
2481
2485
  });
2482
2486
  const inputs = parseImageInputList(
2483
2487
  _nullishCoalesce(record2.images, () => ( record2.image)),
2484
- runtime.limits.maxRemoteUrlBytes
2488
+ runtime.limits
2485
2489
  );
2486
2490
  const resolveObservedInput = async (input) => {
2487
2491
  const reference = isReferenceInput(input);
@@ -32,6 +32,12 @@ function bumpUpstreamProxyGeneration() {
32
32
  }
33
33
  }
34
34
  }
35
+ function isClientDisconnectAbort(signal) {
36
+ if (!signal?.aborted) return false;
37
+ const reason = signal.reason;
38
+ if (!reason || typeof reason !== "object") return false;
39
+ return reason.code === "client_disconnect";
40
+ }
35
41
  function normalizeProxy(cfg) {
36
42
  if ("url" in cfg) {
37
43
  let u;
@@ -144,7 +150,7 @@ function fetchUpstream(url, init, ctx) {
144
150
  return response;
145
151
  },
146
152
  (error) => {
147
- recordActivity(0);
153
+ if (!isClientDisconnectAbort(init.signal)) recordActivity(0);
148
154
  throw error;
149
155
  }
150
156
  );