@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.
- package/dist/expo/{chunk-IY7NNIYM.mjs → chunk-IP2B74KE.mjs} +30 -866
- package/dist/expo/index.cjs +1658 -1070
- package/dist/expo/index.d.mts +179 -10
- package/dist/expo/index.d.ts +179 -10
- package/dist/expo/index.mjs +1563 -77
- package/dist/expo/{recall-DJ5LD5WJ.mjs → recall-NSSIYFNY.mjs} +1 -1
- package/dist/index.cjs +415 -394
- package/dist/index.mjs +412 -391
- package/dist/react/{chunk-OSDVRDLI.mjs → chunk-XVC7DWDN.mjs} +22 -1003
- package/dist/react/index.cjs +1702 -1731
- package/dist/react/index.d.mts +103 -12
- package/dist/react/index.d.ts +103 -12
- package/dist/react/index.mjs +1216 -228
- package/dist/react/{recall-3BDCIEQF.mjs → recall-VDP3H3QT.mjs} +1 -1
- package/dist/server/{chunk-QQOIC37O.mjs → chunk-4GKKHVF7.mjs} +21 -833
- package/dist/server/index.cjs +244 -966
- package/dist/server/index.d.mts +95 -12
- package/dist/server/index.d.ts +95 -12
- package/dist/server/index.mjs +189 -32
- package/dist/server/{recall-6QLUEYB7.mjs → recall-KYSR3XZJ.mjs} +1 -1
- package/dist/tools/selection/chunk-4ETHWSXJ.mjs +25 -0
- package/dist/tools/selection/clientConfig-WITO4T6L.mjs +12 -0
- package/dist/tools/selection/index.cjs +1977 -0
- package/dist/tools/selection/index.d.mts +1380 -0
- package/dist/tools/selection/index.d.ts +1380 -0
- package/dist/tools/selection/index.mjs +1859 -0
- package/package.json +8 -1
|
@@ -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 };
|