@bedolla/enriweb 0.1.5 → 0.1.7

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 (56) hide show
  1. package/README.md +48 -20
  2. package/dist/client/EnriProxyClient.d.ts +176 -5
  3. package/dist/client/EnriProxyClient.d.ts.map +1 -1
  4. package/dist/client/EnriProxyClient.js +255 -31
  5. package/dist/client/EnriProxyClient.js.map +1 -1
  6. package/dist/index.js +65 -25
  7. package/dist/index.js.map +1 -1
  8. package/dist/package-info.d.ts +26 -0
  9. package/dist/package-info.d.ts.map +1 -1
  10. package/dist/package-info.js +29 -2
  11. package/dist/package-info.js.map +1 -1
  12. package/dist/server/EnriWebServer.d.ts +33 -0
  13. package/dist/server/EnriWebServer.d.ts.map +1 -1
  14. package/dist/server/EnriWebServer.js +338 -28
  15. package/dist/server/EnriWebServer.js.map +1 -1
  16. package/dist/shared/Utf8SafeTextSlicer.d.ts +47 -0
  17. package/dist/shared/Utf8SafeTextSlicer.d.ts.map +1 -0
  18. package/dist/shared/Utf8SafeTextSlicer.js +97 -0
  19. package/dist/shared/Utf8SafeTextSlicer.js.map +1 -0
  20. package/dist/shared/validation.d.ts +13 -1
  21. package/dist/shared/validation.d.ts.map +1 -1
  22. package/dist/shared/validation.js +41 -17
  23. package/dist/shared/validation.js.map +1 -1
  24. package/dist/tools/WebFetchNpmProjection.d.ts +143 -0
  25. package/dist/tools/WebFetchNpmProjection.d.ts.map +1 -0
  26. package/dist/tools/WebFetchNpmProjection.js +480 -0
  27. package/dist/tools/WebFetchNpmProjection.js.map +1 -0
  28. package/dist/tools/WebFetchParamsParser.d.ts +26 -0
  29. package/dist/tools/WebFetchParamsParser.d.ts.map +1 -0
  30. package/dist/tools/WebFetchParamsParser.js +157 -0
  31. package/dist/tools/WebFetchParamsParser.js.map +1 -0
  32. package/dist/tools/WebFetchRangesExecutor.d.ts +86 -0
  33. package/dist/tools/WebFetchRangesExecutor.d.ts.map +1 -0
  34. package/dist/tools/WebFetchRangesExecutor.js +277 -0
  35. package/dist/tools/WebFetchRangesExecutor.js.map +1 -0
  36. package/dist/tools/WebFetchTool.d.ts +187 -71
  37. package/dist/tools/WebFetchTool.d.ts.map +1 -1
  38. package/dist/tools/WebFetchTool.js +145 -367
  39. package/dist/tools/WebFetchTool.js.map +1 -1
  40. package/dist/tools/WebFetchToolTextFormatter.d.ts +57 -0
  41. package/dist/tools/WebFetchToolTextFormatter.d.ts.map +1 -0
  42. package/dist/tools/WebFetchToolTextFormatter.js +135 -0
  43. package/dist/tools/WebFetchToolTextFormatter.js.map +1 -0
  44. package/dist/tools/WebSearchRegistryHttpReader.d.ts +116 -0
  45. package/dist/tools/WebSearchRegistryHttpReader.d.ts.map +1 -0
  46. package/dist/tools/WebSearchRegistryHttpReader.js +157 -0
  47. package/dist/tools/WebSearchRegistryHttpReader.js.map +1 -0
  48. package/dist/tools/WebSearchRegistryVerifier.d.ts +111 -6
  49. package/dist/tools/WebSearchRegistryVerifier.d.ts.map +1 -1
  50. package/dist/tools/WebSearchRegistryVerifier.js +406 -125
  51. package/dist/tools/WebSearchRegistryVerifier.js.map +1 -1
  52. package/dist/tools/WebSearchTool.d.ts +85 -2
  53. package/dist/tools/WebSearchTool.d.ts.map +1 -1
  54. package/dist/tools/WebSearchTool.js +197 -19
  55. package/dist/tools/WebSearchTool.js.map +1 -1
  56. package/package.json +3 -2
@@ -0,0 +1,157 @@
1
+ /**
2
+ * Argument parsing for the web_fetch MCP tool.
3
+ *
4
+ * @remarks
5
+ * Lenient for malformed optional values (they degrade to documented
6
+ * defaults, matching the EnriCode client parser: unusable or out-of-domain
7
+ * budgets fall back to the documented default instead of failing the call,
8
+ * per the shared AR-4 client policy) but strict for structural mistakes
9
+ * (broken ranges, unknown action without cursor), which fail fast in
10
+ * Spanish. Snake_case field names
11
+ * are canonical; camelCase aliases (maxChars, offsetChars, limitChars,
12
+ * includeLinks, includeMetadata) are accepted as fallbacks for parity with
13
+ * the EnriCode tool surface. Extracted from {@link WebFetchTool} as a pure
14
+ * function module.
15
+ *
16
+ * @module tools/WebFetchParamsParser
17
+ */
18
+ import { assertHttpUrl, assertObject, optionalInt, optionalString } from "../shared/validation.js";
19
+ import { sliceUtf8Safe } from "../shared/Utf8SafeTextSlicer.js";
20
+ import { MAX_ANCHOR_CHARS, MAX_TOOL_RANGES } from "./WebFetchTool.js";
21
+ /**
22
+ * Validates raw MCP tool arguments.
23
+ *
24
+ * @param raw - Raw tool arguments
25
+ * @returns Validated parameters
26
+ */
27
+ export function parseWebFetchParams(raw) {
28
+ const obj = assertObject(raw, "arguments");
29
+ const cursorRaw = optionalString(obj["cursor"]);
30
+ const cursor = cursorRaw?.trim() ? cursorRaw.trim() : undefined;
31
+ const urlRaw = optionalString(obj["url"]);
32
+ const urlTrimmed = urlRaw?.trim() ? urlRaw.trim() : undefined;
33
+ // A valid cursor always wins over a coexisting `url`: on cursor calls the
34
+ // url degrades to an optional display label (invalid shapes are dropped
35
+ // instead of hard-failing the whole call), while cursor-less calls keep
36
+ // the strict http(s) validation.
37
+ let url;
38
+ if (cursor !== undefined) {
39
+ url = urlTrimmed !== undefined && /^https?:\/\//iu.test(urlTrimmed) ? urlTrimmed : undefined;
40
+ }
41
+ else {
42
+ url = urlTrimmed !== undefined ? assertHttpUrl(urlTrimmed, "url") : undefined;
43
+ }
44
+ if (!cursor && !url) {
45
+ throw new Error("web_fetch requiere 'url' o 'cursor'.");
46
+ }
47
+ if (cursor && !/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/u.test(cursor)) {
48
+ throw new Error("Cursor inválido. Se esperaba un cursor devuelto por una llamada previa a web_fetch.");
49
+ }
50
+ const prompt = optionalString(obj["prompt"]);
51
+ // max_chars is canonical; maxChars is the camelCase alias accepted for
52
+ // parity with the EnriCode tool surface.
53
+ let maxChars = optionalInt(obj["max_chars"]) ?? optionalInt(obj["maxChars"]);
54
+ // Invalid format/content values degrade to the documented defaults
55
+ // ("text"/"main") instead of failing the call, matching EnriCode and
56
+ // EnriProxy projection fallbacks.
57
+ const format = obj["format"] === "markdown"
58
+ ? "markdown"
59
+ : obj["format"] === "text"
60
+ ? "text"
61
+ : obj["format"] === "html"
62
+ ? "html"
63
+ : undefined;
64
+ const content = obj["content"] === "main" ? "main" : obj["content"] === "full" ? "full" : undefined;
65
+ const includeLinks = obj["include_links"] === true || obj["includeLinks"] === true
66
+ ? true
67
+ : obj["include_links"] === false || obj["includeLinks"] === false
68
+ ? false
69
+ : undefined;
70
+ const includeMetadata = obj["include_metadata"] === true || obj["includeMetadata"] === true
71
+ ? true
72
+ : obj["include_metadata"] === false || obj["includeMetadata"] === false
73
+ ? false
74
+ : undefined;
75
+ const anchorRaw = optionalString(obj["anchor"]);
76
+ const anchorClean = anchorRaw ? sliceUtf8Safe(anchorRaw.trim().replace(/^#+/, "").trim(), 0, MAX_ANCHOR_CHARS) : "";
77
+ const anchor = anchorClean ? anchorClean : undefined;
78
+ const offsetCharsRaw = optionalInt(obj["offset_chars"]) ?? optionalInt(obj["offsetChars"]) ?? optionalInt(obj["offset"]);
79
+ const limitCharsRaw = optionalInt(obj["limit_chars"]) ?? optionalInt(obj["limitChars"]) ?? optionalInt(obj["limit"]);
80
+ const action = obj["action"] === "delete" ? "delete" : undefined;
81
+ const ranges = parseRanges(obj["ranges"]);
82
+ if (action === "delete" && !cursor) {
83
+ throw new Error("action 'delete' requiere 'cursor'.");
84
+ }
85
+ // AR-4 client parity (EnriCode readOptionalPositiveInteger): a
86
+ // non-positive or otherwise unusable budget degrades to the server
87
+ // default instead of failing the call mid-task.
88
+ if (maxChars !== undefined && maxChars < 1) {
89
+ maxChars = undefined;
90
+ }
91
+ // offset/limit travel with cursor reads (server-side window over the
92
+ // capture) and with url reads (local slice over the returned content,
93
+ // matching EnriCode's first-read range semantics).
94
+ // AR-4 client parity: negative offsets/limits degrade to the
95
+ // documented defaults (no offset / no explicit limit).
96
+ const offsetChars = offsetCharsRaw !== undefined && offsetCharsRaw >= 0 ? offsetCharsRaw : undefined;
97
+ let limitChars = limitCharsRaw;
98
+ if (limitChars !== undefined && limitChars <= 0) {
99
+ limitChars = undefined;
100
+ }
101
+ return {
102
+ url,
103
+ cursor,
104
+ prompt,
105
+ maxChars,
106
+ format,
107
+ content,
108
+ includeLinks,
109
+ includeMetadata,
110
+ anchor,
111
+ offsetChars,
112
+ limitChars,
113
+ action,
114
+ ranges
115
+ };
116
+ }
117
+ /**
118
+ * Parses an optional `ranges` array of character windows.
119
+ *
120
+ * @param raw - Raw input
121
+ * @returns Range specs, or undefined when absent/empty
122
+ */
123
+ function parseRanges(raw) {
124
+ if (raw === undefined || raw === null) {
125
+ return undefined;
126
+ }
127
+ if (!Array.isArray(raw)) {
128
+ throw new Error("ranges debe ser un arreglo de objetos {offset_chars, limit_chars}.");
129
+ }
130
+ if (raw.length === 0) {
131
+ return undefined;
132
+ }
133
+ if (raw.length > MAX_TOOL_RANGES) {
134
+ throw new Error(`ranges admite un máximo de ${MAX_TOOL_RANGES} rangos por llamada.`);
135
+ }
136
+ const collected = [];
137
+ for (const entry of raw) {
138
+ if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
139
+ throw new Error("cada rango en ranges debe ser un objeto {offset_chars, limit_chars}.");
140
+ }
141
+ const record = entry;
142
+ const offsetChars = optionalInt(record["offset_chars"]) ?? optionalInt(record["offsetChars"]) ?? optionalInt(record["offset"]) ?? 0;
143
+ const limitRaw = optionalInt(record["limit_chars"]) ?? optionalInt(record["limitChars"]) ?? optionalInt(record["limit"]);
144
+ if (offsetChars < 0) {
145
+ throw new Error("offset_chars de cada rango debe ser no negativo.");
146
+ }
147
+ if (limitRaw !== undefined && limitRaw < 0) {
148
+ throw new Error("limit_chars de cada rango debe ser positivo.");
149
+ }
150
+ collected.push({
151
+ offsetChars,
152
+ limitChars: limitRaw === undefined || limitRaw === 0 ? undefined : Math.max(1, limitRaw)
153
+ });
154
+ }
155
+ return collected;
156
+ }
157
+ //# sourceMappingURL=WebFetchParamsParser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebFetchParamsParser.js","sourceRoot":"","sources":["../../src/tools/WebFetchParamsParser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACnG,OAAO,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAmD,MAAM,mBAAmB,CAAC;AAEvH;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAAY;IAC9C,MAAM,GAAG,GAAG,YAAY,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IAE3C,MAAM,SAAS,GAAG,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;IAChD,MAAM,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IAEhE,MAAM,MAAM,GAAG,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;IAC1C,MAAM,UAAU,GAAG,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IAC9D,0EAA0E;IAC1E,wEAAwE;IACxE,wEAAwE;IACxE,iCAAiC;IACjC,IAAI,GAAuB,CAAC;IAC5B,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,GAAG,GAAG,UAAU,KAAK,SAAS,IAAI,gBAAgB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC;IAC/F,CAAC;SAAM,CAAC;QACN,GAAG,GAAG,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAChF,CAAC;IAED,IAAI,CAAC,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC1D,CAAC;IACD,IAAI,MAAM,IAAI,CAAC,gFAAgF,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QAC7G,MAAM,IAAI,KAAK,CAAC,qFAAqF,CAAC,CAAC;IACzG,CAAC;IAED,MAAM,MAAM,GAAG,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC7C,uEAAuE;IACvE,yCAAyC;IACzC,IAAI,QAAQ,GAAG,WAAW,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,IAAI,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC;IAC7E,mEAAmE;IACnE,qEAAqE;IACrE,kCAAkC;IAClC,MAAM,MAAM,GACV,GAAG,CAAC,QAAQ,CAAC,KAAK,UAAU;QAC1B,CAAC,CAAC,UAAU;QACZ,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,MAAM;YACxB,CAAC,CAAC,MAAM;YACR,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,MAAM;gBACxB,CAAC,CAAC,MAAM;gBACR,CAAC,CAAC,SAAS,CAAC;IACpB,MAAM,OAAO,GACX,GAAG,CAAC,SAAS,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;IACtF,MAAM,YAAY,GAChB,GAAG,CAAC,eAAe,CAAC,KAAK,IAAI,IAAI,GAAG,CAAC,cAAc,CAAC,KAAK,IAAI;QAC3D,CAAC,CAAC,IAAI;QACN,CAAC,CAAC,GAAG,CAAC,eAAe,CAAC,KAAK,KAAK,IAAI,GAAG,CAAC,cAAc,CAAC,KAAK,KAAK;YAC/D,CAAC,CAAC,KAAK;YACP,CAAC,CAAC,SAAS,CAAC;IAClB,MAAM,eAAe,GACnB,GAAG,CAAC,kBAAkB,CAAC,KAAK,IAAI,IAAI,GAAG,CAAC,iBAAiB,CAAC,KAAK,IAAI;QACjE,CAAC,CAAC,IAAI;QACN,CAAC,CAAC,GAAG,CAAC,kBAAkB,CAAC,KAAK,KAAK,IAAI,GAAG,CAAC,iBAAiB,CAAC,KAAK,KAAK;YACrE,CAAC,CAAC,KAAK;YACP,CAAC,CAAC,SAAS,CAAC;IAClB,MAAM,SAAS,GAAG,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;IAChD,MAAM,WAAW,GAAG,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACpH,MAAM,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC;IACrD,MAAM,cAAc,GAClB,WAAW,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,IAAI,WAAW,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,IAAI,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;IACpG,MAAM,aAAa,GACjB,WAAW,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,IAAI,WAAW,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,IAAI,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;IACjG,MAAM,MAAM,GAAyB,GAAG,CAAC,QAAQ,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC;IACvF,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC;IAE1C,IAAI,MAAM,KAAK,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;IACxD,CAAC;IACD,+DAA+D;IAC/D,mEAAmE;IACnE,gDAAgD;IAChD,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;QAC3C,QAAQ,GAAG,SAAS,CAAC;IACvB,CAAC;IAED,qEAAqE;IACrE,sEAAsE;IACtE,mDAAmD;IACnD,6DAA6D;IAC7D,uDAAuD;IACvD,MAAM,WAAW,GAAG,cAAc,KAAK,SAAS,IAAI,cAAc,IAAI,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC;IACrG,IAAI,UAAU,GAAuB,aAAa,CAAC;IAEnD,IAAI,UAAU,KAAK,SAAS,IAAI,UAAU,IAAI,CAAC,EAAE,CAAC;QAChD,UAAU,GAAG,SAAS,CAAC;IACzB,CAAC;IAED,OAAO;QACL,GAAG;QACH,MAAM;QACN,MAAM;QACN,QAAQ;QACR,MAAM;QACN,OAAO;QACP,YAAY;QACZ,eAAe;QACf,MAAM;QACN,WAAW;QACX,UAAU;QACV,MAAM;QACN,MAAM;KACP,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,SAAS,WAAW,CAAC,GAAY;IAC/B,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QACtC,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,oEAAoE,CAAC,CAAC;IACxF,CAAC;IACD,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrB,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,IAAI,GAAG,CAAC,MAAM,GAAG,eAAe,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,8BAA8B,eAAe,sBAAsB,CAAC,CAAC;IACvF,CAAC;IAED,MAAM,SAAS,GAAwB,EAAE,CAAC;IAC1C,KAAK,MAAM,KAAK,IAAI,GAAG,EAAE,CAAC;QACxB,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACxE,MAAM,IAAI,KAAK,CAAC,sEAAsE,CAAC,CAAC;QAC1F,CAAC;QACD,MAAM,MAAM,GAAG,KAAgC,CAAC;QAChD,MAAM,WAAW,GACf,WAAW,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,IAAI,WAAW,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,IAAI,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC;QAClH,MAAM,QAAQ,GACZ,WAAW,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,IAAI,WAAW,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,IAAI,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;QAC1G,IAAI,WAAW,GAAG,CAAC,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;QACtE,CAAC;QACD,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;YAC3C,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;QAClE,CAAC;QACD,SAAS,CAAC,IAAI,CAAC;YACb,WAAW;YACX,UAAU,EAAE,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC;SACzF,CAAC,CAAC;IACL,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Grouped-ranges execution for the web_fetch MCP tool.
3
+ *
4
+ * @remarks
5
+ * Cursor slices are independent reads of one immutable capture: the batch
6
+ * runs concurrently (bounded by MAX_TOOL_RANGES) with order following the
7
+ * requested ranges — same semantics as EnriCode's grouped cursor ranges,
8
+ * including the Spanish continuation hints and the early cursor release
9
+ * when every window is exhausted. Extracted from {@link WebFetchTool}.
10
+ *
11
+ * @module tools/WebFetchRangesExecutor
12
+ */
13
+ import { type EnriProxyClient } from "../client/EnriProxyClient.js";
14
+ import { type WebFetchRangeSpec, type WebFetchToolResult, type WebFetchToolRangesResult } from "./WebFetchTool.js";
15
+ /**
16
+ * Executes grouped ranges for the web_fetch tool.
17
+ */
18
+ export declare class WebFetchRangesExecutor {
19
+ /**
20
+ * Reads the undecorated page one local range batch addresses.
21
+ *
22
+ * @param result - Single-read result holding the captured content.
23
+ * @returns Raw page text (bounds-resolved when the proxy reported
24
+ * them, verbatim `content` otherwise).
25
+ */
26
+ static readUndecoratedPage(result: WebFetchToolResult): string;
27
+ /**
28
+ * Resolves the first-read capture budget for grouped ranges.
29
+ *
30
+ * @param ranges - Requested ranges
31
+ * @param maxChars - Call budget
32
+ * @returns Capture budget reaching the furthest requested range end
33
+ */
34
+ resolveRangesCaptureMaxChars(ranges: readonly WebFetchRangeSpec[], maxChars: number): number;
35
+ /**
36
+ * Executes grouped ranges as concurrent cursor reads of one capture.
37
+ *
38
+ * @remarks
39
+ * Cursor slices are independent reads of one immutable capture, so the
40
+ * batch runs concurrently (bounded by {@link MAX_TOOL_RANGES}) with order
41
+ * following the requested ranges — same semantics as EnriCode's grouped
42
+ * cursor ranges. One failed slice does not kill the batch: every range
43
+ * yields a result row and failures surface as Spanish `error` rows while
44
+ * the surviving slices return normally. A definitive proxy rejection on
45
+ * one slice (for example an expired cursor) cancels the sibling reads
46
+ * through a shared signal, since every slice reads the same cursor.
47
+ *
48
+ * @param client - EnriProxy client
49
+ * @param cursor - Cursor addressing the capture
50
+ * @param ranges - Requested ranges
51
+ * @param maxChars - Call budget used as default slice length
52
+ * @param resolvedUrl - URL reported for the grouped result
53
+ * @param signal - Optional caller abort signal
54
+ * @returns Grouped ranges result
55
+ * @throws Error when the caller cancelled the request mid-flight
56
+ */
57
+ executeGroupedCursorRanges(client: EnriProxyClient, cursor: string, ranges: readonly WebFetchRangeSpec[], maxChars: number, resolvedUrl: string, signal?: AbortSignal): Promise<WebFetchToolRangesResult>;
58
+ /**
59
+ * Describes one failed range read with an honest Spanish diagnostic.
60
+ *
61
+ * @param reason - Raw rejection reason of the failed slice.
62
+ * @param abortedBySiblingFailure - Whether the shared batch abort fired.
63
+ * @returns Spanish failure description for the model-facing error row.
64
+ */
65
+ private static describeRangeFailure;
66
+ /**
67
+ * Applies grouped ranges locally over already-fetched content.
68
+ *
69
+ * @remarks
70
+ * A range whose offset lies beyond the UNDECORATED page is out of range,
71
+ * not truncated: the slice comes back empty with an honest Spanish note
72
+ * and `truncated: false`, so the model does not infer more pages behind
73
+ * an empty window. A range that starts inside the page but hits its end
74
+ * is the real truncation case. Windows address the raw page (via the
75
+ * `page_offset_chars`/`page_chars` bounds the proxy reports), so the
76
+ * status header and truncation footer never land inside a requested
77
+ * window; responses without bounds slice `content` verbatim.
78
+ *
79
+ * @param result - Single-read result holding the captured content
80
+ * @param ranges - Requested ranges
81
+ * @param maxChars - Call budget used as default slice length
82
+ * @returns Grouped ranges result
83
+ */
84
+ applyLocalRangesToResult(result: WebFetchToolResult, ranges: readonly WebFetchRangeSpec[], maxChars: number): WebFetchToolRangesResult;
85
+ }
86
+ //# sourceMappingURL=WebFetchRangesExecutor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebFetchRangesExecutor.d.ts","sourceRoot":"","sources":["../../src/tools/WebFetchRangesExecutor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,KAAK,eAAe,EAA0C,MAAM,8BAA8B,CAAC;AAE5G,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,wBAAwB,EAC9B,MAAM,mBAAmB,CAAC;AAE3B;;GAEG;AACH,qBAAa,sBAAsB;IACjC;;;;;;OAMG;WACW,mBAAmB,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM;IAiBrE;;;;;;OAMG;IACI,4BAA4B,CACjC,MAAM,EAAE,SAAS,iBAAiB,EAAE,EACpC,QAAQ,EAAE,MAAM,GACf,MAAM;IAOT;;;;;;;;;;;;;;;;;;;;;OAqBG;IACU,0BAA0B,CACrC,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,SAAS,iBAAiB,EAAE,EACpC,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,wBAAwB,CAAC;IAyIpC;;;;;;OAMG;IACH,OAAO,CAAC,MAAM,CAAC,oBAAoB;IAcnC;;;;;;;;;;;;;;;;;OAiBG;IACI,wBAAwB,CAC7B,MAAM,EAAE,kBAAkB,EAC1B,MAAM,EAAE,SAAS,iBAAiB,EAAE,EACpC,QAAQ,EAAE,MAAM,GACf,wBAAwB;CAwD5B"}
@@ -0,0 +1,277 @@
1
+ /**
2
+ * Grouped-ranges execution for the web_fetch MCP tool.
3
+ *
4
+ * @remarks
5
+ * Cursor slices are independent reads of one immutable capture: the batch
6
+ * runs concurrently (bounded by MAX_TOOL_RANGES) with order following the
7
+ * requested ranges — same semantics as EnriCode's grouped cursor ranges,
8
+ * including the Spanish continuation hints and the early cursor release
9
+ * when every window is exhausted. Extracted from {@link WebFetchTool}.
10
+ *
11
+ * @module tools/WebFetchRangesExecutor
12
+ */
13
+ import { EnriProxyHttpError, MAX_WIRE_MAX_CHARS } from "../client/EnriProxyClient.js";
14
+ import { sliceUtf8Safe } from "../shared/Utf8SafeTextSlicer.js";
15
+ /**
16
+ * Executes grouped ranges for the web_fetch tool.
17
+ */
18
+ export class WebFetchRangesExecutor {
19
+ /**
20
+ * Reads the undecorated page one local range batch addresses.
21
+ *
22
+ * @param result - Single-read result holding the captured content.
23
+ * @returns Raw page text (bounds-resolved when the proxy reported
24
+ * them, verbatim `content` otherwise).
25
+ */
26
+ static readUndecoratedPage(result) {
27
+ const content = result.content;
28
+ const pageOffset = result.page_offset_chars;
29
+ const pageChars = result.page_chars;
30
+ if (typeof pageOffset === "number" &&
31
+ Number.isFinite(pageOffset) &&
32
+ pageOffset >= 0 &&
33
+ typeof pageChars === "number" &&
34
+ Number.isFinite(pageChars) &&
35
+ pageChars >= 0 &&
36
+ pageOffset <= content.length) {
37
+ return sliceUtf8Safe(content, pageOffset, pageOffset + pageChars);
38
+ }
39
+ return content;
40
+ }
41
+ /**
42
+ * Resolves the first-read capture budget for grouped ranges.
43
+ *
44
+ * @param ranges - Requested ranges
45
+ * @param maxChars - Call budget
46
+ * @returns Capture budget reaching the furthest requested range end
47
+ */
48
+ resolveRangesCaptureMaxChars(ranges, maxChars) {
49
+ const furthestEnd = Math.max(...ranges.map((range) => range.offsetChars + (range.limitChars ?? 0)));
50
+ return Math.min(MAX_WIRE_MAX_CHARS, Math.max(maxChars, furthestEnd));
51
+ }
52
+ /**
53
+ * Executes grouped ranges as concurrent cursor reads of one capture.
54
+ *
55
+ * @remarks
56
+ * Cursor slices are independent reads of one immutable capture, so the
57
+ * batch runs concurrently (bounded by {@link MAX_TOOL_RANGES}) with order
58
+ * following the requested ranges — same semantics as EnriCode's grouped
59
+ * cursor ranges. One failed slice does not kill the batch: every range
60
+ * yields a result row and failures surface as Spanish `error` rows while
61
+ * the surviving slices return normally. A definitive proxy rejection on
62
+ * one slice (for example an expired cursor) cancels the sibling reads
63
+ * through a shared signal, since every slice reads the same cursor.
64
+ *
65
+ * @param client - EnriProxy client
66
+ * @param cursor - Cursor addressing the capture
67
+ * @param ranges - Requested ranges
68
+ * @param maxChars - Call budget used as default slice length
69
+ * @param resolvedUrl - URL reported for the grouped result
70
+ * @param signal - Optional caller abort signal
71
+ * @returns Grouped ranges result
72
+ * @throws Error when the caller cancelled the request mid-flight
73
+ */
74
+ async executeGroupedCursorRanges(client, cursor, ranges, maxChars, resolvedUrl, signal) {
75
+ // Shared signal: caller aborts propagate to every slice, and a proxy
76
+ // rejection on one slice cancels the siblings still in flight.
77
+ const sharedController = new AbortController();
78
+ const forwardCallerAbort = () => {
79
+ sharedController.abort();
80
+ };
81
+ if (signal !== undefined) {
82
+ if (signal.aborted) {
83
+ sharedController.abort();
84
+ }
85
+ else {
86
+ signal.addEventListener("abort", forwardCallerAbort, { once: true });
87
+ }
88
+ }
89
+ const settled = await Promise.allSettled(ranges.map(async (range, index) => {
90
+ const limitChars = range.limitChars ?? maxChars;
91
+ try {
92
+ const response = await client.webFetch({ cursor, offsetChars: range.offsetChars, limitChars, maxChars }, sharedController.signal, {
93
+ // Per-slice byte ceiling: ten concurrent windows must not
94
+ // each reserve the full max_chars-derived cap (up to ~25MB);
95
+ // the expected slice payload bounds the buffer instead, so
96
+ // the grouped fan-out stays within a bounded transient
97
+ // memory budget instead of ~10x the call budget.
98
+ maxResponseBytes: 6 * Math.min(limitChars, MAX_WIRE_MAX_CHARS) + 1024 * 1024
99
+ });
100
+ return {
101
+ index: index + 1,
102
+ offset_chars: range.offsetChars,
103
+ limit_chars: limitChars,
104
+ content: response.content,
105
+ status: response.status,
106
+ content_type: response.content_type,
107
+ truncated: response.truncated,
108
+ has_more: response.has_more,
109
+ total_chars: response.total_chars,
110
+ cursor: response.cursor
111
+ };
112
+ }
113
+ catch (error) {
114
+ // A definitive proxy answer (HTTP error) rejects the cursor
115
+ // itself: every sibling slice would fail identically, so the
116
+ // shared signal cancels them instead of burning the budget.
117
+ if (error instanceof EnriProxyHttpError && !sharedController.signal.aborted) {
118
+ sharedController.abort();
119
+ }
120
+ throw error;
121
+ }
122
+ }));
123
+ if (signal !== undefined) {
124
+ signal.removeEventListener("abort", forwardCallerAbort);
125
+ }
126
+ // Caller cancellation keeps traveling as a thrown abort (SDK
127
+ // cancellation semantics) instead of a grouped result of error rows.
128
+ if (signal?.aborted) {
129
+ throw new Error("La petición fue cancelada por el cliente.");
130
+ }
131
+ const abortedBySiblingFailure = sharedController.signal.aborted && signal?.aborted !== true;
132
+ const slices = settled.map((outcome, index) => {
133
+ if (outcome.status === "fulfilled") {
134
+ return outcome.value;
135
+ }
136
+ const range = ranges[index];
137
+ const limitChars = range.limitChars ?? maxChars;
138
+ // A definitive proxy answer keeps its own message (plus the Spanish
139
+ // body diagnostic it carries) even when it triggered the shared
140
+ // abort; sibling reads cancelled by that rejection get the
141
+ // cancellation wording, and raw transport failures are wrapped in
142
+ // Spanish so no English stack jargon reaches the model.
143
+ const reason = WebFetchRangesExecutor.describeRangeFailure(outcome.reason, abortedBySiblingFailure);
144
+ return {
145
+ index: index + 1,
146
+ offset_chars: range.offsetChars,
147
+ limit_chars: limitChars,
148
+ content: "",
149
+ status: 0,
150
+ content_type: "",
151
+ truncated: false,
152
+ error: `Rango ${String(index + 1)} falló: ${reason}`
153
+ };
154
+ });
155
+ // Early reclamation parity with EnriCode: only windows that actually
156
+ // read content through the capture end count as exhaustion. Out-of-range
157
+ // empty windows (has_more: false with no content) never release, so a
158
+ // typo'd offset cannot destroy a capture whose bulk was never read.
159
+ let captureReleased = false;
160
+ const everyWindowReadThroughEnd = slices.length > 0 &&
161
+ slices.every((slice) => slice.error === undefined &&
162
+ slice.has_more === false &&
163
+ slice.content.length > 0 &&
164
+ (slice.total_chars === undefined || slice.offset_chars + slice.content.length >= slice.total_chars));
165
+ if (everyWindowReadThroughEnd) {
166
+ if (signal?.aborted !== true) {
167
+ captureReleased = true;
168
+ void client
169
+ .webFetch({ cursor, action: "delete" }, signal)
170
+ .then(() => undefined)
171
+ .catch(() => undefined);
172
+ }
173
+ }
174
+ return {
175
+ range_applied: true,
176
+ range_count: slices.length,
177
+ ranges: slices,
178
+ truncated: slices.some((slice) => slice.truncated),
179
+ range_hint: captureReleased
180
+ ? "Todas las ventanas agotaron la captura y el cursor quedó liberado del servidor; para releer el documento use la url original."
181
+ : `Vuelva a llamar web_fetch con el mismo cursor (cursor="${cursor}") y ranges para pedir otros tramos no contiguos del documento sin volver a descargarlo.`,
182
+ url: resolvedUrl,
183
+ cursor
184
+ };
185
+ }
186
+ /**
187
+ * Describes one failed range read with an honest Spanish diagnostic.
188
+ *
189
+ * @param reason - Raw rejection reason of the failed slice.
190
+ * @param abortedBySiblingFailure - Whether the shared batch abort fired.
191
+ * @returns Spanish failure description for the model-facing error row.
192
+ */
193
+ static describeRangeFailure(reason, abortedBySiblingFailure) {
194
+ if (reason instanceof EnriProxyHttpError) {
195
+ const bodyDetail = sliceUtf8Safe(reason.body.trim(), 0, 300);
196
+ return bodyDetail.length > 0 ? `${reason.message} ${bodyDetail}` : reason.message;
197
+ }
198
+ if (abortedBySiblingFailure) {
199
+ return "lectura cancelada porque el servidor rechazó el cursor en otro rango del mismo lote";
200
+ }
201
+ if (reason instanceof Error) {
202
+ return `fallo de red leyendo el rango (${sliceUtf8Safe(reason.message, 0, 120)})`;
203
+ }
204
+ return String(reason);
205
+ }
206
+ /**
207
+ * Applies grouped ranges locally over already-fetched content.
208
+ *
209
+ * @remarks
210
+ * A range whose offset lies beyond the UNDECORATED page is out of range,
211
+ * not truncated: the slice comes back empty with an honest Spanish note
212
+ * and `truncated: false`, so the model does not infer more pages behind
213
+ * an empty window. A range that starts inside the page but hits its end
214
+ * is the real truncation case. Windows address the raw page (via the
215
+ * `page_offset_chars`/`page_chars` bounds the proxy reports), so the
216
+ * status header and truncation footer never land inside a requested
217
+ * window; responses without bounds slice `content` verbatim.
218
+ *
219
+ * @param result - Single-read result holding the captured content
220
+ * @param ranges - Requested ranges
221
+ * @param maxChars - Call budget used as default slice length
222
+ * @returns Grouped ranges result
223
+ */
224
+ applyLocalRangesToResult(result, ranges, maxChars) {
225
+ const page = WebFetchRangesExecutor.readUndecoratedPage(result);
226
+ const slices = ranges.map((range, index) => {
227
+ const limitChars = range.limitChars ?? maxChars;
228
+ if (range.offsetChars >= page.length) {
229
+ return {
230
+ index: index + 1,
231
+ offset_chars: range.offsetChars,
232
+ limit_chars: limitChars,
233
+ content: "",
234
+ status: result.status,
235
+ content_type: result.content_type,
236
+ truncated: false,
237
+ note: `El offset queda fuera de la página devuelta (${String(page.length)} caracteres sin decoraciones); este rango está vacío.`
238
+ };
239
+ }
240
+ const slice = sliceUtf8Safe(page, range.offsetChars, range.offsetChars + limitChars);
241
+ return {
242
+ index: index + 1,
243
+ offset_chars: range.offsetChars,
244
+ limit_chars: limitChars,
245
+ content: slice,
246
+ status: result.status,
247
+ content_type: result.content_type,
248
+ truncated: range.offsetChars + limitChars > page.length
249
+ };
250
+ });
251
+ return {
252
+ range_applied: true,
253
+ range_count: slices.length,
254
+ ranges: slices,
255
+ truncated: result.truncated,
256
+ range_hint: "Los rangos se aplicaron localmente sobre la captura devuelta; para leer más allá de la captura vuelva a llamar web_fetch con un max_chars mayor.",
257
+ url: result.url,
258
+ // Raw-capture continuation fields only travel when the delivered
259
+ // content shares the raw base: a reduced excerpt pack reorders the
260
+ // text, and an npm projection stitches a metadata header in front of
261
+ // the README (its cursor addresses the README alone), so local offsets
262
+ // would mispage the raw capture in both cases (EnriCode excludes the
263
+ // same fields in its URL projections).
264
+ ...(result.reduced === true || result.applied_max_chars !== undefined
265
+ ? {}
266
+ : result.cursor !== undefined
267
+ ? { cursor: result.cursor }
268
+ : {}),
269
+ ...(result.reduced === true || result.applied_max_chars !== undefined
270
+ ? {}
271
+ : result.total_chars !== undefined
272
+ ? { total_chars: result.total_chars }
273
+ : {})
274
+ };
275
+ }
276
+ }
277
+ //# sourceMappingURL=WebFetchRangesExecutor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebFetchRangesExecutor.js","sourceRoot":"","sources":["../../src/tools/WebFetchRangesExecutor.ts"],"names":[],"mappings":"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"}