@anuma/sdk 3.0.0 → 3.1.1

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.
@@ -0,0 +1,1380 @@
1
+ type LlmapiChatCompletionTool = {
2
+ [key: string]: unknown;
3
+ };
4
+
5
+ /**
6
+ * Tool executor function type
7
+ */
8
+ type ToolExecutor = (args: Record<string, unknown>) => Promise<unknown> | unknown;
9
+ /**
10
+ * Tool configuration with optional executor
11
+ */
12
+ type ToolConfig = LlmapiChatCompletionTool & {
13
+ /**
14
+ * Function to execute when the tool is called.
15
+ * If provided, the tool will be executed automatically when the LLM calls it.
16
+ * If not provided, an onToolCall event will be emitted instead.
17
+ */
18
+ executor?: ToolExecutor;
19
+ /**
20
+ * Whether to skip sending the tool result back to the model as a continuation.
21
+ * When true, the tool is executed but its result is not fed back to the model.
22
+ * Useful for display-only tools (charts, weather cards) that render client-side
23
+ * and don't need a model follow-up.
24
+ */
25
+ skipContinuation?: boolean;
26
+ /**
27
+ * Whether to remove this tool from the tools list after it has been
28
+ * successfully executed. This prevents smaller models from calling
29
+ * the same tool repeatedly in continuation requests.
30
+ *
31
+ * Only applies when the tool has an executor. The tool is kept if
32
+ * execution fails, allowing the model to retry.
33
+ */
34
+ removeAfterExecution?: boolean;
35
+ /**
36
+ * Timeout in milliseconds for this tool's executor.
37
+ * Overrides the default 30-second timeout.
38
+ * Set to `Infinity` to disable the timeout (e.g. for interactive tools
39
+ * that wait for user input).
40
+ * @default 30000
41
+ */
42
+ executorTimeout?: number;
43
+ /**
44
+ * When PII redaction is active, de-anonymize this tool's call arguments
45
+ * (restore original values for any `[CATEGORY_n]` placeholders) BEFORE the
46
+ * executor runs, using the same redactor that redacted the request this turn.
47
+ * Opt in only for tools that act on data that stays on the device — e.g.
48
+ * `memory_vault_save`, which must persist the real value, not a placeholder.
49
+ * Leave off for tools that forward arguments off-device (connectors), so PII
50
+ * stays redacted on the wire.
51
+ * @default false
52
+ */
53
+ deAnonymizeArgs?: boolean;
54
+ /**
55
+ * Tool names that this tool depends on. When multiple tools are called in
56
+ * the same response, tools with `dependsOn` will wait for the named tools
57
+ * to finish executing before starting.
58
+ *
59
+ * Example: `display_slides` depends on `create_file` because it reads
60
+ * files from IndexedDB that `create_file` writes.
61
+ */
62
+ dependsOn?: string[];
63
+ };
64
+
65
+ /**
66
+ * Server-side tools caching module
67
+ *
68
+ * Fetches and caches tools from /api/v1/tools endpoint
69
+ * with configurable expiration and localStorage persistence.
70
+ */
71
+
72
+ /** Tool parameters schema */
73
+ interface ToolParameters {
74
+ properties: Record<string, unknown>;
75
+ required: string[];
76
+ type: "object";
77
+ }
78
+ /** Current API response format (description and parameters at top level) */
79
+ interface ServerToolsResponseItemCurrent {
80
+ description: string;
81
+ name: string;
82
+ parameters: ToolParameters;
83
+ }
84
+ /** New API response format with schema wrapper */
85
+ interface ServerToolsResponseItemNew {
86
+ name: string;
87
+ schema: {
88
+ name: string;
89
+ description: string;
90
+ parameters: ToolParameters;
91
+ };
92
+ cost?: number;
93
+ embedding?: number[];
94
+ }
95
+ /** Response item can be either format */
96
+ type ServerToolsResponseItem = ServerToolsResponseItemCurrent | ServerToolsResponseItemNew;
97
+ /** Tools object mapping tool names to their definitions */
98
+ type ServerToolsMap = {
99
+ [toolName: string]: ServerToolsResponseItem;
100
+ };
101
+ /**
102
+ * Response format from /api/v1/tools endpoint.
103
+ * New format includes checksum and tools wrapper.
104
+ * Legacy format is just the tools map directly.
105
+ */
106
+ type ServerToolsResponse = {
107
+ checksum: string;
108
+ tools: ServerToolsMap;
109
+ } | ServerToolsMap;
110
+ /**
111
+ * Server tool definition with parameters field.
112
+ * This is the neutral format stored in cache.
113
+ * Strategies transform this to the correct API format.
114
+ */
115
+ interface ServerTool {
116
+ type: "function";
117
+ name: string;
118
+ description: string;
119
+ parameters: {
120
+ type: string;
121
+ properties: Record<string, unknown>;
122
+ required: string[];
123
+ };
124
+ /** Optional embedding vector for semantic matching */
125
+ embedding?: number[];
126
+ }
127
+ /**
128
+ * Cached tools structure stored in localStorage
129
+ */
130
+ interface CachedServerTools {
131
+ tools: ServerTool[];
132
+ timestamp: number;
133
+ version: string;
134
+ /** Checksum from the server for cache invalidation */
135
+ checksum?: string;
136
+ }
137
+ /**
138
+ * Pluggable persistence for the fetched server-tools list.
139
+ *
140
+ * The default backend ({@link localStorageToolsCache}) writes to browser
141
+ * `localStorage` and is a silent no-op where `localStorage` is undefined
142
+ * (Node, React Native). Pass a custom backend to `getServerTools` to cache
143
+ * somewhere that survives on those platforms — e.g. an AsyncStorage/MMKV
144
+ * adapter on RN, or an in-memory `Map` on a server. Methods may be sync or
145
+ * async; `getServerTools` awaits them either way.
146
+ *
147
+ * The stored payload carries a `version`; `getServerTools` discards any entry
148
+ * whose version does not match the current cache format, so a stale custom
149
+ * backend can never feed an incompatible shape back into selection.
150
+ */
151
+ interface ToolsCacheBackend {
152
+ /** Return the cached payload, or null when absent/unreadable. */
153
+ get(): CachedServerTools | null | Promise<CachedServerTools | null>;
154
+ /** Persist the payload. Implementations should swallow write failures. */
155
+ set(value: CachedServerTools): void | Promise<void>;
156
+ /**
157
+ * Remove the cached payload. Optional — a read/write-only backend may omit it,
158
+ * in which case `clearServerToolsCache` (and the version-mismatch
159
+ * invalidation) is a no-op for that backend. The default
160
+ * {@link localStorageToolsCache} implements it.
161
+ */
162
+ clear?(): void | Promise<void>;
163
+ }
164
+ /**
165
+ * Options for fetching server tools
166
+ */
167
+ interface ServerToolsOptions {
168
+ /** Base URL for the API (defaults to BASE_URL from clientConfig) */
169
+ baseUrl?: string;
170
+ /** Cache expiration time in milliseconds (default: 5 minutes) */
171
+ cacheExpirationMs?: number;
172
+ /** Force refresh even if cache is valid */
173
+ forceRefresh?: boolean;
174
+ /** Authentication token getter (uses Authorization: Bearer header) */
175
+ getToken?: () => Promise<string | null>;
176
+ /** Direct API key for server-side usage (uses X-API-Key header) */
177
+ apiKey?: string;
178
+ /**
179
+ * Where to read/write the cached tools list. Defaults to
180
+ * {@link localStorageToolsCache} (browser `localStorage`; no-op elsewhere).
181
+ * Provide a backend to enable caching on Node / React Native.
182
+ */
183
+ cache?: ToolsCacheBackend;
184
+ }
185
+ /** Default cache expiration: 1 day */
186
+ declare const DEFAULT_CACHE_EXPIRATION_MS: number;
187
+ /** Minimum prompt length for tool matching. Shorter prompts skip embedding. */
188
+ declare const MIN_CONTENT_LENGTH_FOR_TOOLS = 5;
189
+ /**
190
+ * Max client tools to include after automatic semantic filtering.
191
+ * Set high — CLIENT_TOOLS_RELEVANCE_RATIO does the real trimming; this
192
+ * is just a safety cap to avoid pathological cases.
193
+ */
194
+ declare const MAX_CLIENT_TOOLS_AFTER_FILTER = 10;
195
+ /** Minimum similarity for client tool semantic matching. */
196
+ declare const CLIENT_TOOLS_MIN_SIMILARITY = 0.53;
197
+ /**
198
+ * Client-tool relevance ratio: drop tools scoring below this fraction of the
199
+ * top match. 0.75, not 0.9 — multi-intent prompts ("weather in Tokyo, and
200
+ * chart the temperature trend") embed dominated by one intent, so the second
201
+ * tool lands around 75-80% of the top score; at 0.9 the second intent could
202
+ * NEVER survive, no matter how good its description (measured: display_chart
203
+ * 0.62 vs display_weather 0.81 → ratio 0.77).
204
+ */
205
+ declare const CLIENT_TOOLS_RELEVANCE_RATIO = 0.75;
206
+ /**
207
+ * Result of parsing server tools response
208
+ */
209
+ interface ParsedServerToolsResponse {
210
+ tools: ServerTool[];
211
+ checksum?: string;
212
+ }
213
+ /**
214
+ * Get cached tools from localStorage
215
+ */
216
+ declare function getCachedServerTools(): CachedServerTools | null;
217
+ declare const localStorageToolsCache: ToolsCacheBackend;
218
+ /**
219
+ * Clear the cached server tools. Defaults to the browser-`localStorage` backend;
220
+ * pass the SAME {@link ToolsCacheBackend} you gave `getServerTools` to invalidate
221
+ * a custom backend (a no-op when that backend defines no `clear`). Returns the
222
+ * backend's clear result, which may be async.
223
+ */
224
+ declare function clearServerToolsCache(): void;
225
+ declare function clearServerToolsCache(cache: ToolsCacheBackend): void | Promise<void>;
226
+ /**
227
+ * Get the checksum of the currently cached tools, or undefined when there is no
228
+ * cache / no stored checksum. Defaults to the browser-`localStorage` backend;
229
+ * pass the SAME backend you gave `getServerTools` to read a custom backend's
230
+ * checksum (an async backend yields a promise).
231
+ */
232
+ declare function getToolsChecksum(): string | undefined;
233
+ declare function getToolsChecksum(cache: ToolsCacheBackend): string | undefined | Promise<string | undefined>;
234
+ /**
235
+ * Check if tools should be refreshed based on checksum comparison.
236
+ * Returns true if:
237
+ * - responseChecksum is provided and differs from cached checksum
238
+ * - No cached checksum exists (first time with checksum support)
239
+ *
240
+ * Returns false if:
241
+ * - responseChecksum is not provided (legacy response)
242
+ * - Checksums match
243
+ */
244
+ declare function shouldRefreshTools(responseChecksum: string | undefined): boolean;
245
+ declare function shouldRefreshTools(responseChecksum: string | undefined, cache: ToolsCacheBackend | undefined): boolean | Promise<boolean>;
246
+ /**
247
+ * Get server tools with caching support.
248
+ *
249
+ * Flow:
250
+ * 1. Check the cache backend (localStorage by default; override via `cache`)
251
+ * 2. If cache valid and not force refresh, return cached tools
252
+ * 3. Otherwise, fetch from API, cache, and return
253
+ * 4. On fetch failure, return cached tools if available (stale-while-error)
254
+ */
255
+ declare function getServerTools(options: ServerToolsOptions): Promise<ServerTool[]>;
256
+ /**
257
+ * Filter server tools by name.
258
+ * @param serverTools - All server tools
259
+ * @param includeNames - Names to include (undefined = all, [] = none)
260
+ */
261
+ declare function filterServerTools(serverTools: ServerTool[], includeNames?: string[]): ServerTool[];
262
+ /**
263
+ * Opt-in defer-loading config for {@link mergeTools}. OFF by default — when absent or `enabled:false`,
264
+ * tools are emitted exactly as today (no ordering change, no defer flags, no search tool). When ON, the
265
+ * server tools are emitted as the full catalog in a deterministic, byte-stable order every turn:
266
+ * `[tool-search] → [hot, in hotToolNames order] → [deferred, name-sorted]`, with `defer_loading:true` on
267
+ * every tool that is neither hot nor the search tool. Deferred tools keep their FULL definition (so
268
+ * Anthropic's matcher can index them); they are not reduced to names. This stabilizes the leading `tools`
269
+ * prefix so Anthropic prompt caching can hit across turns.
270
+ */
271
+ interface DeferLoadingConfig {
272
+ enabled: boolean;
273
+ /** Server-tool names to keep non-deferred (besides the tool-search tool), in priority order. */
274
+ hotToolNames: readonly string[];
275
+ }
276
+ declare function mergeTools(serverTools: ServerTool[], clientTools: Array<LlmapiChatCompletionTool | ToolConfig> | undefined, apiType?: "responses" | "completions", deferConfig?: DeferLoadingConfig): Array<Record<string, unknown>>;
277
+ /**
278
+ * Result of tool matching with similarity score
279
+ */
280
+ interface ToolMatchResult {
281
+ tool: ServerTool;
282
+ similarity: number;
283
+ }
284
+ /**
285
+ * Options for findMatchingTools
286
+ */
287
+ interface ToolMatchOptions {
288
+ /** Maximum number of tools to return (default: 5) */
289
+ limit?: number;
290
+ /** Minimum similarity threshold 0-1 (default: 0.3) */
291
+ minSimilarity?: number;
292
+ /**
293
+ * When enabled, returns empty results if the top match doesn't clearly
294
+ * stand out from the runner-up. This filters out generic prompts like
295
+ * "hello" or "tell me a joke" where all tools score similarly low.
296
+ *
297
+ * A match is considered ambiguous when:
298
+ * - The top score is below `ambiguityThreshold` (default: 0.55), AND
299
+ * - The gap between the top score and the runner-up is below `minLead` (default: 0.04)
300
+ */
301
+ filterAmbiguous?: boolean;
302
+ /** Top score must be above this to skip the ambiguity check (default: 0.55) */
303
+ ambiguityThreshold?: number;
304
+ /** Minimum gap between top and runner-up scores (default: 0.04) */
305
+ minLead?: number;
306
+ /**
307
+ * Only keep tools scoring at least this fraction of the top match's score.
308
+ * Filters out the tail of weakly-related tools that fill up the limit.
309
+ * For example, 0.85 means a tool must score within 85% of the top match.
310
+ * Set to 0 to disable. Default: 0 (disabled).
311
+ */
312
+ relevanceRatio?: number;
313
+ }
314
+ /**
315
+ * Find tools that semantically match prompt embedding(s).
316
+ *
317
+ * Accepts either a single embedding or an array of embeddings (e.g., from chunked messages).
318
+ * When multiple embeddings are provided, uses max similarity across all chunks for each tool.
319
+ *
320
+ * @param promptEmbeddings - Single embedding vector or array of embeddings (for chunked messages)
321
+ * @param tools - Array of server tools (with embeddings) to search through
322
+ * @param options - Optional matching configuration
323
+ * @returns Array of matching tools with similarity scores, sorted by relevance
324
+ *
325
+ * @example
326
+ * ```ts
327
+ * // Single embedding
328
+ * const matches = findMatchingTools(embedding, tools, { limit: 5 });
329
+ *
330
+ * // Multiple embeddings (chunked message) - uses max similarity
331
+ * const matches = findMatchingTools(chunkEmbeddings, tools, { limit: 5 });
332
+ * ```
333
+ */
334
+ declare function findMatchingTools(promptEmbeddings: number[] | number[][], tools: ServerTool[], options?: ToolMatchOptions): ToolMatchResult[];
335
+ /**
336
+ * Compute the raw max similarity for every tool with a valid embedding,
337
+ * without any filtering (no `minSimilarity`, no `relevanceRatio`, no
338
+ * ambiguity check, no limit). Use this when you need true per-tool scores
339
+ * — e.g., to drive `expandToolSetsAdditive`'s anchor activation without
340
+ * letting `findMatchingTools`' relevance cutoff silently drop sub-threshold
341
+ * anchors that should still trigger their set.
342
+ */
343
+ declare function scoreTools(promptEmbeddings: number[] | number[][], tools: ServerTool[]): Map<string, number>;
344
+ /**
345
+ * A tool set defines a group of tools that work together. When any "anchor"
346
+ * tool in the set is matched semantically (with a score at or above
347
+ * `anchorMinSimilarity`), the set is activated and all of its members are
348
+ * pulled into the selection.
349
+ *
350
+ * Two activation strategies consume this interface:
351
+ * - `expandToolSetsAdditive` (used by `useChatStorage` and
352
+ * `createServerToolsFilter`) keeps all original matches and adds the
353
+ * set's members on top — non-set tools are never dropped.
354
+ * - `applyToolSets` is exclusive: it keeps only set members plus non-set
355
+ * tools that scored above `independentThreshold`.
356
+ *
357
+ * Pick `expandToolSetsAdditive` when you want recall over precision
358
+ * (typical), and `applyToolSets` when you specifically want non-set
359
+ * matches stripped on activation.
360
+ */
361
+ interface ToolSet {
362
+ /** Human-readable name for logging/debugging */
363
+ name: string;
364
+ /** All tool names in the set */
365
+ members: string[];
366
+ /**
367
+ * Tools that trigger the set when selected. If any anchor appears in the
368
+ * semantic match results with a score at or above `anchorMinSimilarity`,
369
+ * all members are pulled in.
370
+ */
371
+ anchors: string[];
372
+ /**
373
+ * Minimum similarity an anchor must reach to activate the set.
374
+ * Prevents false activation on prompts where the anchor barely passes
375
+ * the global minSimilarity threshold. Default: 0.60
376
+ */
377
+ anchorMinSimilarity?: number;
378
+ /**
379
+ * System-prompt fragment to APPEND to the base prompt when this set
380
+ * activates. Additive, never a replacement — it composes with the host's
381
+ * persona / memory. Gated on genuine activation (anchor score ≥
382
+ * `anchorMinSimilarity`, or a forced set) via {@link activatedToolSetNames} →
383
+ * {@link toolSetSystemPrompts}, NOT on mere anchor presence — a borderline
384
+ * anchor kept by recall-over-precision must not drag this persona in. Write
385
+ * it to be self-limiting too (condition its behavior on the user actually
386
+ * wanting what the set does), so a borderline activation doesn't bias the turn.
387
+ */
388
+ systemPrompt?: string;
389
+ }
390
+ /** Built-in tool sets. Consumers can extend this with their own. */
391
+ declare const BUILT_IN_TOOL_SETS: ToolSet[];
392
+ /**
393
+ * Apply tool set logic to a set of semantic match results.
394
+ *
395
+ * For each defined tool set, if any anchor tool appears in `matchedNames`,
396
+ * all set members present in `availableNames` are added and non-member
397
+ * tools are removed (unless they scored above `independentThreshold`).
398
+ *
399
+ * @param matchedNames - Names selected by semantic matching
400
+ * @param availableNames - All tool names available for selection
401
+ * @param scores - Map of tool name → similarity score (from semantic matching)
402
+ * @param toolSets - Tool sets to apply (defaults to BUILT_IN_TOOL_SETS)
403
+ * @param independentThreshold - Non-set tools scoring above this survive (default: 0.65)
404
+ */
405
+ declare function applyToolSets(matchedNames: Set<string>, availableNames: Set<string>, scores: Map<string, number>, toolSets?: ToolSet[], independentThreshold?: number): Set<string>;
406
+ /**
407
+ * Additively expand tool sets: when any anchor of a set scores at or above
408
+ * its `anchorMinSimilarity`, all set members are added to the result.
409
+ * Original matches are preserved; multiple sets can expand independently.
410
+ *
411
+ * Members of sets that *don't* activate are kept if they were individually
412
+ * matched. We deliberately don't strip orphans: the cost of a single
413
+ * borderline tool slipping into the request is cheap (a few extra bytes,
414
+ * no behavioral impact) but stripping legitimate matches like
415
+ * `create_file 0.55` on prompts where `patch_file` doesn't also clear the
416
+ * anchor threshold would silently break app-creation flows. Recall over
417
+ * precision.
418
+ *
419
+ * Use this for server-side toolkit suites where the LLM needs the full
420
+ * call chain (e.g. search_web → read_url / parallel_read_url, or
421
+ * geocoding before the OpenMeteo data tools). Differs from `applyToolSets`,
422
+ * which replaces non-set matches when a set activates.
423
+ *
424
+ * To express "any member triggers the set" (not specific anchors), pass
425
+ * `anchors: members` when defining the ToolSet.
426
+ *
427
+ * @param matchedNames - Names selected by semantic matching
428
+ * @param availableNames - All tool names available for selection
429
+ * @param scores - Map of tool name → similarity score
430
+ * @param toolSets - Tool sets to evaluate
431
+ * @param activeSetNames - Set names that should expand unconditionally,
432
+ * bypassing the anchor-similarity check. Use this when conversation state
433
+ * implies a set should be present regardless of how the current prompt is
434
+ * phrased (e.g., a slide deck artifact already exists in the conversation).
435
+ * @returns Set including original matches plus members of any activated set
436
+ */
437
+ declare function expandToolSetsAdditive(matchedNames: Set<string>, availableNames: Set<string>, scores: Map<string, number>, toolSets: ToolSet[], activeSetNames?: ReadonlySet<string>): Set<string>;
438
+ /**
439
+ * Names of the tool sets that *activated* for a request — the exact gate
440
+ * {@link expandToolSetsAdditive} uses to pull in members: an anchor whose
441
+ * similarity cleared `anchorMinSimilarity`, or a set the caller forced active
442
+ * via `activeSetNames`. Drives {@link toolSetSystemPrompts} so a set's persona
443
+ * rides in only on genuine activation, not on a borderline anchor that was kept
444
+ * by recall-over-precision (below the activation floor) without the set
445
+ * actually activating.
446
+ *
447
+ * @param scores - Tool name → similarity score (from semantic matching).
448
+ * @param toolSets - Tool sets to evaluate (defaults to {@link BUILT_IN_TOOL_SETS}).
449
+ * @param activeSetNames - Set names forced active regardless of score.
450
+ */
451
+ declare function activatedToolSetNames(scores: ReadonlyMap<string, number>, toolSets?: ToolSet[], activeSetNames?: ReadonlySet<string>): Set<string>;
452
+ /**
453
+ * Collect the `systemPrompt` of every tool set that activated for a request,
454
+ * for the caller to APPEND to its base system prompt.
455
+ *
456
+ * Pass `activatedSetNames` (from {@link activatedToolSetNames}) to gate on
457
+ * genuine activation — an anchor that cleared `anchorMinSimilarity` or a forced
458
+ * set. This is the correct gate: `expandToolSetsAdditive` keeps borderline
459
+ * anchor matches in the selection even when the set did NOT activate (recall
460
+ * over precision), so gating on mere anchor *presence* would inject a set's
461
+ * persona on prompts it has nothing to do with (e.g. the App Builder prompt on
462
+ * "write a story"). When `activatedSetNames` is omitted, falls back to anchor
463
+ * presence for legacy callers that don't compute scores.
464
+ *
465
+ * Additive by design: append the returned fragments, never replace the base
466
+ * prompt, so persona / memory survive. De-duplicated, order preserved.
467
+ *
468
+ * @param selectedToolNames - Final selected tool names (client + server tools).
469
+ * @param toolSets - Tool sets to consult (defaults to {@link BUILT_IN_TOOL_SETS}).
470
+ * @param activatedSetNames - Set names that genuinely activated (see above).
471
+ * @returns Mode prompts for active sets, in `toolSets` order, deduplicated.
472
+ */
473
+ declare function toolSetSystemPrompts(selectedToolNames: Iterable<string>, toolSets?: ToolSet[], activatedSetNames?: ReadonlySet<string>): string[];
474
+ /**
475
+ * Options for createServerToolsFilter.
476
+ */
477
+ interface CreateServerToolsFilterOptions {
478
+ /**
479
+ * Tool sets to expand additively. When any anchor scores at or above the
480
+ * set's `anchorMinSimilarity`, all members are included alongside the
481
+ * original semantic matches.
482
+ */
483
+ toolSets?: ToolSet[];
484
+ /** Tool names to always drop from results, even when they match. */
485
+ excludeTools?: Iterable<string>;
486
+ /** Options forwarded to `findMatchingTools`. */
487
+ matchOptions?: ToolMatchOptions;
488
+ }
489
+ /**
490
+ * Build a server-tools filter function for use with `useChatStorage`'s
491
+ * `serverTools` option. Composes `findMatchingTools`, `expandToolSetsAdditive`,
492
+ * and an exclude-list into a single (embeddings, tools) → string[] callback.
493
+ *
494
+ * @example
495
+ * ```ts
496
+ * import { createServerToolsFilter } from "@anuma/sdk/tools";
497
+ *
498
+ * const serverTools = createServerToolsFilter({
499
+ * toolSets: [
500
+ * {
501
+ * name: "research",
502
+ * members: ["AnumaJinaMCP-search_web", "AnumaJinaMCP-read_url", ...],
503
+ * anchors: ["AnumaJinaMCP-search_web"],
504
+ * anchorMinSimilarity: 0.7,
505
+ * },
506
+ * ],
507
+ * excludeTools: ["OpenMeteoMCP-weather_forecast"],
508
+ * matchOptions: { limit: 5, minSimilarity: 0.5 },
509
+ * });
510
+ * ```
511
+ */
512
+ declare function createServerToolsFilter(options?: CreateServerToolsFilterOptions): (embeddings: number[] | number[][], tools: ServerTool[]) => string[];
513
+ /**
514
+ * Default exclusions baked into `defaultServerToolsFilter`.
515
+ *
516
+ * - `AnumaVisionMCP-anuma_analyze_image`: modern frontier models have native
517
+ * vision via image content blocks; routing through a server-side vision
518
+ * tool just adds a hop.
519
+ * - `OpenMeteoMCP-weather_forecast`: redundant when the consumer registers
520
+ * `createWeatherTool` (the client-side display tool handles geocoding
521
+ * internally and renders a card inline). Including the server-side
522
+ * equivalent causes the model to prefer raw data over the card. Consumers
523
+ * who don't register `createWeatherTool` should instead build their own
524
+ * filter via `createServerToolsFilter`. NOTE: `OpenMeteoMCP-geocoding` is
525
+ * deliberately NOT excluded — the non-weather OpenMeteo data tools
526
+ * (air_quality, marine_weather, …) require lat/lon and depend on it via the
527
+ * openmeteo-geocode set; excluding it stranded them. Bare geocoding doesn't
528
+ * compete with the weather card (it returns coordinates, not weather).
529
+ */
530
+ declare const DEFAULT_EXCLUDED_SERVER_TOOLS: readonly string[];
531
+ /** Default match options for the server-tools filter (limit 5, minSim 0.5). */
532
+ declare const DEFAULT_SERVER_TOOLS_MATCH_OPTIONS: ToolMatchOptions;
533
+ /**
534
+ * Dependency edges between server tools: when an entry tool (anchor) matches
535
+ * a prompt, its continuation tools ride in even though they can never match
536
+ * the prompt themselves.
537
+ *
538
+ * These exist because semantic selection structurally cannot reach a tool
539
+ * whose job is step 2 of a call-chain. Measured against the live catalog
540
+ * (June 2026): on "research the latest news on X", `search_web` scores 0.64
541
+ * but `parallel_read_url` scores 0.33 and `parallel_search_web` 0.47 — below
542
+ * the 0.5 floor, unreachable at ANY match limit. No threshold or limit tuning
543
+ * fixes this; an explicit edge is the only mechanism that does.
544
+ *
545
+ * Deliberately NOT grouped: same-vendor siblings (`extract_pdf`,
546
+ * `search_images`, weather/finance variants…). Those
547
+ * embed near the prompts that need them and survive plain top-5 selection on
548
+ * their own — vendor-wide expansion just dilutes the toolset. Keep this list
549
+ * to genuine call-chains.
550
+ *
551
+ * Tool names are EXACT `/api/v1/tools` catalog matches — all filtering in
552
+ * this module is exact-string, so a stale name silently selects nothing (the
553
+ * May 2026 `Anuma` prefix rename broke every consumer keeping copies of
554
+ * these lists). The toolSelection e2e suite asserts every name below exists
555
+ * in the live catalog.
556
+ */
557
+ declare const SERVER_TOOL_DEPENDENCY_SETS: ToolSet[];
558
+ /**
559
+ * Pre-configured server-tools filter ready to drop into `useChatStorage`'s
560
+ * `serverTools` option. Semantic matching against the user prompt with the
561
+ * default exclusion list applied, plus call-chain expansion via
562
+ * {@link SERVER_TOOL_DEPENDENCY_SETS} so continuation tools (read-after-search,
563
+ * geocode-before-weather) ride in with their entry tool.
564
+ *
565
+ * @example
566
+ * ```ts
567
+ * import { defaultServerToolsFilter, useChatStorage } from "@anuma/sdk/react";
568
+ *
569
+ * useChatStorage({
570
+ * ...,
571
+ * serverTools: defaultServerToolsFilter,
572
+ * });
573
+ * ```
574
+ *
575
+ * If you need to customize (extra excludes, different limits, opt into
576
+ * tool-set expansion), call `createServerToolsFilter` directly.
577
+ */
578
+ declare const defaultServerToolsFilter: (embeddings: number[] | number[][], tools: ServerTool[]) => string[];
579
+ /**
580
+ * Type for a server-tools filter — a function that takes prompt embeddings
581
+ * and the full server tool catalog and returns the names of tools to keep.
582
+ * Matches `useChatStorage`'s `serverTools` callback signature.
583
+ */
584
+ type ServerToolsFilterFunction = (embeddings: number[] | number[][], tools: ServerTool[]) => string[];
585
+ /**
586
+ * Options for `selectServerToolsForPrompt`.
587
+ */
588
+ interface SelectServerToolsForPromptOptions {
589
+ /** User prompt to match tools against. */
590
+ prompt: string;
591
+ /**
592
+ * Filter to apply: either a function (called with the prompt embedding +
593
+ * full catalog) or a static list of tool names. Same shape `useChatStorage`
594
+ * accepts on its `serverTools` option. Pass `defaultServerToolsFilter` to
595
+ * mirror the default chat-flow selection.
596
+ */
597
+ serverToolsFilter?: string[] | ServerToolsFilterFunction;
598
+ /** Function that resolves an auth token (Bearer). */
599
+ getToken: () => Promise<string | null>;
600
+ /** Base URL for the API. */
601
+ baseUrl?: string;
602
+ /** Embedding model override. Falls back to the SDK default. */
603
+ embeddingModel?: string;
604
+ /** Cache expiration in ms for the server-tools catalog fetch. */
605
+ cacheExpirationMs?: number;
606
+ /**
607
+ * Where to read/write the cached catalog. Defaults to browser `localStorage`
608
+ * (a no-op on Node/RN); pass a backend to persist on those platforms.
609
+ */
610
+ cache?: ToolsCacheBackend;
611
+ /**
612
+ * Phase 3 defer-loading. When `enabled`, this helper returns the FULL catalog (skipping semantic/
613
+ * static filtering) to mirror useChatStorage's responses send path, which swaps in the full catalog
614
+ * for mergeTools + tool-search. Omit/disabled → today's filtered selection.
615
+ */
616
+ deferLoading?: DeferLoadingConfig;
617
+ }
618
+ /**
619
+ * Select server-side tools for a prompt using the same path
620
+ * `useChatStorage` runs internally. Use this anywhere outside the chat
621
+ * hook — background-task workers, server scripts, debug tools — that needs
622
+ * the same selection the chat flow would produce.
623
+ *
624
+ * Mirrors the responses-API branch of `sendMessage`: fetch catalog with
625
+ * caching, optionally embed the prompt (only when the filter is a function),
626
+ * apply the filter, return matching `ServerTool[]` (with embeddings and
627
+ * descriptions intact for downstream serialization).
628
+ *
629
+ * Returns `[]` on any of: undefined/empty filter, empty prompt for a
630
+ * function filter, failed catalog fetch, or failed embedding.
631
+ *
632
+ * @example
633
+ * ```ts
634
+ * import { defaultServerToolsFilter, selectServerToolsForPrompt } from "@anuma/sdk/server";
635
+ *
636
+ * const tools = await selectServerToolsForPrompt({
637
+ * prompt: "Generate a slide deck about AI",
638
+ * serverToolsFilter: defaultServerToolsFilter,
639
+ * getToken: async () => identityToken,
640
+ * baseUrl: process.env.API_URL,
641
+ * });
642
+ * ```
643
+ */
644
+ declare function selectServerToolsForPrompt(options: SelectServerToolsForPromptOptions): Promise<ServerTool[]>;
645
+ /**
646
+ * Options for selectServerSideTools
647
+ */
648
+ interface SelectServerSideToolsOptions {
649
+ /** The user prompt to match tools against */
650
+ prompt: string;
651
+ /** Function to get auth token (uses Authorization: Bearer header) */
652
+ getToken?: () => Promise<string | null>;
653
+ /** Direct API key for server-side usage (uses X-API-Key header) */
654
+ apiKey?: string;
655
+ /** Base URL for the API */
656
+ baseUrl?: string;
657
+ /** Cache expiration in ms (default: 24h) */
658
+ cacheExpirationMs?: number;
659
+ /** Force refresh tools cache */
660
+ forceRefresh?: boolean;
661
+ /** Embedding model to use */
662
+ embeddingModel?: string;
663
+ /** Max tools to return (default: 10) */
664
+ limit?: number;
665
+ /** Minimum cosine similarity 0-1 (default: 0.3) */
666
+ minSimilarity?: number;
667
+ /** API format for returned tools (default: "responses") */
668
+ apiType?: "responses" | "completions";
669
+ }
670
+ /**
671
+ * Select server tools that are semantically relevant to a prompt.
672
+ *
673
+ * Fetches available tools (with caching), generates embeddings for the prompt,
674
+ * runs cosine-similarity matching, and returns tool schemas in the requested
675
+ * API format (Responses or Completions).
676
+ *
677
+ * @example
678
+ * ```ts
679
+ * import { selectServerSideTools } from "@anuma/sdk/tools";
680
+ *
681
+ * const tools = await selectServerSideTools({
682
+ * prompt: "Draw me a cat",
683
+ * getToken: async () => identityToken,
684
+ * });
685
+ *
686
+ * const response = await postApiV1Responses({
687
+ * body: {
688
+ * messages: [{ role: "user", content: [{ type: "text", text: "Draw me a cat" }] }],
689
+ * model: "fireworks/accounts/fireworks/models/kimi-k2p5",
690
+ * tools,
691
+ * },
692
+ * headers: { Authorization: `Bearer ${identityToken}` },
693
+ * });
694
+ * ```
695
+ */
696
+ declare function selectServerSideTools(options: SelectServerSideToolsOptions): Promise<Array<Record<string, unknown>>>;
697
+
698
+ /**
699
+ * Client-tool selection — the per-turn semantic filter over a client-tool
700
+ * catalog.
701
+ *
702
+ * Extracted out of `../../react/useChatStorage` (a `"use client"` React +
703
+ * WatermelonDB file) so the identical selection can run anywhere the engine
704
+ * runs: the standalone council path that bypasses the hook, Node unit tests,
705
+ * and the node/RN-safe `@anuma/sdk/tools/selection` subpath. The hook re-imports
706
+ * these — behavior is unchanged from when they lived inline.
707
+ *
708
+ * Dependency-safe by construction: `generateEmbeddings` comes from the db-free
709
+ * `../memoryEngine/generate` core and `RECALL_TOOL_NAME` from the
710
+ * dependency-free `../memory/recallConstants`, so nothing here drags in the
711
+ * WatermelonDB data layer.
712
+ */
713
+
714
+ /** Typed accessor for client tool name (handles function-call style and flat). */
715
+ declare function getToolName(t: LlmapiChatCompletionTool): string;
716
+ /** Typed accessor for client tool description. */
717
+ declare function getToolDescription(t: LlmapiChatCompletionTool): string;
718
+ /**
719
+ * Build the tool-set guidance to inject for a request: the `systemPrompt` of
720
+ * every tool set whose tools ended up selected (e.g. the App Builder prompt
721
+ * when app-gen tools are pulled in — by an explicit force-include OR an
722
+ * implicit semantic match). Returned as one string for useChat's `toolGuidance`
723
+ * channel, which adds it as a separate system message (additive — composes with
724
+ * the persona, doesn't replace it). `undefined` when no selected set carries a
725
+ * prompt, so non-app turns are unaffected.
726
+ */
727
+ declare function computeToolGuidance(selectedServerTools: ServerTool[], selectedClientTools: LlmapiChatCompletionTool[] | undefined, extraToolSets: ToolSet[], activatedSetNames?: ReadonlySet<string>): string | undefined;
728
+ /**
729
+ * Automatically filter client tools using embedding-based semantic matching.
730
+ * Generates embeddings for tool descriptions (cached), then selects the most
731
+ * relevant tools for the user's prompt. This prevents sending 20+ tool
732
+ * definitions that eat up the context window.
733
+ *
734
+ * @returns Filtered client tools, or the original array if filtering fails/skips.
735
+ */
736
+ declare function autoFilterClientTools(clientTools: LlmapiChatCompletionTool[], promptEmbeddings: number[] | number[][] | null, cache: Map<string, number[]>, embeddingOptions: {
737
+ getToken?: () => Promise<string | null>;
738
+ apiKey?: string;
739
+ baseUrl?: string;
740
+ model?: string;
741
+ }, extraToolSets?: ToolSet[], activeToolSets?: string[],
742
+ /**
743
+ * Why `promptEmbeddings` is null. "short-prompt" (the length gate —
744
+ * deliberate) sends NO tools; "error" (embedding generation failed —
745
+ * transient) degrades to the FULL catalog so an embeddings outage never
746
+ * strips every tool from every request.
747
+ */
748
+ noEmbeddingsReason?: "short-prompt" | "error"): Promise<{
749
+ tools: LlmapiChatCompletionTool[];
750
+ activatedSetNames?: ReadonlySet<string>;
751
+ }>;
752
+
753
+ /**
754
+ * Connector tool catalog + denied-tools system-prompt rider.
755
+ *
756
+ * Granular connector access works by ALLOW/DENY-ing individual SDK tools.
757
+ * Denying a tool means it's never handed to the model that turn, so it
758
+ * physically can't be called — bypass-proof at the model layer.
759
+ *
760
+ * Consumer contract (this PR ships the foundation only — it does NOT wire
761
+ * anything into runtime filtering or the client; those are later phases):
762
+ *
763
+ * 1. Hide the denied tools from the model — pass the denied tool names as
764
+ * `createServerToolsFilter({ excludeTools })` so they're dropped from the
765
+ * toolset before it reaches the LLM.
766
+ * 2. Tell the user how to re-enable — append `buildDeniedToolsRider(denied)`
767
+ * to the system prompt. Because the tool is absent, the model can't name
768
+ * it on its own and would give a generic "I don't have access". The rider
769
+ * gives it the specific capability names (grouped by connector) so it can
770
+ * tell the user to re-enable that exact tool in Connected Apps settings.
771
+ *
772
+ * `TOOL_CATALOG` is the single source of truth for connector tool → friendly
773
+ * label + provider. `provider` is the canonical logical-provider identifier the
774
+ * portal and SDK already key on (matches `internal/oauth/providers.go` and the
775
+ * `createConnectorTokenGetter` call sites) — Phase 2/3 use it to group and
776
+ * persist per-tool denial. `connector` is the human-facing UI display string.
777
+ * Consumers (portal, client) read this on a version bump rather than re-encoding
778
+ * tool names. Labels are placeholders that will be refined later — keep them
779
+ * sensible.
780
+ */
781
+
782
+ interface ToolCatalogEntry {
783
+ label: string;
784
+ /** Canonical logical-provider id (e.g. "gmail", "gcalendar", "gdrive"). */
785
+ provider: string;
786
+ /** Human-facing connector display name (UI label). */
787
+ connector: string;
788
+ }
789
+ declare const TOOL_CATALOG: Record<string, ToolCatalogEntry>;
790
+ /**
791
+ * Build a system-prompt fragment telling the model which connector capabilities
792
+ * the user has turned off, so it can give the specific "re-enable this tool"
793
+ * message instead of a generic refusal.
794
+ *
795
+ * Unknown names (not in {@link TOOL_CATALOG}) are skipped. Returns `""` when the
796
+ * input is empty or every name is unknown — callers append the result
797
+ * conditionally, so an empty string is a no-op.
798
+ */
799
+ declare function buildDeniedToolsRider(deniedToolNames: Iterable<string>): string;
800
+ interface ConnectorGuidanceInput {
801
+ /** The candidate tools for this turn (the final assembled set). */
802
+ tools: ToolConfig[];
803
+ /**
804
+ * Logical provider codes connected for the user — the same codes used as
805
+ * {@link TOOL_CATALOG} `provider` values (e.g. "gmail", "gcalendar",
806
+ * "gdrive", "notion", "github", "dropbox").
807
+ */
808
+ connectedProviders: string[];
809
+ /** Exact SDK tool-name strings the user turned off ({@link TOOL_CATALOG} keys). */
810
+ deniedToolNames: string[];
811
+ }
812
+ interface ConnectorGuidance {
813
+ /** `input.tools` with any denied tool removed (the helper owns filtering). */
814
+ tools: ToolConfig[];
815
+ /** Compact system-prompt block, or "" when there's nothing actionable. */
816
+ rider: string;
817
+ }
818
+ /**
819
+ * Single helper both web and mobile use so neither re-implements connector
820
+ * tool filtering or the accuracy messaging. It enforces denial (drops denied
821
+ * tools from the turn's toolset) AND builds a compact rider letting the model
822
+ * give an accurate message for each connector state instead of a generic
823
+ * "I don't have access":
824
+ *
825
+ * 1. Toggled off — connected provider whose tool is denied → "turned off,
826
+ * re-enable in Connected Apps".
827
+ * 2a. Pruned / 2b. no tool — covered by a general line telling the model not to
828
+ * claim no-access for a connected app. It rides along only when another
829
+ * section is present (on its own it isn't actionable).
830
+ * 3. Not connected — catalog provider absent from `connectedProviders` →
831
+ * "connect it in Connected Apps".
832
+ *
833
+ * State 3 is derived from {@link TOOL_CATALOG}'s provider set — providers with
834
+ * no tools (e.g. Disconnect-only Dropbox) aren't actionable via tools, so they
835
+ * aren't surfaced here. Everything is sorted alphabetically for deterministic
836
+ * output (no cache / snapshot churn). `rider` is "" when nothing is actionable
837
+ * (every catalog provider connected and nothing denied).
838
+ */
839
+ declare function buildConnectorGuidance(input: ConnectorGuidanceInput): ConnectorGuidance;
840
+
841
+ /**
842
+ * `deriveActiveToolSets` — event-shape-agnostic sticky tool-set derivation
843
+ * (issue #702, Phase 4).
844
+ *
845
+ * Web derived sticky sets by scanning `ChatMessage[]` for two web-specific
846
+ * signals: synthetic tool-result user messages (`Tool "<name>" returned: …`)
847
+ * and `ActivityPhase.id`s shaped `server-tool-<name>-<n>`. This module keeps the
848
+ * exact matching logic but keys on a neutral {@link ToolActivationEvent[]}, so
849
+ * both apps feed it through a tiny adapter that maps their own message/activity
850
+ * store to events. That closes the terse-follow-up gap on mobile: a 3-char
851
+ * "yes" inside a slide conversation keeps the slide toolkit because the set
852
+ * stays sticky.
853
+ *
854
+ * Pure and node/RN-safe.
855
+ */
856
+
857
+ /**
858
+ * A neutral activation signal derived from conversation history.
859
+ *
860
+ * - `tool-result` — a tool ran and returned; `toolName` is the tool's name.
861
+ * - `server-tool-phase` — a server-tool activity phase occurred; `phaseId` is
862
+ * the phase id (shaped like `server-tool-<name>-<n>` on web).
863
+ */
864
+ interface ToolActivationEvent {
865
+ kind: "tool-result" | "server-tool-phase";
866
+ /** The tool name, for `tool-result` events. */
867
+ toolName?: string;
868
+ /** The phase id, for `server-tool-phase` events. */
869
+ phaseId?: string;
870
+ }
871
+ /**
872
+ * Derive the set of tool-set names that have "genuinely activated" across a
873
+ * conversation's activation events. Accumulation is monotonic: a set, once
874
+ * detected, stays detected; the scan early-exits once every set is active.
875
+ *
876
+ * @param events - Neutral activation signals, oldest-to-newest.
877
+ * @param sets - Tool sets to test against (defaults to `BUILT_IN_TOOL_SETS`).
878
+ * @returns The active tool-set names, to pass as `activeToolSets`.
879
+ */
880
+ declare function deriveActiveToolSets(events: ToolActivationEvent[], sets?: readonly ToolSet[]): string[];
881
+ /**
882
+ * Merge freshly-derived sticky sets into an existing sticky list without ever
883
+ * removing (append-only union). Mirrors web's Zustand `setFor`: an empty
884
+ * detection means a truncated/paginated history window, not "drop stickiness".
885
+ * Returns the same array reference when nothing changed.
886
+ */
887
+ declare function mergeActiveToolSets(current: string[], derived: string[]): string[];
888
+
889
+ /**
890
+ * Tool-selection vocabulary — the neutral, product-agnostic types that let the
891
+ * SDK own the "which tools this turn" orchestration both `apps/web` and
892
+ * `apps/mobile` previously hand-duplicated (see issue #702).
893
+ *
894
+ * The split of ownership is deliberate:
895
+ *
896
+ * - The SDK owns the neutral {@link CreationIntent}→client-factory mapping
897
+ * ({@link CREATION_INTENT_CLIENT_FACTORIES}) and the send-policy rules.
898
+ * - Each app owns its UI→{@link ToolIntentDescriptor} mapper and injects a
899
+ * {@link ServerToolCatalog} (built from its own static server-tool lists) and
900
+ * {@link ../assembleClientTools.ToolSelectionAdapters | adapters}. The SDK
901
+ * never imports the app's tool lists — the dependency direction stays
902
+ * app→SDK.
903
+ *
904
+ * This module has no runtime dependency on React, the DOM, WatermelonDB, or the
905
+ * generated HTTP client, so it is safe to import from the node/RN-safe
906
+ * `@anuma/sdk/tools/selection` subpath.
907
+ */
908
+
909
+ /**
910
+ * Which orchestration path a turn runs through.
911
+ *
912
+ * - `chat` — the ordinary single-model chat turn (per-mode client + server
913
+ * tools, send-policy overrides).
914
+ * - `council` — the multi-model comparison path; each worker sees the full
915
+ * semantic server-tool filter and (optionally) its own per-worker memory
916
+ * tools, and no per-mode client toolkit.
917
+ * - `aggregation` — the council "unify" worker; like `council` but must never
918
+ * persist memories (no `memory_vault_save`).
919
+ */
920
+ type ToolLane = "chat" | "council" | "aggregation";
921
+ /**
922
+ * The neutral creation intent for a chat turn. This is the union of web's
923
+ * `(chatMode, activeTool)` triple and mobile's `ChatMode`, normalized so a
924
+ * single resolver reproduces both.
925
+ *
926
+ * `music` / `sfx` scope a coerced turn to a single audio generator; `audio` is
927
+ * the free-choice bundle (music + sfx). Apps that expose only a combined audio
928
+ * mode use `audio`; the scoped keys exist so a `tool_choice: "required"` turn
929
+ * cannot call the wrong generator.
930
+ */
931
+ type CreationIntent = "plain" | "image" | "audio" | "music" | "sfx" | "video" | "remove-image-bg" | "app" | "slides" | "document" | "web-search" | "deep-research";
932
+ /**
933
+ * A client-tool factory the SDK (or the host, for `saved`/`background`/
934
+ * `schedule`) can instantiate. Presence of the matching adapter in
935
+ * {@link ../assembleClientTools.ToolSelectionAdapters} GATES the factory — an
936
+ * absent adapter yields zero tools, which is what lets one unified plan produce
937
+ * web's full toolkit and mobile's subset automatically.
938
+ */
939
+ type ClientFactoryKey = "memory" | "connectors" | "slides" | "app" | "document" | "ui" | "saved" | "background" | "schedule";
940
+ /**
941
+ * How the assembled client tools are trimmed for the turn.
942
+ *
943
+ * - `auto` — the SDK semantic filter (`autoFilterClientTools`): send only the
944
+ * tools relevant to the prompt (plus always-on memory + sticky sets).
945
+ * - `include-all` — send every assembled tool (builder modes: slides/app).
946
+ * - `slide-editor` — keep only the slide-editing tools (the fullscreen-editor
947
+ * overlay); everything else is dropped even off-topic.
948
+ */
949
+ type ClientToolsFilterMode = "auto" | "include-all" | "slide-editor";
950
+ /** A custom client-tools filter: given the assembled tools, return the subset to send. */
951
+ type AssembledToolsFilterFn<TTool = unknown> = (tools: TTool[]) => TTool[] | Promise<TTool[]>;
952
+ /**
953
+ * App-facing thinking hint. There is intentionally no `ThinkingMode` type in
954
+ * the SDK core — each app translates this hint into its provider reasoning
955
+ * config (e.g. web's `getReasoningConfigForModel`). The SDK only carries the
956
+ * neutral hint so both apps agree on when a mode is "fast" vs "extended".
957
+ */
958
+ type ThinkingModeHint = "fast" | "thinking" | "extended";
959
+ /** Resolved tool-choice coercion for the turn. */
960
+ type ToolChoice = "auto" | "required";
961
+ /** A server-tools filter: a static allow-list of names, or a semantic filter fn. */
962
+ type ServerToolsFilter = string[] | ServerToolsFilterFunction;
963
+ /** Post-resolution client-tool mutations, applied by the host at send time. */
964
+ type PostFilterKey =
965
+ /** Strip `memory_vault_save` because the turn coerces a single tool (`tool_choice: "required"`). */
966
+ "strip-memory-save-when-coerced"
967
+ /** Web: strip `memory_vault_save` on a pure retrieval-intent prompt. */
968
+ | "strip-memory-save-on-retrieval-intent"
969
+ /** Web: strip ALL server tools on a save-intent prompt (avoid a search loop before saving). */
970
+ | "strip-server-tools-on-save-intent";
971
+ /**
972
+ * The neutral description of a turn a host hands to {@link ../plan.resolvePlan}.
973
+ * Each app writes a small UI→descriptor mapper; the resolver is otherwise
974
+ * identical across apps.
975
+ */
976
+ interface ToolIntentDescriptor {
977
+ /** Which orchestration path (chat / council / aggregation). */
978
+ lane: ToolLane;
979
+ /** The creation intent for the turn. Ignored for council/aggregation lanes. */
980
+ creation: CreationIntent;
981
+ /** Sticky tool-set names carried from conversation history (see `deriveActiveToolSets`). */
982
+ activeToolSets?: string[];
983
+ /** Attachments present on this turn — drives attachment-aware server-tool filters. */
984
+ attachments?: {
985
+ hasImages: boolean;
986
+ hasVideos: boolean;
987
+ };
988
+ /** The fullscreen editor open behind an ordinary chat turn, if any. */
989
+ editorPinned?: "slides" | null;
990
+ /** Message-aware escalation: the prompt reads as "make me a deck". */
991
+ slideDeckIntent?: boolean;
992
+ /**
993
+ * Message-aware signal that the prompt reads as an image edit. When true it
994
+ * SUPPRESSES slide-deck escalation (`slideDeckIntent`) in `resolvePlan` — an
995
+ * image-edit turn must not be re-routed into the slide builder. Mirrors web's
996
+ * `!imageEditActive` guard on slide-deck intent.
997
+ */
998
+ imageEditIntent?: boolean;
999
+ }
1000
+ /**
1001
+ * Context passed to a catalog entry's server-tools factory form so it can vary
1002
+ * by attachments (e.g. drop background-removal when only a video is attached).
1003
+ */
1004
+ interface ServerToolsFilterContext {
1005
+ attachments?: {
1006
+ hasImages: boolean;
1007
+ hasVideos: boolean;
1008
+ };
1009
+ }
1010
+ /**
1011
+ * One creation intent's server-tool policy plus its send-policy defaults,
1012
+ * supplied by the app.
1013
+ *
1014
+ * Provide EITHER a static `serverTools` value (an allow-list or a semantic
1015
+ * filter function) OR the attachment-aware `resolveServerTools` factory — the
1016
+ * latter takes precedence and is what the plain-chat entry uses (it binds a
1017
+ * logger and drops background-removal on a video-only attachment, which a
1018
+ * static value cannot express). The two are separate fields, not a union,
1019
+ * because a semantic filter is itself a function and would be indistinguishable
1020
+ * from a `(ctx) => filter` factory by shape alone.
1021
+ */
1022
+ interface ServerToolCatalogEntry {
1023
+ /** The server tools for this intent — a static allow-list or a semantic filter function. */
1024
+ serverTools?: ServerToolsFilter;
1025
+ /**
1026
+ * Attachment-aware form: produces the server tools for the turn from its
1027
+ * context. Takes precedence over `serverTools` when present.
1028
+ */
1029
+ resolveServerTools?: (ctx: ServerToolsFilterContext) => ServerToolsFilter;
1030
+ /** Override the default client-tools filter for this intent. */
1031
+ clientToolsFilter?: ClientToolsFilterMode | AssembledToolsFilterFn;
1032
+ /** Explicit tool-choice; omit to let the shape of `serverTools` decide (see `resolveToolChoice`). */
1033
+ toolChoice?: ToolChoice;
1034
+ /** Per-intent max tool rounds (web uses a flat 35; mobile varies by mode). */
1035
+ maxToolRounds?: number;
1036
+ /** Per-intent thinking hint (e.g. slides→fast, deep-research→extended). */
1037
+ thinkingMode?: ThinkingModeHint;
1038
+ /** An authoritative system prompt for this intent (e.g. the slide/deep-research prompt). */
1039
+ systemPrompt?: string;
1040
+ /** Server tools that must always be present regardless of filtering. */
1041
+ forcedServerTools?: string[];
1042
+ }
1043
+ /**
1044
+ * The app-supplied catalog: a per-intent (and per-lane, for council) map of
1045
+ * {@link ServerToolCatalogEntry}. Built by each app from its own static
1046
+ * server-tool lists via a `buildServerToolCatalog()` helper and injected into
1047
+ * `resolvePlan(descriptor, { catalog })`. The SDK stays catalog-agnostic — this
1048
+ * is the seam that keeps the SDK from ever importing the app's tool lists.
1049
+ *
1050
+ * Named `ServerToolCatalog` (not `ToolCatalog`) to stay distinct from the SDK's
1051
+ * existing `TOOL_CATALOG` (a connector→label map for the denied-tools rider).
1052
+ */
1053
+ type ServerToolCatalog = Partial<Record<CreationIntent | ToolLane, ServerToolCatalogEntry>>;
1054
+ /**
1055
+ * The fully-resolved plan for a turn: what `resolvePlan` produces and
1056
+ * `assembleClientTools` + the host's send layer consume.
1057
+ */
1058
+ interface ToolPlanSpec {
1059
+ /** Which client-tool factories to instantiate (capability-gated at assembly). */
1060
+ clientFactories: ClientFactoryKey[];
1061
+ /** How to trim the assembled client tools. */
1062
+ clientToolsFilter: ClientToolsFilterMode | AssembledToolsFilterFn;
1063
+ /** The server-tools filter for the turn (resolved value, factory already applied). */
1064
+ serverTools: ServerToolsFilter;
1065
+ /** Server tools that must always be present. */
1066
+ forcedServerTools?: string[];
1067
+ /** Sticky tool-set names to force-activate in the semantic client filter. */
1068
+ activeToolSets: string[];
1069
+ /** The resolved tool-choice coercion. */
1070
+ toolChoice: ToolChoice;
1071
+ /** Max tool rounds (undefined → the host/SDK default). */
1072
+ maxToolRounds?: number;
1073
+ /** Thinking hint (undefined → the host default). */
1074
+ thinkingMode?: ThinkingModeHint;
1075
+ /** Authoritative system-prompt riders for the turn (tool-set personas ride in separately). */
1076
+ systemPromptRiders: string[];
1077
+ /** Client-tool mutations the host applies at send time. */
1078
+ postFilters: PostFilterKey[];
1079
+ }
1080
+ /**
1081
+ * Full generative client toolkit — the unified plain-chat / creation-mode
1082
+ * factory set. Web registers all of these unconditionally today; mobile
1083
+ * registers only the subset whose adapters it wires. Under capability-gated
1084
+ * assembly the SAME list yields web's superset and mobile's subset, so "make me
1085
+ * a deck" works from plain chat on whichever platform wires the slides adapter.
1086
+ */
1087
+ declare const FULL_GENERATIVE_CLIENT_FACTORIES: readonly ClientFactoryKey[];
1088
+ /**
1089
+ * The neutral {@link CreationIntent}→{@link ClientFactoryKey}[] mapping the SDK
1090
+ * owns. Creation modes (image/audio/video/…) share the full generative set —
1091
+ * the server-tool coercion + semantic filter do the narrowing, exactly as web's
1092
+ * fall-through does today. Builder modes (`app`, `slides`) are deliberately
1093
+ * restrictive.
1094
+ */
1095
+ declare const CREATION_INTENT_CLIENT_FACTORIES: Record<CreationIntent, readonly ClientFactoryKey[]>;
1096
+ /**
1097
+ * Default client-tools filter per intent. Generative modes use the semantic
1098
+ * filter; builder modes send their full toolkit (`include-all`).
1099
+ */
1100
+ declare const CREATION_INTENT_CLIENT_FILTER: Record<CreationIntent, ClientToolsFilterMode>;
1101
+ /**
1102
+ * Built-in tool-set names (mirrors `BUILT_IN_TOOL_SETS[].name`). The generative
1103
+ * toolkits that a creation intent should force-activate as sticky sets — so a
1104
+ * builder mode's persona/toolkit rides in, and a follow-up stays in that lane.
1105
+ */
1106
+ declare const CREATION_INTENT_TOOL_SET: Partial<Record<CreationIntent, string>>;
1107
+
1108
+ /**
1109
+ * `assembleClientTools` — capability-gated client-tool assembly (issue #702,
1110
+ * Phase 3). Given a resolved plan's `clientFactories` and a set of adapters, it
1111
+ * instantiates only the factories whose adapter is present and concatenates
1112
+ * them in a canonical order.
1113
+ *
1114
+ * The presence of an adapter GATES its factory — the generalization of
1115
+ * `createDocumentTools` returning `[]` when `displayDocument` is absent
1116
+ * (src/tools/document/index.ts). This is what lets ONE unified plan produce
1117
+ * web's full toolkit and mobile's subset automatically: web wires every
1118
+ * builder, mobile wires only the ones its RN surface supports, and the absent
1119
+ * ones contribute nothing.
1120
+ *
1121
+ * The SDK deliberately owns the GATING, ORDER, and filter application — not the
1122
+ * per-factory wiring. Each app's factory instantiation (slide auto-display,
1123
+ * app-lineage tracking, RN-vs-web storage, logging instrumentation) is
1124
+ * genuinely app-specific and stays app-side, expressed as a builder here.
1125
+ *
1126
+ * Pure and node/RN-safe.
1127
+ */
1128
+
1129
+ /** Minimal logger the assembler uses when a builder throws. */
1130
+ interface SelectionLogger {
1131
+ warn(message: string, context?: unknown): void;
1132
+ error(message: string, context?: unknown): void;
1133
+ debug?(message: string, context?: unknown): void;
1134
+ }
1135
+ /**
1136
+ * A per-factory builder: returns the tools for one {@link ClientFactoryKey}.
1137
+ * Synchronous — factory instantiation is synchronous in both apps, and this
1138
+ * lets `assembleClientTools` run inside a synchronous React `useMemo`. Resolve
1139
+ * any async work (e.g. fetching saved tools) before calling.
1140
+ */
1141
+ type ClientFactoryBuilder<TTool = ToolConfig> = () => TTool[];
1142
+ /**
1143
+ * Adapters for {@link assembleClientTools}. The `builders` map is the gate: a
1144
+ * factory key with a builder produces its tools; a key with no builder produces
1145
+ * nothing. Each app supplies the builders for the capabilities its surface
1146
+ * supports (web: all; mobile: memory/connectors/document/slides today).
1147
+ */
1148
+ interface ToolSelectionAdapters<TTool = ToolConfig> {
1149
+ /** Logged to when a builder throws; assembly continues without that factory. */
1150
+ logger?: SelectionLogger;
1151
+ /** Per-factory builders. Presence gates the factory on. */
1152
+ builders: Partial<Record<ClientFactoryKey, ClientFactoryBuilder<TTool>>>;
1153
+ }
1154
+ /**
1155
+ * Instantiate the plan's client factories, gated by adapter presence, in the
1156
+ * canonical `clientFactories` order. A builder that throws is logged and
1157
+ * skipped so one failing capability never takes down the whole turn.
1158
+ *
1159
+ * The result is the CANDIDATE array. Apply {@link filterAssembledClientTools}
1160
+ * (or the semantic `autoFilterClientTools`) to trim it for the turn.
1161
+ *
1162
+ * Synchronous, so it can run directly inside a React `useMemo` (which is how
1163
+ * both apps build their per-turn client-tool list).
1164
+ */
1165
+ declare function assembleClientTools<TTool = ToolConfig>(spec: Pick<ToolPlanSpec, "clientFactories">, adapters: ToolSelectionAdapters<TTool>): TTool[];
1166
+ /**
1167
+ * Apply the plan's static client-tools filter to the assembled candidates.
1168
+ *
1169
+ * - `include-all` → every tool (builder modes).
1170
+ * - `slide-editor` → only tools whose name is in `slideEditorToolNames`; when
1171
+ * that set is absent it fails CLOSED (returns `[]`) so a missing name set can
1172
+ * never leave the overlay silently unrestricted. Callers that want the full
1173
+ * toolkit use `include-all`, not slide-editor-without-names.
1174
+ * - `auto` → returned unchanged; the caller runs the semantic
1175
+ * `autoFilterClientTools` (which needs prompt embeddings) instead.
1176
+ * - a function → applied directly.
1177
+ */
1178
+ declare function filterAssembledClientTools<TTool = ToolConfig>(tools: TTool[], mode: ClientToolsFilterMode | AssembledToolsFilterFn<TTool>, opts?: {
1179
+ /** Tool names the slide-editor overlay keeps (the slide tool set members). */
1180
+ slideEditorToolNames?: ReadonlySet<string>;
1181
+ /** Name accessor; defaults to the SDK's client-tool name reader. */
1182
+ getName?: (t: TTool) => string;
1183
+ }): TTool[] | Promise<TTool[]>;
1184
+
1185
+ /**
1186
+ * `resolvePlan` — the single source of truth for "which tools this turn"
1187
+ * (issue #702, Phase 2). Given a neutral {@link ToolIntentDescriptor} and an
1188
+ * app-injected {@link ServerToolCatalog}, it produces a fully-resolved
1189
+ * {@link ToolPlanSpec} that both web and mobile consume, replacing each app's
1190
+ * hand-written per-mode switch.
1191
+ *
1192
+ * Pure and node/RN-safe. The plan is data — the host feeds `clientFactories`
1193
+ * into `assembleClientTools`, and `serverTools`/`toolChoice`/`maxToolRounds`/
1194
+ * `thinkingMode` into its send layer.
1195
+ */
1196
+
1197
+ /** Context for {@link resolvePlan}: the injected catalog plus host defaults. */
1198
+ interface ResolvePlanContext {
1199
+ /** The app-built per-intent/-lane server-tool catalog. */
1200
+ catalog: ServerToolCatalog;
1201
+ /** Fallback max tool rounds when a catalog entry doesn't set one (web: 35). */
1202
+ defaultMaxToolRounds?: number;
1203
+ /** Fallback thinking hint when a catalog entry doesn't set one. */
1204
+ defaultThinkingMode?: ThinkingModeHint;
1205
+ /**
1206
+ * App-detected memory intents for the turn (web only today). When present,
1207
+ * they add the corresponding post-filters so the host strips the vault-save
1208
+ * tool on a retrieval-intent prompt and the server tools on a save-intent
1209
+ * prompt. Mobile omits this.
1210
+ */
1211
+ memoryIntent?: {
1212
+ retrieval?: boolean;
1213
+ save?: boolean;
1214
+ };
1215
+ }
1216
+ /**
1217
+ * Resolve the complete tool plan for a turn.
1218
+ *
1219
+ * Chat lane: keys on the creation intent — client factories from the neutral
1220
+ * SDK mapping, server tools + send-policy knobs from the catalog, tool-choice
1221
+ * shape-derived unless the intent is a builder mode or a slide-deck intent
1222
+ * (both forced `auto`). Council/aggregation lanes carry no per-mode client
1223
+ * toolkit here — `resolveCouncilPlan` (council.ts) adds per-worker memory tools
1224
+ * on top of this server-tool plan.
1225
+ */
1226
+ declare function resolvePlan(descriptor: ToolIntentDescriptor, ctx: ResolvePlanContext): ToolPlanSpec;
1227
+
1228
+ /**
1229
+ * Council tool resolution (issue #702, Phase 6).
1230
+ *
1231
+ * The council path bypasses the per-mode chat switch: each worker sees the full
1232
+ * semantic server-tool filter and its OWN per-worker memory tools (built from
1233
+ * that worker's model so a private-capable model sees `['private','shared']`
1234
+ * and a standard model sees `['shared']` only). The aggregation ("unify")
1235
+ * worker must never persist — its `memory_vault_save` is dropped.
1236
+ *
1237
+ * This module composes each worker's client-tool candidate array and runs it
1238
+ * through the SAME `autoFilterClientTools` the chat hook uses, so council and
1239
+ * chat share one selection. Building this on the exported selector is what lets
1240
+ * mobile council gain per-worker memory tools without re-implementing anything.
1241
+ *
1242
+ * Pure and node/RN-safe.
1243
+ */
1244
+
1245
+ /**
1246
+ * Resolve the council/aggregation server-tool plan. This is the chat resolver's
1247
+ * council-lane path: a semantic server-tool filter, no per-mode client toolkit,
1248
+ * and (for aggregation) a coerced-save strip. Per-worker client tools are added
1249
+ * separately via {@link selectCouncilClientTools}.
1250
+ */
1251
+ declare function resolveCouncilPlan(descriptor: ToolIntentDescriptor, ctx: ResolvePlanContext): ToolPlanSpec;
1252
+ /** The council/aggregation server-tools filter (a semantic filter, from the catalog). */
1253
+ declare function resolveCouncilServerTools(descriptor: ToolIntentDescriptor, ctx: ResolvePlanContext): ServerToolsFilter;
1254
+ /** Inputs to compose one council worker's client-tool candidate array. */
1255
+ interface CouncilClientToolsInput<TTool extends LlmapiChatCompletionTool = ToolConfig> {
1256
+ /**
1257
+ * Memory tools built from THIS worker's model (via the host's per-model
1258
+ * memory-tool factory). Empty for workers that carry no memory tools.
1259
+ */
1260
+ memoryTools: TTool[];
1261
+ /** Model-agnostic shared client tools for council (connectors, saved). */
1262
+ sharedTools?: TTool[];
1263
+ /**
1264
+ * Whether this worker may persist memories. `false` for the aggregation /
1265
+ * unify worker — its `memory_vault_save` is dropped.
1266
+ */
1267
+ canPersistMemory: boolean;
1268
+ }
1269
+ /**
1270
+ * Compose a council worker's client-tool candidate array: per-worker memory
1271
+ * tools first, then the shared tools, with `memory_vault_save` removed when the
1272
+ * worker may not persist (aggregation).
1273
+ */
1274
+ declare function composeCouncilClientTools<TTool extends LlmapiChatCompletionTool = ToolConfig>(input: CouncilClientToolsInput<TTool>): TTool[];
1275
+ /** Options forwarded to the shared `autoFilterClientTools` selection. */
1276
+ interface CouncilClientSelectionOptions {
1277
+ promptEmbeddings: number[] | number[][] | null;
1278
+ cache: Map<string, number[]>;
1279
+ embeddingOptions: {
1280
+ getToken?: () => Promise<string | null>;
1281
+ apiKey?: string;
1282
+ baseUrl?: string;
1283
+ model?: string;
1284
+ };
1285
+ extraToolSets?: ToolSet[];
1286
+ activeToolSets?: string[];
1287
+ noEmbeddingsReason?: "short-prompt" | "error";
1288
+ }
1289
+ /**
1290
+ * Select a council worker's client tools by composing its candidate array and
1291
+ * running the SAME semantic filter the chat hook runs. Returns the filtered
1292
+ * tools plus which tool sets genuinely activated (for persona injection).
1293
+ */
1294
+ declare function selectCouncilClientTools<TTool extends LlmapiChatCompletionTool = ToolConfig>(input: CouncilClientToolsInput<TTool>, options: CouncilClientSelectionOptions): Promise<{
1295
+ tools: LlmapiChatCompletionTool[];
1296
+ activatedSetNames?: ReadonlySet<string>;
1297
+ }>;
1298
+
1299
+ /**
1300
+ * Send-policy primitives — the per-turn `tool_choice` / `maxToolRounds` /
1301
+ * thinking-mode / coerced-memory-write rules, unified so web and mobile stop
1302
+ * hand-duplicating them (issue #702, Phase 1).
1303
+ *
1304
+ * These were previously spread across web's `useChatSetup` + `useChatSubmitHandler`
1305
+ * + `webChatSendMessage` and mobile's `chatModeRouting`. They are pure and
1306
+ * node/RN-safe.
1307
+ */
1308
+
1309
+ /** The vault-save tool name — the one client tool stripped on a coerced turn. */
1310
+ declare const MEMORY_SAVE_TOOL_NAME = "memory_vault_save";
1311
+ /**
1312
+ * Resolve the turn's tool-choice from the SHAPE of its server-tools filter,
1313
+ * unless the caller/catalog set an explicit value.
1314
+ *
1315
+ * The rule (matching both apps today): an explicit choice wins; otherwise a
1316
+ * non-empty static array of server tools coerces `required` (creation modes
1317
+ * like image/audio/video/remove-bg must call their one tool), while a filter
1318
+ * function or an empty array defers to `auto` (plain chat, and builder modes
1319
+ * whose server list is empty).
1320
+ *
1321
+ * This is load-bearing: naively defaulting an unset choice to `auto` would
1322
+ * silently downgrade image/audio/video/remove-bg from single-forced-tool to
1323
+ * `auto` — a real behavior regression.
1324
+ */
1325
+ declare function resolveToolChoice(serverTools: ServerToolsFilter, explicit?: ToolChoice): ToolChoice;
1326
+ /**
1327
+ * The per-turn max tool rounds. Returns the catalog entry's value when set,
1328
+ * else the supplied fallback (e.g. web's flat 35), else undefined to let the
1329
+ * SDK/host default apply.
1330
+ */
1331
+ declare function getMaxToolRounds(entry: ServerToolCatalogEntry | undefined, fallback?: number): number | undefined;
1332
+ /**
1333
+ * The per-turn thinking hint. Returns the catalog entry's value when set, else
1334
+ * undefined so the host applies its model-dependent default (e.g. web's
1335
+ * gemini-fast→`fast`, otherwise `thinking`). The app translates the hint into
1336
+ * its provider reasoning config.
1337
+ */
1338
+ declare function getThinkingMode(entry: ServerToolCatalogEntry | undefined, fallback?: ThinkingModeHint): ThinkingModeHint | undefined;
1339
+ /**
1340
+ * Remove `memory_vault_save` from a client-tool list when the turn coerces a
1341
+ * single tool (`tool_choice: "required"`). Under coercion the model MUST call
1342
+ * exactly one tool; leaving the save tool in risks the model "saving" instead
1343
+ * of running the coerced generator. Both apps do this today.
1344
+ *
1345
+ * `recall_memory` and every other tool are preserved. Returns the same array
1346
+ * reference when nothing changed, so callers can cheaply skip re-renders.
1347
+ */
1348
+ declare function stripCoercedMemoryWrite<T extends LlmapiChatCompletionTool>(clientTools: T[], toolChoice: ToolChoice): T[];
1349
+
1350
+ /**
1351
+ * Server-tools policy — resolve the concrete server-tools filter for a turn
1352
+ * from the app-injected {@link ServerToolCatalog} (issue #702, Phase 2).
1353
+ *
1354
+ * The catalog is opaque to the SDK: each app builds it from its own static
1355
+ * server-tool lists (`IMAGE_SERVER_TOOLS`, `SLIDE_SERVER_TOOLS`, …) and passes
1356
+ * it in. This module only knows how to pick the right entry and, when the entry
1357
+ * is an attachment-aware factory, apply it with the turn's context.
1358
+ */
1359
+
1360
+ /**
1361
+ * Look up the catalog entry for a descriptor. Chat turns key on the creation
1362
+ * intent; council/aggregation turns key on the lane.
1363
+ */
1364
+ declare function getCatalogEntry(descriptor: ToolIntentDescriptor, catalog: ServerToolCatalog): ServerToolCatalogEntry | undefined;
1365
+ /**
1366
+ * Resolve a catalog entry's server tools to a concrete filter. The
1367
+ * attachment-aware `resolveServerTools` factory takes precedence over the
1368
+ * static `serverTools` value. When the intent has no catalog entry (or an empty
1369
+ * one) the fallback is used — defaulting to an empty allow-list, which
1370
+ * `resolveToolChoice` reads as `auto`.
1371
+ */
1372
+ declare function resolveServerTools(descriptor: ToolIntentDescriptor, catalog: ServerToolCatalog, fallback?: ServerToolsFilter): ServerToolsFilter;
1373
+ /**
1374
+ * A creation intent whose server tools are a coercing (non-empty static) list —
1375
+ * useful for tests and diagnostics. Distinguishes the "required" creation modes
1376
+ * from the semantic-filter chat modes without resolving a full plan.
1377
+ */
1378
+ declare function isCoercingIntent(creation: CreationIntent, catalog: ServerToolCatalog): boolean;
1379
+
1380
+ export { type AssembledToolsFilterFn, BUILT_IN_TOOL_SETS, CLIENT_TOOLS_MIN_SIMILARITY, CLIENT_TOOLS_RELEVANCE_RATIO, CREATION_INTENT_CLIENT_FACTORIES, CREATION_INTENT_CLIENT_FILTER, CREATION_INTENT_TOOL_SET, type CachedServerTools, type ClientFactoryBuilder, type ClientFactoryKey, type ClientToolsFilterMode, type ConnectorGuidance, type ConnectorGuidanceInput, type CouncilClientSelectionOptions, type CouncilClientToolsInput, type CreateServerToolsFilterOptions, type CreationIntent, DEFAULT_CACHE_EXPIRATION_MS, DEFAULT_EXCLUDED_SERVER_TOOLS, DEFAULT_SERVER_TOOLS_MATCH_OPTIONS, type DeferLoadingConfig, FULL_GENERATIVE_CLIENT_FACTORIES, MAX_CLIENT_TOOLS_AFTER_FILTER, MEMORY_SAVE_TOOL_NAME, MIN_CONTENT_LENGTH_FOR_TOOLS, type ParsedServerToolsResponse, type PostFilterKey, type ResolvePlanContext, SERVER_TOOL_DEPENDENCY_SETS, type SelectServerSideToolsOptions, type SelectServerToolsForPromptOptions, type SelectionLogger, type ServerTool, type ServerToolCatalog, type ServerToolCatalogEntry, type ServerToolsFilter, type ServerToolsFilterContext, type ServerToolsFilterFunction, type ServerToolsOptions, type ServerToolsResponse, TOOL_CATALOG, type ThinkingModeHint, type ToolActivationEvent, type ToolChoice, type ToolConfig, type ToolExecutor, type ToolIntentDescriptor, type ToolLane, type ToolMatchOptions, type ToolMatchResult, type ToolPlanSpec, type ToolSelectionAdapters, type ToolSet, type ToolsCacheBackend, activatedToolSetNames, applyToolSets, assembleClientTools, autoFilterClientTools, buildConnectorGuidance, buildDeniedToolsRider, clearServerToolsCache, composeCouncilClientTools, computeToolGuidance, createServerToolsFilter, defaultServerToolsFilter, deriveActiveToolSets, expandToolSetsAdditive, filterAssembledClientTools, filterServerTools, findMatchingTools, getCachedServerTools, getCatalogEntry, getMaxToolRounds, getServerTools, getThinkingMode, getToolDescription, getToolName, getToolsChecksum, isCoercingIntent, localStorageToolsCache, mergeActiveToolSets, mergeTools, resolveCouncilPlan, resolveCouncilServerTools, resolvePlan, resolveServerTools, resolveToolChoice, scoreTools, selectCouncilClientTools, selectServerSideTools, selectServerToolsForPrompt, shouldRefreshTools, stripCoercedMemoryWrite, toolSetSystemPrompts };