@ganju/utils 0.0.13 → 0.0.15

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 (70) hide show
  1. package/dist/channelCustomer.d.ts +99 -0
  2. package/dist/channelCustomer.d.ts.map +1 -0
  3. package/dist/channelCustomer.js +533 -0
  4. package/dist/channelDebounce.d.ts +7 -0
  5. package/dist/channelDebounce.d.ts.map +1 -1
  6. package/dist/chunkOverlap.d.ts +2 -0
  7. package/dist/chunkOverlap.d.ts.map +1 -0
  8. package/dist/chunkOverlap.js +9 -0
  9. package/dist/chunking.d.ts.map +1 -1
  10. package/dist/chunking.js +24 -4
  11. package/dist/citations.d.ts +28 -0
  12. package/dist/citations.d.ts.map +1 -0
  13. package/dist/citations.js +111 -0
  14. package/dist/constants.d.ts +26 -0
  15. package/dist/constants.d.ts.map +1 -1
  16. package/dist/constants.js +108 -10
  17. package/dist/index.d.ts +263 -31
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +70 -0
  20. package/dist/jsonSchemaToZodShape.d.ts +5 -1
  21. package/dist/jsonSchemaToZodShape.d.ts.map +1 -1
  22. package/dist/jsonSchemaToZodShape.js +21 -9
  23. package/dist/pagination.d.ts +47 -0
  24. package/dist/pagination.d.ts.map +1 -0
  25. package/dist/pagination.js +160 -0
  26. package/dist/processQueueBatch.d.ts +6 -1
  27. package/dist/processQueueBatch.d.ts.map +1 -1
  28. package/dist/processQueueBatch.js +23 -10
  29. package/dist/queueFailure.d.ts +14 -0
  30. package/dist/queueFailure.d.ts.map +1 -0
  31. package/dist/queueFailure.js +43 -0
  32. package/dist/resourceRerank.d.ts.map +1 -1
  33. package/dist/resourceRerank.js +3 -1
  34. package/dist/schema.d.ts +90 -26
  35. package/dist/schema.d.ts.map +1 -1
  36. package/dist/schema.js +87 -6
  37. package/dist/ssrf.d.ts +1 -0
  38. package/dist/ssrf.d.ts.map +1 -1
  39. package/dist/ssrf.js +48 -12
  40. package/dist/toolConfirmation.d.ts +48 -0
  41. package/dist/toolConfirmation.d.ts.map +1 -1
  42. package/dist/toolConfirmation.js +75 -1
  43. package/dist/toolCount.d.ts +13 -0
  44. package/dist/toolCount.d.ts.map +1 -0
  45. package/dist/toolCount.js +45 -0
  46. package/dist/toolLint.d.ts +1 -1
  47. package/dist/toolLint.d.ts.map +1 -1
  48. package/dist/toolLint.js +37 -3
  49. package/dist/untrustedContent.d.ts +135 -0
  50. package/dist/untrustedContent.d.ts.map +1 -0
  51. package/dist/untrustedContent.js +402 -0
  52. package/package.json +2 -1
  53. package/src/channelCustomer.ts +604 -0
  54. package/src/channelDebounce.ts +17 -0
  55. package/src/chunkOverlap.ts +6 -0
  56. package/src/chunking.ts +25 -4
  57. package/src/citations.ts +127 -0
  58. package/src/constants.ts +112 -10
  59. package/src/index.ts +152 -2
  60. package/src/jsonSchemaToZodShape.ts +31 -13
  61. package/src/pagination.ts +193 -0
  62. package/src/processQueueBatch.ts +42 -12
  63. package/src/queueFailure.ts +63 -0
  64. package/src/resourceRerank.ts +5 -1
  65. package/src/schema.ts +100 -4
  66. package/src/ssrf.ts +40 -11
  67. package/src/toolConfirmation.ts +123 -0
  68. package/src/toolCount.ts +53 -0
  69. package/src/toolLint.ts +46 -3
  70. package/src/untrustedContent.ts +476 -0
@@ -4,7 +4,7 @@
4
4
  // participant's next message is a plain yes. These are the pieces of that rule
5
5
  // that aren't the runner's own bookkeeping.
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.stableJson = exports.isSensitiveTool = exports.formatConfirmationSummary = exports.isConfirmationReply = exports.parseConfirmationButton = exports.confirmationButtonId = exports.confirmationButtonLabels = exports.languageFromPhoneNumber = exports.annotationsForEffect = exports.TOOL_EFFECTS = void 0;
7
+ exports.toolApprovalUrl = exports.toolApprovalStatus = exports.stableJson = exports.isSensitiveProxiedTool = exports.keepProxiedToolMarks = exports.proxiedToolAnnotations = exports.proxiedToolTrust = exports.isSensitiveTool = exports.formatConfirmationSummary = exports.isConfirmationReply = exports.parseConfirmationButton = exports.confirmationButtonId = exports.confirmationButtonLabels = exports.languageFromPhoneNumber = exports.annotationsForEffect = exports.TOOL_EFFECTS = void 0;
8
8
  // What an owner says a tool they wrote does, in the words the dashboard asks
9
9
  // it in, and the MCP annotations each answer stands for: `read` only looks
10
10
  // things up, `write` changes things that can be undone, `sensitive` sends,
@@ -223,6 +223,62 @@ exports.formatConfirmationSummary = formatConfirmationSummary;
223
223
  */
224
224
  const isSensitiveTool = (annotations) => annotations?.readOnlyHint !== true && annotations?.destructiveHint !== false;
225
225
  exports.isSensitiveTool = isSensitiveTool;
226
+ const proxiedToolTrust = (config, remoteToolName) => ({
227
+ trustHints: config?.trustAnnotations === true,
228
+ readOnly: Array.isArray(config?.readOnlyTools) &&
229
+ config.readOnlyTools.includes(remoteToolName)
230
+ });
231
+ exports.proxiedToolTrust = proxiedToolTrust;
232
+ /**
233
+ * The annotations a proxied tool is registered with. A remote server's hints
234
+ * are its own claim about itself, and one that marks a delete read-only would
235
+ * skip every confirmation — so unless the organization chose to trust that
236
+ * server, the read-only and destructive hints are dropped and the tool reads
237
+ * as sensitive by the defaults above. A tool the owner marked as only reading
238
+ * is read-only whatever the remote says, trusted or not. Clients see the
239
+ * same, so they ask about the same tools. The harmless parts (title,
240
+ * openWorldHint, idempotentHint) pass through.
241
+ */
242
+ const proxiedToolAnnotations = (annotations, trust) => {
243
+ const result = { ...annotations };
244
+ if (trust.readOnly) {
245
+ delete result.destructiveHint;
246
+ return { ...result, readOnlyHint: true };
247
+ }
248
+ if (!trust.trustHints) {
249
+ delete result.readOnlyHint;
250
+ delete result.destructiveHint;
251
+ }
252
+ return Object.keys(result).length > 0 ? result : undefined;
253
+ };
254
+ exports.proxiedToolAnnotations = proxiedToolAnnotations;
255
+ // The install-config keys that hold the owner's trust marks above.
256
+ const PROXIED_TOOL_MARK_KEYS = ['trustAnnotations', 'readOnlyTools'];
257
+ /**
258
+ * An install's new config with the owner's trust marks carried over from the
259
+ * stored one wherever the new one doesn't say. A save that only knew about
260
+ * the allow-lists (an older dashboard, a script) must not quietly turn the
261
+ * marks off; one that sends them, even as false or empty, decides.
262
+ */
263
+ const keepProxiedToolMarks = (stored, incoming) => {
264
+ if (!stored ||
265
+ typeof stored !== 'object' ||
266
+ !incoming ||
267
+ typeof incoming !== 'object') {
268
+ return incoming;
269
+ }
270
+ const merged = { ...incoming };
271
+ for (const key of PROXIED_TOOL_MARK_KEYS) {
272
+ if (merged[key] === undefined && key in stored) {
273
+ merged[key] = stored[key];
274
+ }
275
+ }
276
+ return merged;
277
+ };
278
+ exports.keepProxiedToolMarks = keepProxiedToolMarks;
279
+ /** Whether a proxied tool is confirmed, decided as its registration is. */
280
+ const isSensitiveProxiedTool = (annotations, trust) => (0, exports.isSensitiveTool)((0, exports.proxiedToolAnnotations)(annotations, trust));
281
+ exports.isSensitiveProxiedTool = isSensitiveProxiedTool;
226
282
  // JSON with keys sorted at every depth, so two argument objects that say the
227
283
  // same thing serialize the same whatever order the model emitted them in.
228
284
  const stableJson = (value) => {
@@ -237,3 +293,21 @@ const stableJson = (value) => {
237
293
  return JSON.stringify(value) ?? 'null';
238
294
  };
239
295
  exports.stableJson = stableJson;
296
+ /**
297
+ * Where an approval stands. Spent and refused come first, since an answer
298
+ * stays the answer after the window closes; past its time, one never answered
299
+ * or never used can no longer be.
300
+ */
301
+ const toolApprovalStatus = (approval, now = Date.now()) => {
302
+ if (approval.usedAt)
303
+ return 'used';
304
+ if (approval.deniedAt)
305
+ return 'denied';
306
+ if (approval.expiresAt.getTime() <= now)
307
+ return 'expired';
308
+ return approval.approvedAt ? 'approved' : 'pending';
309
+ };
310
+ exports.toolApprovalStatus = toolApprovalStatus;
311
+ /** The dashboard page where the user answers one approval. */
312
+ const toolApprovalUrl = (webUrl, path, approvalId) => `${webUrl.replace(/\/+$/, '')}${path}/${encodeURIComponent(approvalId)}`;
313
+ exports.toolApprovalUrl = toolApprovalUrl;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * An mcp-proxy row exposes each discovered remote tool its allow-list keeps,
3
+ * so a single GitHub install can be dozens of tools. A custom-code row exposes
4
+ * the functions of its published version the allow-list keeps — pass their
5
+ * names as `customCodeFunctions`; without them the row counts as one. Every
6
+ * other row is one tool.
7
+ */
8
+ export declare const countInstallTools: (install: {
9
+ toolKey: string;
10
+ config: unknown;
11
+ metadata: unknown;
12
+ }, customCodeFunctions?: string[]) => number;
13
+ //# sourceMappingURL=toolCount.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toolCount.d.ts","sourceRoot":"","sources":["../src/toolCount.ts"],"names":[],"mappings":"AAqBA;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,GAC5B,SAAS;IACP,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;CACnB,EACD,sBAAsB,MAAM,EAAE,KAC7B,MAiBF,CAAC"}
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ // How many tools an install puts in front of a model, which is what the tool
3
+ // limit counts. Imports nothing, so node --test runs it directly.
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.countInstallTools = void 0;
6
+ // The same values as constants.TOOL_DEFINITION_KEY_MCP_PROXY and
7
+ // TOOL_DEFINITION_KEY_CUSTOM_CODE, written out rather than imported, since
8
+ // this file imports nothing.
9
+ const MCP_PROXY_TOOL_KEY = 'mcp-proxy';
10
+ const CUSTOM_CODE_TOOL_KEY = 'custom-code';
11
+ // The tools an allow-list keeps out of `names`. An empty or absent list keeps
12
+ // all of them, as the MCP boot loop reads it.
13
+ const allowedCount = (names, config) => {
14
+ const allowedTools = config
15
+ ?.allowedTools;
16
+ if (!Array.isArray(allowedTools) || allowedTools.length === 0) {
17
+ return names.length;
18
+ }
19
+ const allowed = new Set(allowedTools);
20
+ return names.filter(name => allowed.has(name)).length;
21
+ };
22
+ /**
23
+ * An mcp-proxy row exposes each discovered remote tool its allow-list keeps,
24
+ * so a single GitHub install can be dozens of tools. A custom-code row exposes
25
+ * the functions of its published version the allow-list keeps — pass their
26
+ * names as `customCodeFunctions`; without them the row counts as one. Every
27
+ * other row is one tool.
28
+ */
29
+ const countInstallTools = (install, customCodeFunctions) => {
30
+ if (install.toolKey === CUSTOM_CODE_TOOL_KEY) {
31
+ return customCodeFunctions
32
+ ? allowedCount(customCodeFunctions, install.config)
33
+ : 1;
34
+ }
35
+ if (install.toolKey !== MCP_PROXY_TOOL_KEY)
36
+ return 1;
37
+ const discovered = install.metadata?.discovery?.tools;
38
+ if (!Array.isArray(discovered))
39
+ return 0;
40
+ const names = discovered
41
+ .map(tool => tool?.name)
42
+ .filter((name) => typeof name === 'string');
43
+ return allowedCount(names, install.config);
44
+ };
45
+ exports.countInstallTools = countInstallTools;
@@ -10,7 +10,7 @@ export interface LintableTool {
10
10
  openWorldHint?: boolean;
11
11
  };
12
12
  }
13
- export declare const TOOL_LINT_RULES: readonly ["missing-description", "short-description", "no-usage-guidance", "missing-annotations", "undescribed-input", "overlapping-tools", "too-many-tools"];
13
+ export declare const TOOL_LINT_RULES: readonly ["missing-description", "short-description", "no-usage-guidance", "missing-annotations", "undescribed-input", "reserved-input", "overlapping-tools", "too-many-tools"];
14
14
  export type ToolLintRule = (typeof TOOL_LINT_RULES)[number];
15
15
  export interface ToolLintFinding {
16
16
  rule: ToolLintRule;
@@ -1 +1 @@
1
- {"version":3,"file":"toolLint.d.ts","sourceRoot":"","sources":["../src/toolLint.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE;QACZ,YAAY,CAAC,EAAE,OAAO,CAAC;QACvB,eAAe,CAAC,EAAE,OAAO,CAAC;QAC1B,cAAc,CAAC,EAAE,OAAO,CAAC;QACzB,aAAa,CAAC,EAAE,OAAO,CAAC;KACzB,CAAC;CACH;AAED,eAAO,MAAM,eAAe,+JAQlB,CAAC;AAEX,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAE5D,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,YAAY,CAAC;IAGnB,IAAI,CAAC,EAAE,MAAM,CAAC;IAGd,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IAEjB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IAEjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IAGf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAI9B,MAAM,CAAC,EAAE,YAAY,EAAE,CAAC;IAGxB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAID,eAAO,MAAM,gCAAgC,KAAK,CAAC;AAKnD,eAAO,MAAM,mBAAmB,KAAK,CAAC;AA2ItC;;;GAGG;AACH,eAAO,MAAM,SAAS,GACpB,OAAO,YAAY,EAAE,EACrB,UAAS,eAAoB,KAC5B,eAAe,EA8FjB,CAAC"}
1
+ {"version":3,"file":"toolLint.d.ts","sourceRoot":"","sources":["../src/toolLint.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE;QACZ,YAAY,CAAC,EAAE,OAAO,CAAC;QACvB,eAAe,CAAC,EAAE,OAAO,CAAC;QAC1B,cAAc,CAAC,EAAE,OAAO,CAAC;QACzB,aAAa,CAAC,EAAE,OAAO,CAAC;KACzB,CAAC;CACH;AAED,eAAO,MAAM,eAAe,iLASlB,CAAC;AAEX,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAE5D,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,YAAY,CAAC;IAGnB,IAAI,CAAC,EAAE,MAAM,CAAC;IAGd,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IAGjB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IAEjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IAGf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAI9B,MAAM,CAAC,EAAE,YAAY,EAAE,CAAC;IAGxB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAID,eAAO,MAAM,gCAAgC,KAAK,CAAC;AAKnD,eAAO,MAAM,mBAAmB,KAAK,CAAC;AA0KtC;;;GAGG;AACH,eAAO,MAAM,SAAS,GACpB,OAAO,YAAY,EAAE,EACrB,UAAS,eAAoB,KAC5B,eAAe,EAwGjB,CAAC"}
package/dist/toolLint.js CHANGED
@@ -19,6 +19,7 @@ exports.TOOL_LINT_RULES = [
19
19
  'no-usage-guidance',
20
20
  'missing-annotations',
21
21
  'undescribed-input',
22
+ 'reserved-input',
22
23
  'overlapping-tools',
23
24
  'too-many-tools'
24
25
  ];
@@ -44,8 +45,11 @@ const fold = (text) => text
44
45
  // Wording that tells a model WHEN to call a tool rather than only what it does
45
46
  // — English, Spanish and Portuguese, the languages descriptions here are
46
47
  // written in. Loose on purpose: a false "says when" costs nothing, a false
47
- // "doesn't" nags someone whose description is fine.
48
- const USAGE_GUIDANCE = /\b(use|uses|using|call|calls|when|whenever|before|after|instead|only if|if the user|if you|for questions|usa|usala|usalo|usar|llama|llamala|llamar|cuando|antes de|despues de|en lugar de|si el usuario|quando|use-a|utilize|chame)\b/;
48
+ // "doesn't" nags someone whose description is fine. But not so loose that
49
+ // words about how a tool works count: "uses the Stripe API" and "makes an API
50
+ // call" say nothing about when to reach for it, so "call" counts only as an
51
+ // instruction ("call this…", "call it…").
52
+ const USAGE_GUIDANCE = /\b(use|call (?:this|it)|when|whenever|before|after|instead|only if|if the user|if you|for questions|usa|usala|usalo|usar|llama|llamala|llamar|cuando|antes de|despues de|en lugar de|si el usuario|quando|use-a|utilize|chame)\b/;
49
53
  const STOPWORDS = new Set([
50
54
  'the',
51
55
  'and',
@@ -87,8 +91,19 @@ const STOPWORDS = new Set([
87
91
  const contentWords = (text) => new Set(fold(text)
88
92
  .split(/[^a-z0-9]+/)
89
93
  .filter(word => word.length >= 3 && !STOPWORDS.has(word)));
94
+ // A proxied tool is named `<server prefix>__<remote name>`. The prefix says
95
+ // which connection it came from, not what it does, so `search_repositories`
96
+ // and `github__search_repositories` are the same tool to a model. Kept here
97
+ // rather than imported from constants (MCP_PROXY_TOOL_NAME_SEP), since this
98
+ // file imports nothing.
99
+ const PROXY_NAME_SEP = '__';
100
+ const withoutProxyPrefix = (name) => {
101
+ const at = name.lastIndexOf(PROXY_NAME_SEP);
102
+ const bare = at === -1 ? name : name.slice(at + PROXY_NAME_SEP.length);
103
+ return bare || name;
104
+ };
90
105
  // `lookupOrder`, `lookup-order` and `order_lookup` name the same thing.
91
- const nameTokens = (name) => name
106
+ const nameTokens = (name) => withoutProxyPrefix(name)
92
107
  .replace(/([a-z0-9])([A-Z])/g, '$1 $2')
93
108
  .toLowerCase()
94
109
  .split(/[^a-z0-9]+/)
@@ -146,6 +161,16 @@ const undescribedPaths = (schema, prefix = '') => {
146
161
  }
147
162
  return paths;
148
163
  };
164
+ // Top-level input names the server takes for itself. `confirmation` carries
165
+ // the token a sensitive tool's second call brings back: the server replaces a
166
+ // property of that name and strips it before the tool runs, so it never
167
+ // reaches the tool.
168
+ // Kept here rather than imported from constants (MCP_TOOL_CONFIRMATION_ARG),
169
+ // since this file imports nothing.
170
+ const RESERVED_INPUT_NAMES = ['confirmation'];
171
+ const reservedPaths = (schema) => isObject(schema) && isObject(schema.properties)
172
+ ? RESERVED_INPUT_NAMES.filter(name => Object.prototype.hasOwnProperty.call(schema.properties, name))
173
+ : [];
149
174
  const quoted = (name) => `"${name}"`;
150
175
  /**
151
176
  * Check a set of tools for what makes them hard for a model to use. Findings
@@ -211,6 +236,15 @@ const lintTools = (tools, options = {}) => {
211
236
  message: `${quoted(tool.name)} has input properties with no description: ${paths.join(', ')}. A model has to guess what to pass.`
212
237
  });
213
238
  }
239
+ const reserved = reservedPaths(tool.inputSchema);
240
+ if (reserved.length > 0) {
241
+ findings.push({
242
+ rule: 'reserved-input',
243
+ tool: tool.name,
244
+ paths: reserved,
245
+ message: `${quoted(tool.name)} has an input named ${reserved.map(quoted).join(', ')}, which the server keeps for confirming sensitive actions: on a tool it confirms, that property is replaced and its value never reaches the tool. Rename it.`
246
+ });
247
+ }
214
248
  // Each pair once — against the tools after this one, then the rest of the
215
249
  // server — and one finding per tool, so twenty look-alikes are nineteen
216
250
  // lines rather than a hundred and ninety.
@@ -0,0 +1,135 @@
1
+ export declare const UNTRUSTED_CONTENT_TAG = "untrusted_content";
2
+ export declare const UNTRUSTED_CONTENT_META_KEY = "ganju.ai/untrusted";
3
+ export declare const UNTRUSTED_CONTENT_NOTE: string;
4
+ /**
5
+ * Wrap text that came from outside in the marks the model is told about.
6
+ * `source` says where it came from (a tool name, a URI) and is reduced to
7
+ * characters that can't close the attribute.
8
+ */
9
+ export declare const wrapUntrustedContent: (source: string, text: string) => string;
10
+ /**
11
+ * The text inside a wrapped block, for code that reads a tool's result itself
12
+ * (citations parse search results as JSON). Text that isn't one block is
13
+ * returned as it is.
14
+ */
15
+ export declare const unwrapUntrustedContent: (text: string) => string;
16
+ /** Whether a tool result carries the flag set by the server that ran it. */
17
+ export declare const isUntrustedToolResult: (result: unknown) => boolean;
18
+ export declare const INSTRUCTION_WARNING_METADATA_KEY = "instructionWarning";
19
+ export interface InstructionWarning {
20
+ passages: string[];
21
+ checkedAt: string;
22
+ }
23
+ /**
24
+ * The passages of `text` that read like instructions to an AI model, as the
25
+ * document wrote them, at most five and each cut to a readable length. Empty
26
+ * when nothing matched.
27
+ */
28
+ export declare const findInstructionLikeText: (text: string) => string[];
29
+ type ContentBlock = {
30
+ type: string;
31
+ text?: string;
32
+ [key: string]: unknown;
33
+ };
34
+ export interface LabelledToolResult {
35
+ content: ContentBlock[];
36
+ structuredContent?: unknown;
37
+ isError?: boolean;
38
+ _meta?: Record<string, unknown>;
39
+ }
40
+ /**
41
+ * Outside text as a tool result: wrapped, and flagged so that a sensitive call
42
+ * made after it asks first. `flag: false` labels without flagging — for the
43
+ * organization's own knowledge base, where reading a clean document shouldn't
44
+ * make every later action ask.
45
+ */
46
+ export declare const untrustedToolResult: (source: string, text: string, options?: {
47
+ flag?: boolean;
48
+ }) => {
49
+ content: Array<{
50
+ type: "text";
51
+ text: string;
52
+ }>;
53
+ _meta?: Record<string, unknown>;
54
+ };
55
+ /**
56
+ * Mostly the user's own writing, but able to quote someone else's — a draft
57
+ * carrying the email it replies to. Labelled always, flagged only when it
58
+ * reads like instructions, so "show my drafts, then send that one" doesn't
59
+ * ask every time.
60
+ */
61
+ export declare const ownWritingToolResult: (source: string, text: string) => {
62
+ content: Array<{
63
+ type: "text";
64
+ text: string;
65
+ }>;
66
+ _meta?: Record<string, unknown>;
67
+ };
68
+ /**
69
+ * What one of the organization's own integrations (an HTTP endpoint, a custom
70
+ * tool) brought back. The integration is the owner's, but the data may not be
71
+ * — a support ticket, a product review — so its text is wrapped. Flagged only
72
+ * when it reads like instructions: a menu lookup before an order is the
73
+ * ordinary case. A declared output schema makes the structured copy required,
74
+ * so it stays and can't carry the label, but it is read for instructions all
75
+ * the same. Errors pass through as they are: a tool whose error carries
76
+ * outside text labels that part itself (see untrustedErrorResult).
77
+ */
78
+ export declare const labelOwnToolResult: <T extends LabelledToolResult>(result: T, source: string) => T;
79
+ /**
80
+ * A failure whose message carries text from outside — an endpoint's error
81
+ * body, a remote server's or a script's error. `message` is ours and stays
82
+ * first, so the result still reads as an `Error:`; `detail` is wrapped.
83
+ * Flagged always unless `flag: false`, which the organization's own
84
+ * integrations pass with whether the detail reads like instructions.
85
+ */
86
+ export declare const untrustedErrorResult: (message: string, source: string, detail: string, options?: {
87
+ flag?: boolean;
88
+ }) => {
89
+ content: Array<{
90
+ type: "text";
91
+ text: string;
92
+ }>;
93
+ isError: true;
94
+ _meta?: Record<string, unknown>;
95
+ };
96
+ /** Whether text reads like instructions to the model. */
97
+ export declare const readsLikeInstructions: (text: string) => boolean;
98
+ type ResourceContent = {
99
+ uri: string;
100
+ text?: string;
101
+ [key: string]: unknown;
102
+ };
103
+ /**
104
+ * A resource read, as it goes back to the model: each text part wrapped under
105
+ * its own uri, binary parts as they are. `instructionLike` says whether any
106
+ * text part reads like instructions, for the caller deciding whether to flag
107
+ * the session.
108
+ */
109
+ export declare const labelResourceContents: <T extends ResourceContent>(contents: T[]) => {
110
+ contents: T[];
111
+ instructionLike: boolean;
112
+ };
113
+ /**
114
+ * A remote MCP server's tool result, as it goes back through the proxy.
115
+ *
116
+ * Within `maxBytes` the blocks are kept as they are; past it they are
117
+ * flattened to one text block, structured copy included, since the SDK can't
118
+ * return several large blocks in one result. Whatever the remote answers was written by someone
119
+ * else, so every text block is labelled and the result is always flagged.
120
+ * Images and other blocks pass through.
121
+ *
122
+ * A structured copy can't carry the label, and some clients hand the model
123
+ * that copy instead of the text. Proxied tools register no output schema, so
124
+ * the copy is optional: it is folded into the labelled text (as JSON, unless a
125
+ * text block already says exactly that) and dropped. A copy alone counts as
126
+ * content — "(the tool returned no content)" is only for a result that has
127
+ * neither.
128
+ */
129
+ export declare const labelProxiedToolResult: (raw: {
130
+ content?: unknown;
131
+ structuredContent?: unknown;
132
+ isError?: boolean;
133
+ }, source: string, maxBytes: number) => LabelledToolResult;
134
+ export {};
135
+ //# sourceMappingURL=untrustedContent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"untrustedContent.d.ts","sourceRoot":"","sources":["../src/untrustedContent.ts"],"names":[],"mappings":"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"}