@flutchai/flutch-sdk 0.6.11 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -0
- package/dist/index.cjs +425 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +69 -3
- package/dist/index.d.ts +69 -3
- package/dist/index.js +411 -9
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -20,6 +20,8 @@ import { dispatchCustomEvent } from '@langchain/core/callbacks/dispatch';
|
|
|
20
20
|
import { DynamicStructuredTool } from '@langchain/core/tools';
|
|
21
21
|
import axios2 from 'axios';
|
|
22
22
|
import { parseCallbackConfigArg, CallbackManager } from '@langchain/core/callbacks/manager';
|
|
23
|
+
import { RunnableLambda } from '@langchain/core/runnables';
|
|
24
|
+
import { z } from 'zod';
|
|
23
25
|
import { ChatOpenAI, OpenAIEmbeddings } from '@langchain/openai';
|
|
24
26
|
import { ChatBedrockConverse } from '@langchain/aws';
|
|
25
27
|
import { fetcher } from 'cohere-ai/core';
|
|
@@ -5384,6 +5386,10 @@ var EventProcessor = class _EventProcessor {
|
|
|
5384
5386
|
...acc.attachments,
|
|
5385
5387
|
...attachments
|
|
5386
5388
|
];
|
|
5389
|
+
this.sendDelta(channel, {
|
|
5390
|
+
type: "attachments_added",
|
|
5391
|
+
attachments
|
|
5392
|
+
}, onPartial);
|
|
5387
5393
|
this.logger.debug("[ATTACHMENTS] Extracted from send_attachments event", {
|
|
5388
5394
|
extractedCount: attachments.length,
|
|
5389
5395
|
totalAccCount: acc.attachments.length
|
|
@@ -5398,7 +5404,8 @@ var EventProcessor = class _EventProcessor {
|
|
|
5398
5404
|
if (chunk.content) {
|
|
5399
5405
|
blocks.push(...this.normalizeContentBlocks(chunk.content));
|
|
5400
5406
|
}
|
|
5401
|
-
|
|
5407
|
+
const contentHasToolBlocks = blocks.some((block) => block?.type === "tool_use" || block?.type === "tool_call" || block?.type === "input_json_delta");
|
|
5408
|
+
if (!contentHasToolBlocks && Array.isArray(chunk.tool_call_chunks) && chunk.tool_call_chunks.length > 0) {
|
|
5402
5409
|
blocks.push(...this.toolCallChunksToBlocks(chunk.tool_call_chunks));
|
|
5403
5410
|
}
|
|
5404
5411
|
if (blocks.length > 0) {
|
|
@@ -7051,6 +7058,314 @@ McpRuntimeHttpClient = _ts_decorate25([
|
|
|
7051
7058
|
])
|
|
7052
7059
|
], McpRuntimeHttpClient);
|
|
7053
7060
|
|
|
7061
|
+
// src/tools/tool-search/tool-search.catalog.ts
|
|
7062
|
+
var K1 = 1.2;
|
|
7063
|
+
var B = 0.75;
|
|
7064
|
+
var NAME_WEIGHT = 3;
|
|
7065
|
+
var STEM_LENGTH = 5;
|
|
7066
|
+
var HIT_DESCRIPTION_CHARS = 240;
|
|
7067
|
+
function toolSearchTerms(text) {
|
|
7068
|
+
return text.replace(/([a-z])([A-Z])/g, "$1 $2").toLowerCase().split(/[^\p{L}\p{N}]+/u).filter((word) => word.length > 1).map((word) => word.slice(0, STEM_LENGTH));
|
|
7069
|
+
}
|
|
7070
|
+
__name(toolSearchTerms, "toolSearchTerms");
|
|
7071
|
+
function schemaParams(schema) {
|
|
7072
|
+
const json = schema;
|
|
7073
|
+
const properties = json?.properties ?? json?.shape ?? {};
|
|
7074
|
+
return Object.entries(properties).flatMap(([name, property]) => property?.description ? [
|
|
7075
|
+
name,
|
|
7076
|
+
property.description
|
|
7077
|
+
] : [
|
|
7078
|
+
name
|
|
7079
|
+
]);
|
|
7080
|
+
}
|
|
7081
|
+
__name(schemaParams, "schemaParams");
|
|
7082
|
+
function shortDescription(description) {
|
|
7083
|
+
const flat = description.replace(/\s+/g, " ").trim();
|
|
7084
|
+
if (flat.length <= HIT_DESCRIPTION_CHARS) return flat;
|
|
7085
|
+
const cut = flat.slice(0, HIT_DESCRIPTION_CHARS);
|
|
7086
|
+
const sentenceEnd = cut.lastIndexOf(". ");
|
|
7087
|
+
return sentenceEnd > HIT_DESCRIPTION_CHARS / 2 ? cut.slice(0, sentenceEnd + 1) : `${cut.trimEnd()}\u2026`;
|
|
7088
|
+
}
|
|
7089
|
+
__name(shortDescription, "shortDescription");
|
|
7090
|
+
var ToolSearchCatalog = class {
|
|
7091
|
+
static {
|
|
7092
|
+
__name(this, "ToolSearchCatalog");
|
|
7093
|
+
}
|
|
7094
|
+
entries;
|
|
7095
|
+
documents;
|
|
7096
|
+
lengths;
|
|
7097
|
+
averageLength;
|
|
7098
|
+
documentFrequency = /* @__PURE__ */ new Map();
|
|
7099
|
+
constructor(tools) {
|
|
7100
|
+
this.entries = tools.map((tool) => ({
|
|
7101
|
+
name: tool.name,
|
|
7102
|
+
description: tool.description ?? "",
|
|
7103
|
+
params: schemaParams(tool.schema)
|
|
7104
|
+
}));
|
|
7105
|
+
this.documents = this.entries.map((entry) => {
|
|
7106
|
+
const nameTerms = toolSearchTerms(entry.name);
|
|
7107
|
+
const terms = [
|
|
7108
|
+
...Array.from({
|
|
7109
|
+
length: NAME_WEIGHT
|
|
7110
|
+
}, () => nameTerms).flat(),
|
|
7111
|
+
...toolSearchTerms(entry.description),
|
|
7112
|
+
...entry.params.flatMap(toolSearchTerms)
|
|
7113
|
+
];
|
|
7114
|
+
const counts = /* @__PURE__ */ new Map();
|
|
7115
|
+
for (const term of terms) counts.set(term, (counts.get(term) ?? 0) + 1);
|
|
7116
|
+
return counts;
|
|
7117
|
+
});
|
|
7118
|
+
this.lengths = this.documents.map((counts) => Array.from(counts.values()).reduce((sum, n) => sum + n, 0));
|
|
7119
|
+
this.averageLength = this.lengths.reduce((sum, n) => sum + n, 0) / Math.max(this.lengths.length, 1);
|
|
7120
|
+
for (const counts of this.documents) {
|
|
7121
|
+
for (const term of counts.keys()) {
|
|
7122
|
+
this.documentFrequency.set(term, (this.documentFrequency.get(term) ?? 0) + 1);
|
|
7123
|
+
}
|
|
7124
|
+
}
|
|
7125
|
+
}
|
|
7126
|
+
get size() {
|
|
7127
|
+
return this.entries.length;
|
|
7128
|
+
}
|
|
7129
|
+
has(name) {
|
|
7130
|
+
return this.entries.some((entry) => entry.name === name);
|
|
7131
|
+
}
|
|
7132
|
+
/**
|
|
7133
|
+
* The best `limit` tools for a query, best first. A query that names a tool
|
|
7134
|
+
* exactly returns that tool first whatever its score. Tools that share no
|
|
7135
|
+
* word with the query are never returned.
|
|
7136
|
+
*/
|
|
7137
|
+
search(query, limit) {
|
|
7138
|
+
const terms = Array.from(new Set(toolSearchTerms(query)));
|
|
7139
|
+
const exact = query.split(/[\s,]+/).map((word) => word.trim()).filter((word) => this.has(word));
|
|
7140
|
+
const total = this.entries.length;
|
|
7141
|
+
const scored = this.entries.map((entry, index) => {
|
|
7142
|
+
const counts = this.documents[index];
|
|
7143
|
+
const length = this.lengths[index];
|
|
7144
|
+
let score = 0;
|
|
7145
|
+
for (const term of terms) {
|
|
7146
|
+
const frequency = counts.get(term);
|
|
7147
|
+
if (!frequency) continue;
|
|
7148
|
+
const df = this.documentFrequency.get(term) ?? 0;
|
|
7149
|
+
const idf = Math.log(1 + (total - df + 0.5) / (df + 0.5));
|
|
7150
|
+
score += idf * frequency * (K1 + 1) / (frequency + K1 * (1 - B + B * length / this.averageLength));
|
|
7151
|
+
}
|
|
7152
|
+
if (exact.includes(entry.name)) score += 1e3;
|
|
7153
|
+
return {
|
|
7154
|
+
entry,
|
|
7155
|
+
score
|
|
7156
|
+
};
|
|
7157
|
+
}).filter(({ score }) => score > 0).sort((a, b) => b.score - a.score);
|
|
7158
|
+
return scored.slice(0, Math.max(1, limit)).map(({ entry }) => ({
|
|
7159
|
+
name: entry.name,
|
|
7160
|
+
description: shortDescription(entry.description)
|
|
7161
|
+
}));
|
|
7162
|
+
}
|
|
7163
|
+
/**
|
|
7164
|
+
* What the catalog covers, as name prefixes with counts:
|
|
7165
|
+
* "funnel_* (4), recipe_* (5), rl_* (41)". Goes into the search tool's
|
|
7166
|
+
* description so the model knows a search is worth making. Sorted, so the
|
|
7167
|
+
* description — and the prompt cache — stays the same between requests.
|
|
7168
|
+
*/
|
|
7169
|
+
summary(maxGroups = 20) {
|
|
7170
|
+
const groups = /* @__PURE__ */ new Map();
|
|
7171
|
+
for (const entry of this.entries) {
|
|
7172
|
+
const prefix = entry.name.includes("_") ? `${entry.name.split("_")[0]}_*` : entry.name;
|
|
7173
|
+
groups.set(prefix, (groups.get(prefix) ?? 0) + 1);
|
|
7174
|
+
}
|
|
7175
|
+
const sorted = Array.from(groups.entries()).sort(([a], [b]) => a.localeCompare(b));
|
|
7176
|
+
const shown = sorted.slice(0, maxGroups).map(([prefix, count]) => count > 1 ? `${prefix} (${count})` : prefix);
|
|
7177
|
+
return sorted.length > maxGroups ? `${shown.join(", ")}, \u2026` : shown.join(", ");
|
|
7178
|
+
}
|
|
7179
|
+
};
|
|
7180
|
+
|
|
7181
|
+
// src/tools/tool-search/tool-search.result.ts
|
|
7182
|
+
var TOOL_SEARCH_NAME = "search_tools";
|
|
7183
|
+
function isToolSearchCall(name) {
|
|
7184
|
+
return name === TOOL_SEARCH_NAME;
|
|
7185
|
+
}
|
|
7186
|
+
__name(isToolSearchCall, "isToolSearchCall");
|
|
7187
|
+
function formatToolSearchResult(hits) {
|
|
7188
|
+
if (hits.length === 0) {
|
|
7189
|
+
return JSON.stringify({
|
|
7190
|
+
tools: [],
|
|
7191
|
+
note: "No tools matched. Search again with other words: what the tool does, the object it works on, or a name prefix."
|
|
7192
|
+
});
|
|
7193
|
+
}
|
|
7194
|
+
return JSON.stringify({
|
|
7195
|
+
tools: hits,
|
|
7196
|
+
note: "These tools are available now. Call them directly."
|
|
7197
|
+
});
|
|
7198
|
+
}
|
|
7199
|
+
__name(formatToolSearchResult, "formatToolSearchResult");
|
|
7200
|
+
function parseToolSearchResult(content) {
|
|
7201
|
+
const text = contentText(content);
|
|
7202
|
+
if (!text) return [];
|
|
7203
|
+
try {
|
|
7204
|
+
const parsed = JSON.parse(text);
|
|
7205
|
+
return (parsed.tools ?? []).map((tool) => tool?.name).filter((name) => typeof name === "string");
|
|
7206
|
+
} catch {
|
|
7207
|
+
return [];
|
|
7208
|
+
}
|
|
7209
|
+
}
|
|
7210
|
+
__name(parseToolSearchResult, "parseToolSearchResult");
|
|
7211
|
+
function contentText(content) {
|
|
7212
|
+
if (typeof content === "string") return content;
|
|
7213
|
+
if (Array.isArray(content)) {
|
|
7214
|
+
return content.map((part) => typeof part === "string" ? part : part && typeof part === "object" && "text" in part ? String(part.text) : "").join("");
|
|
7215
|
+
}
|
|
7216
|
+
return "";
|
|
7217
|
+
}
|
|
7218
|
+
__name(contentText, "contentText");
|
|
7219
|
+
function loadedToolNames(messages) {
|
|
7220
|
+
const searchCallIds = /* @__PURE__ */ new Set();
|
|
7221
|
+
for (const message of messages) {
|
|
7222
|
+
const calls = message.tool_calls;
|
|
7223
|
+
for (const call of calls ?? []) {
|
|
7224
|
+
if (isToolSearchCall(call.name) && call.id) searchCallIds.add(call.id);
|
|
7225
|
+
}
|
|
7226
|
+
}
|
|
7227
|
+
const loaded = [];
|
|
7228
|
+
for (const message of messages) {
|
|
7229
|
+
if (message._getType() !== "tool") continue;
|
|
7230
|
+
const tool = message;
|
|
7231
|
+
const isSearch = isToolSearchCall(tool.name) || tool.tool_call_id !== void 0 && searchCallIds.has(tool.tool_call_id);
|
|
7232
|
+
if (!isSearch) continue;
|
|
7233
|
+
for (const name of parseToolSearchResult(tool.content)) {
|
|
7234
|
+
if (!loaded.includes(name)) loaded.push(name);
|
|
7235
|
+
}
|
|
7236
|
+
}
|
|
7237
|
+
return loaded;
|
|
7238
|
+
}
|
|
7239
|
+
__name(loadedToolNames, "loadedToolNames");
|
|
7240
|
+
var DEFAULT_TOOL_SEARCH_RESULTS = 5;
|
|
7241
|
+
var DEFAULT_TOOL_SEARCH_MIN_TOOLS = 15;
|
|
7242
|
+
function toolSearchApplies(options, toolCount) {
|
|
7243
|
+
return !!options?.enabled && toolCount >= (options.minTools ?? DEFAULT_TOOL_SEARCH_MIN_TOOLS);
|
|
7244
|
+
}
|
|
7245
|
+
__name(toolSearchApplies, "toolSearchApplies");
|
|
7246
|
+
function splitTools(tools, options, extraCore = []) {
|
|
7247
|
+
const listed = typeof options.alwaysLoaded === "string" ? options.alwaysLoaded.split(",") : options.alwaysLoaded ?? [];
|
|
7248
|
+
const always = /* @__PURE__ */ new Set([
|
|
7249
|
+
...listed.map((name) => name.trim()).filter(Boolean),
|
|
7250
|
+
...extraCore.map((tool) => tool.name)
|
|
7251
|
+
]);
|
|
7252
|
+
return {
|
|
7253
|
+
core: tools.filter((tool) => always.has(tool.name)),
|
|
7254
|
+
deferred: tools.filter((tool) => !always.has(tool.name))
|
|
7255
|
+
};
|
|
7256
|
+
}
|
|
7257
|
+
__name(splitTools, "splitTools");
|
|
7258
|
+
function createToolSearchTool(catalog, maxResults = DEFAULT_TOOL_SEARCH_RESULTS) {
|
|
7259
|
+
return new DynamicStructuredTool({
|
|
7260
|
+
name: TOOL_SEARCH_NAME,
|
|
7261
|
+
description: `Find more tools. You see only some of your tools; ${catalog.size} more are found by search: ${catalog.summary()}. Describe the task in a few words (what to do and with what, e.g. "customer review quotes by theme"), or give exact tool names. Found tools become callable right away and stay available for the rest of the conversation. Search before saying you cannot do something.`,
|
|
7262
|
+
schema: z.object({
|
|
7263
|
+
query: z.string().describe("What the tool should do, in a few words, or tool names separated by commas"),
|
|
7264
|
+
limit: z.number().int().min(1).max(20).optional().describe(`How many tools to return (default ${maxResults})`)
|
|
7265
|
+
}),
|
|
7266
|
+
func: /* @__PURE__ */ __name(async ({ query, limit }) => formatToolSearchResult(catalog.search(query, limit ?? maxResults)), "func")
|
|
7267
|
+
});
|
|
7268
|
+
}
|
|
7269
|
+
__name(createToolSearchTool, "createToolSearchTool");
|
|
7270
|
+
function deferredCopy(tool) {
|
|
7271
|
+
const copy = Object.create(tool);
|
|
7272
|
+
copy.extras = {
|
|
7273
|
+
...tool.extras ?? {},
|
|
7274
|
+
defer_loading: true
|
|
7275
|
+
};
|
|
7276
|
+
return copy;
|
|
7277
|
+
}
|
|
7278
|
+
__name(deferredCopy, "deferredCopy");
|
|
7279
|
+
function bindToolsWithSearch(params) {
|
|
7280
|
+
const { model, core, deferred, searchTool, mode, bindOptions } = params;
|
|
7281
|
+
const bind = /* @__PURE__ */ __name((tools) => bindOptions ? model.bindTools(tools, bindOptions) : model.bindTools(tools), "bind");
|
|
7282
|
+
if (mode === "deferred") {
|
|
7283
|
+
return bind([
|
|
7284
|
+
searchTool,
|
|
7285
|
+
...core,
|
|
7286
|
+
...deferred.map(deferredCopy)
|
|
7287
|
+
]);
|
|
7288
|
+
}
|
|
7289
|
+
const byName = new Map(deferred.map((tool) => [
|
|
7290
|
+
tool.name,
|
|
7291
|
+
tool
|
|
7292
|
+
]));
|
|
7293
|
+
const bound = /* @__PURE__ */ new Map();
|
|
7294
|
+
const forHistory = /* @__PURE__ */ __name((messages) => {
|
|
7295
|
+
const found = loadedToolNames(messages).filter((name) => byName.has(name));
|
|
7296
|
+
const key = found.join(",");
|
|
7297
|
+
let runnable = bound.get(key);
|
|
7298
|
+
if (!runnable) {
|
|
7299
|
+
runnable = bind([
|
|
7300
|
+
...core,
|
|
7301
|
+
searchTool,
|
|
7302
|
+
...found.map((name) => byName.get(name))
|
|
7303
|
+
]);
|
|
7304
|
+
bound.set(key, runnable);
|
|
7305
|
+
}
|
|
7306
|
+
return runnable;
|
|
7307
|
+
}, "forHistory");
|
|
7308
|
+
return RunnableLambda.from(async (input, config) => {
|
|
7309
|
+
const messages = Array.isArray(input) ? input : [];
|
|
7310
|
+
return forHistory(messages).invoke(input, config);
|
|
7311
|
+
}).withConfig({
|
|
7312
|
+
runName: "ToolSearchModel"
|
|
7313
|
+
});
|
|
7314
|
+
}
|
|
7315
|
+
__name(bindToolsWithSearch, "bindToolsWithSearch");
|
|
7316
|
+
|
|
7317
|
+
// src/tools/tool-search/tool-reference.fetch.ts
|
|
7318
|
+
function rewriteToolReferences(body) {
|
|
7319
|
+
if (!body.includes(TOOL_SEARCH_NAME)) return body;
|
|
7320
|
+
let parsed;
|
|
7321
|
+
try {
|
|
7322
|
+
parsed = JSON.parse(body);
|
|
7323
|
+
} catch {
|
|
7324
|
+
return body;
|
|
7325
|
+
}
|
|
7326
|
+
const known = new Set((parsed.tools ?? []).map((tool) => tool.name));
|
|
7327
|
+
const searchIds = /* @__PURE__ */ new Set();
|
|
7328
|
+
for (const message of parsed.messages ?? []) {
|
|
7329
|
+
if (message.role !== "assistant" || !Array.isArray(message.content)) continue;
|
|
7330
|
+
for (const block of message.content) {
|
|
7331
|
+
if (block.type === "tool_use" && block.name === TOOL_SEARCH_NAME && block.id) {
|
|
7332
|
+
searchIds.add(block.id);
|
|
7333
|
+
}
|
|
7334
|
+
}
|
|
7335
|
+
}
|
|
7336
|
+
if (searchIds.size === 0) return body;
|
|
7337
|
+
let changed = false;
|
|
7338
|
+
for (const message of parsed.messages ?? []) {
|
|
7339
|
+
if (message.role !== "user" || !Array.isArray(message.content)) continue;
|
|
7340
|
+
for (const block of message.content) {
|
|
7341
|
+
if (block.type !== "tool_result" || !block.tool_use_id) continue;
|
|
7342
|
+
if (!searchIds.has(block.tool_use_id)) continue;
|
|
7343
|
+
const names = parseToolSearchResult(block.content).filter((name) => known.has(name));
|
|
7344
|
+
if (names.length === 0) continue;
|
|
7345
|
+
block.content = names.map((name) => ({
|
|
7346
|
+
type: "tool_reference",
|
|
7347
|
+
tool_name: name
|
|
7348
|
+
}));
|
|
7349
|
+
changed = true;
|
|
7350
|
+
}
|
|
7351
|
+
}
|
|
7352
|
+
return changed ? JSON.stringify(parsed) : body;
|
|
7353
|
+
}
|
|
7354
|
+
__name(rewriteToolReferences, "rewriteToolReferences");
|
|
7355
|
+
function withToolReferences(inner) {
|
|
7356
|
+
return (input, init) => {
|
|
7357
|
+
if (init && typeof init.body === "string") {
|
|
7358
|
+
const body = rewriteToolReferences(init.body);
|
|
7359
|
+
if (body !== init.body) return inner(input, {
|
|
7360
|
+
...init,
|
|
7361
|
+
body
|
|
7362
|
+
});
|
|
7363
|
+
}
|
|
7364
|
+
return inner(input, init);
|
|
7365
|
+
};
|
|
7366
|
+
}
|
|
7367
|
+
__name(withToolReferences, "withToolReferences");
|
|
7368
|
+
|
|
7054
7369
|
// src/models/enums.ts
|
|
7055
7370
|
var ModelProvider = /* @__PURE__ */ (function(ModelProvider2) {
|
|
7056
7371
|
ModelProvider2["MISTRAL"] = "mistral";
|
|
@@ -7417,6 +7732,8 @@ var ModelInitializer = class _ModelInitializer {
|
|
|
7417
7732
|
modelConfigCache = /* @__PURE__ */ new Map();
|
|
7418
7733
|
// Cache for model instances to avoid recreating identical models
|
|
7419
7734
|
modelInstanceCache = /* @__PURE__ */ new Map();
|
|
7735
|
+
// Tool-search catalogs, keyed like the model instance that uses them
|
|
7736
|
+
toolSearchCatalogs = /* @__PURE__ */ new Map();
|
|
7420
7737
|
static DEFAULT_ENV_MAP = {
|
|
7421
7738
|
[ModelProvider.OPENAI]: "OPENAI_API_KEY",
|
|
7422
7739
|
[ModelProvider.ANTHROPIC]: "ANTHROPIC_API_KEY",
|
|
@@ -7492,7 +7809,8 @@ var ModelInitializer = class _ModelInitializer {
|
|
|
7492
7809
|
const withMcp = config.mcpServers && config.mcpServers.length > 0 ? `${base}:mcp:${JSON.stringify(config.mcpServers)}` : base;
|
|
7493
7810
|
const withSampling = config.supportsSamplingParams === void 0 ? withMcp : `${withMcp}:sp:${config.supportsSamplingParams}`;
|
|
7494
7811
|
const withCache = config.promptCache === void 0 && config.promptCacheTtl === void 0 ? withSampling : `${withSampling}:pc:${config.promptCache ?? "auto"}:${config.promptCacheTtl ?? "default"}`;
|
|
7495
|
-
|
|
7812
|
+
const withEffort = config.effort === void 0 ? withCache : `${withCache}:eff:${config.effort}`;
|
|
7813
|
+
return config.toolSearch?.enabled ? `${withEffort}:ts:${JSON.stringify(config.toolSearch)}` : withEffort;
|
|
7496
7814
|
}
|
|
7497
7815
|
// Chat model creators
|
|
7498
7816
|
chatModelCreators = {
|
|
@@ -7526,10 +7844,13 @@ var ModelInitializer = class _ModelInitializer {
|
|
|
7526
7844
|
},
|
|
7527
7845
|
anthropicApiKey: apiToken || this.resolveApiKey(ModelProvider.ANTHROPIC),
|
|
7528
7846
|
...routerURL && {
|
|
7529
|
-
anthropicApiUrl: routerURL
|
|
7530
|
-
|
|
7531
|
-
|
|
7532
|
-
|
|
7847
|
+
anthropicApiUrl: routerURL
|
|
7848
|
+
},
|
|
7849
|
+
// Tool search results become `tool_reference` blocks on the wire
|
|
7850
|
+
// (LangChain cannot express them). A request without a search passes
|
|
7851
|
+
// through untouched.
|
|
7852
|
+
clientOptions: {
|
|
7853
|
+
fetch: withToolReferences(routerURL ? flutchFetch : fetch)
|
|
7533
7854
|
}
|
|
7534
7855
|
});
|
|
7535
7856
|
},
|
|
@@ -7773,7 +8094,11 @@ var ModelInitializer = class _ModelInitializer {
|
|
|
7773
8094
|
// Converse takes cache control as a per-call option; the Anthropic
|
|
7774
8095
|
// client already got it as a constructor field, and handing it the
|
|
7775
8096
|
// same value twice would put an unknown key in its call options.
|
|
7776
|
-
finalConfig.useBedrock ? promptCacheControl : void 0
|
|
8097
|
+
finalConfig.useBedrock ? promptCacheControl : void 0,
|
|
8098
|
+
config.toolSearch?.enabled ? {
|
|
8099
|
+
options: config.toolSearch,
|
|
8100
|
+
cacheKey
|
|
8101
|
+
} : void 0
|
|
7777
8102
|
);
|
|
7778
8103
|
this.modelInstanceCache.set(cacheKey, boundModel);
|
|
7779
8104
|
return boundModel;
|
|
@@ -7799,8 +8124,9 @@ var ModelInitializer = class _ModelInitializer {
|
|
|
7799
8124
|
* - Runnable when tools are bound (model.bindTools returns Runnable)
|
|
7800
8125
|
* - BaseChatModel when no tools
|
|
7801
8126
|
*/
|
|
7802
|
-
async bindToolsToModel(model, toolsConfig, customTools, mcpServers, mcpContext, promptCacheControl) {
|
|
8127
|
+
async bindToolsToModel(model, toolsConfig, customTools, mcpServers, mcpContext, promptCacheControl, toolSearch) {
|
|
7803
8128
|
const allTools = [];
|
|
8129
|
+
const mcpToolsFound = [];
|
|
7804
8130
|
const enabledToolsConfig = (toolsConfig || []).filter((tc) => tc.enabled !== false);
|
|
7805
8131
|
const hasInlineServers = !!(mcpServers && mcpServers.length > 0);
|
|
7806
8132
|
if (enabledToolsConfig.length > 0 || hasInlineServers) {
|
|
@@ -7810,6 +8136,7 @@ var ModelInitializer = class _ModelInitializer {
|
|
|
7810
8136
|
const mcpTools = await mcpToolFilter.getFilteredTools(enabledToolsConfig, mcpServers, mcpContext);
|
|
7811
8137
|
this.logger.debug(`Successfully fetched ${mcpTools.length} tools with dynamic schemas from MCP Runtime`);
|
|
7812
8138
|
allTools.push(...mcpTools);
|
|
8139
|
+
mcpToolsFound.push(...mcpTools);
|
|
7813
8140
|
} catch (error) {
|
|
7814
8141
|
this.logger.error(`Failed to fetch tools from MCP Runtime: ${error instanceof Error ? error.message : String(error)}`);
|
|
7815
8142
|
}
|
|
@@ -7823,11 +8150,86 @@ var ModelInitializer = class _ModelInitializer {
|
|
|
7823
8150
|
const boundOptions = {
|
|
7824
8151
|
cache_control: promptCacheControl
|
|
7825
8152
|
};
|
|
8153
|
+
if (toolSearch && toolSearchApplies(toolSearch.options, allTools.length)) {
|
|
8154
|
+
const { core, deferred } = splitTools(mcpToolsFound, toolSearch.options, customTools ?? []);
|
|
8155
|
+
if (deferred.length > 0) {
|
|
8156
|
+
const maxResults = toolSearch.options.maxResults ?? DEFAULT_TOOL_SEARCH_RESULTS;
|
|
8157
|
+
const catalog = new ToolSearchCatalog(deferred);
|
|
8158
|
+
this.toolSearchCatalogs.set(toolSearch.cacheKey, {
|
|
8159
|
+
catalog,
|
|
8160
|
+
maxResults
|
|
8161
|
+
});
|
|
8162
|
+
const mode = model instanceof ChatAnthropic ? "deferred" : "rebind";
|
|
8163
|
+
this.logger.debug(`Tool search (${mode}): ${core.length + (customTools?.length ?? 0)} tools in sight, ${deferred.length} found on demand`);
|
|
8164
|
+
return bindToolsWithSearch({
|
|
8165
|
+
model,
|
|
8166
|
+
core: [
|
|
8167
|
+
...core,
|
|
8168
|
+
...customTools ?? []
|
|
8169
|
+
],
|
|
8170
|
+
deferred,
|
|
8171
|
+
searchTool: createToolSearchTool(catalog, maxResults),
|
|
8172
|
+
mode,
|
|
8173
|
+
bindOptions: promptCacheControl ? boundOptions : void 0
|
|
8174
|
+
});
|
|
8175
|
+
}
|
|
8176
|
+
}
|
|
7826
8177
|
const modelWithTools = promptCacheControl ? model.bindTools(allTools, boundOptions) : model.bindTools(allTools);
|
|
7827
8178
|
return modelWithTools;
|
|
7828
8179
|
}
|
|
7829
8180
|
return model;
|
|
7830
8181
|
}
|
|
8182
|
+
/**
|
|
8183
|
+
* Runs a `search_tools` call. `config` must be the one the model was
|
|
8184
|
+
* initialized with (same tools, same `toolSearch`): it names the catalog.
|
|
8185
|
+
* Emits tool start/end events like `McpRuntimeHttpClient.executeToolWithEvents`,
|
|
8186
|
+
* so the call shows as a finished step in the chat.
|
|
8187
|
+
*
|
|
8188
|
+
* Never throws: a failure comes back as the tool's answer.
|
|
8189
|
+
*/
|
|
8190
|
+
async searchTools(config, args, runConfig) {
|
|
8191
|
+
const parsedConfig = parseCallbackConfigArg(runConfig);
|
|
8192
|
+
const callbackManager = CallbackManager.configure(parsedConfig.callbacks);
|
|
8193
|
+
const runManager = await callbackManager?.handleToolStart({
|
|
8194
|
+
name: TOOL_SEARCH_NAME,
|
|
8195
|
+
lc: 1,
|
|
8196
|
+
type: "not_implemented",
|
|
8197
|
+
id: [
|
|
8198
|
+
"langchain",
|
|
8199
|
+
"tools",
|
|
8200
|
+
TOOL_SEARCH_NAME
|
|
8201
|
+
]
|
|
8202
|
+
}, JSON.stringify(args ?? {}), parsedConfig.runId, void 0, parsedConfig.tags, parsedConfig.metadata, TOOL_SEARCH_NAME);
|
|
8203
|
+
try {
|
|
8204
|
+
const key = this.generateModelCacheKey(config);
|
|
8205
|
+
if (!this.toolSearchCatalogs.has(key)) {
|
|
8206
|
+
await this.initializeChatModel(config);
|
|
8207
|
+
}
|
|
8208
|
+
const entry = this.toolSearchCatalogs.get(key);
|
|
8209
|
+
const query = typeof args?.query === "string" ? args.query : "";
|
|
8210
|
+
const limit = Number(args?.limit);
|
|
8211
|
+
const content = !entry ? JSON.stringify({
|
|
8212
|
+
error: "Tool search is not available for this agent: every tool is already loaded."
|
|
8213
|
+
}) : !query.trim() ? JSON.stringify({
|
|
8214
|
+
error: "query is required"
|
|
8215
|
+
}) : formatToolSearchResult(entry.catalog.search(query, Number.isFinite(limit) && limit > 0 ? limit : entry.maxResults));
|
|
8216
|
+
await runManager?.handleToolEnd(content);
|
|
8217
|
+
return {
|
|
8218
|
+
content,
|
|
8219
|
+
success: !!entry && !!query.trim()
|
|
8220
|
+
};
|
|
8221
|
+
} catch (error) {
|
|
8222
|
+
await runManager?.handleToolError(error);
|
|
8223
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
8224
|
+
this.logger.error(`Tool search failed: ${message}`);
|
|
8225
|
+
return {
|
|
8226
|
+
content: JSON.stringify({
|
|
8227
|
+
error: `Tool search failed: ${message}`
|
|
8228
|
+
}),
|
|
8229
|
+
success: false
|
|
8230
|
+
};
|
|
8231
|
+
}
|
|
8232
|
+
}
|
|
7831
8233
|
async initializeRerankModel(config) {
|
|
7832
8234
|
const cacheKey = this.generateModelCacheKey(config);
|
|
7833
8235
|
const cachedModel = this.modelInstanceCache.get(cacheKey);
|
|
@@ -8616,6 +9018,6 @@ var MongoTokenStore = class {
|
|
|
8616
9018
|
}
|
|
8617
9019
|
};
|
|
8618
9020
|
|
|
8619
|
-
export { AbstractGraphBuilder, AttachmentType, GraphController as BaseGraphServiceController, UniversalGraphModule as BaseGraphServiceModule, BuilderRegistryService, Callback, CallbackACL, CallbackAuditAction, CallbackAuditor, CallbackController, CallbackMetrics, CallbackPatchService, CallbackRateLimiter, CallbackRegistry, CallbackStore, CallbackTokenGuard, ChatFeature, DEFAULT_ATTACHMENT_THRESHOLD, DEFAULT_ROUTER_URL, DEFAULT_TRACER_OPTIONS, ENDPOINT_METADATA_KEY, Endpoint, EndpointRegistry, EventProcessor, ExternalGraphBuilder, FileBasedDiscovery, FileTokenStore, FlutchChatBedrockConverse, GraphController, GraphEngineFactory, GraphEngineType, GraphManifestSchema, GraphManifestValidator, GraphServiceTokens, GraphTypeUtils, IdempotencyManager, IdempotencyStatus, LangGraphEngine, McpConverter, McpRuntimeHttpClient, McpToolFilter, ModelInitializer, ModelProvider, ModelType, MongoTokenStore, OAuthTokenManager, PROMPT_CACHE_MIN_VERSIONS, RetrieverSearchType, RetrieverService, SAMPLING_PARAM_FREE_THRESHOLDS, SmartCallbackRouter, StaticDiscovery, StreamChannel, TelegramPatchHandler, UIDispatchController, UIEndpoint, UIEndpointsDiscoveryService, UniversalCallbackService, UniversalGraphModule, UniversalGraphService, VersionedGraphService, VoyageAIRerank, WebPatchHandler, WithCallbacks, WithEndpoints, WithUIEndpoints, _internals, bootstrap, buildEffortRequestFields, buildOAuthAuthorizationUrl, buildOpenAIModelConfig, clearAttachmentDataStore, createEndpointDescriptors, createGraphAttachment, createMongoClientAdapter, createStaticMessage, decryptTokens, dispatchAttachments, encryptTokens, executeToolWithAttachments, findCallbackMethod, findEndpointMethod, flutchFetch, flutchHeaders, flutchMistralHook, generateAttachmentSummary, generateModelCacheKey, getAttachmentData, getCallbackMetadata, getEndpointMetadata, getFlutchContext, getOAuthProvider, getOAuthProviderNames, getUIEndpointClassMetadata, getUIEndpointMethodsMetadata, hasCallbacks, hasUIEndpoints, hashToolsConfig, isInternalMode, isReasoningBlock, isReasoningModel, isSendableReasoningBlock, joinTextSteps, loadOAuthProviders, modelAcceptsSamplingParams, modelSupportsPromptCache, normalizeToolConfigs, redactConnectionString, registerFinanceExampleCallback, registerUIEndpointsFromClass, resolveOAuthProviderConfig, resolvePromptCacheControl, resolveRouterURL, resolveSamplingParams, sanitizeMessageReasoning, sanitizeReasoningForBedrock, sanitizeTraceData, storeAttachmentData, toOptionalNumber, traceApiCall, withFlutchContext, wrapCohereFetcher };
|
|
9021
|
+
export { AbstractGraphBuilder, AttachmentType, GraphController as BaseGraphServiceController, UniversalGraphModule as BaseGraphServiceModule, BuilderRegistryService, Callback, CallbackACL, CallbackAuditAction, CallbackAuditor, CallbackController, CallbackMetrics, CallbackPatchService, CallbackRateLimiter, CallbackRegistry, CallbackStore, CallbackTokenGuard, ChatFeature, DEFAULT_ATTACHMENT_THRESHOLD, DEFAULT_ROUTER_URL, DEFAULT_TOOL_SEARCH_MIN_TOOLS, DEFAULT_TOOL_SEARCH_RESULTS, DEFAULT_TRACER_OPTIONS, ENDPOINT_METADATA_KEY, Endpoint, EndpointRegistry, EventProcessor, ExternalGraphBuilder, FileBasedDiscovery, FileTokenStore, FlutchChatBedrockConverse, GraphController, GraphEngineFactory, GraphEngineType, GraphManifestSchema, GraphManifestValidator, GraphServiceTokens, GraphTypeUtils, IdempotencyManager, IdempotencyStatus, LangGraphEngine, McpConverter, McpRuntimeHttpClient, McpToolFilter, ModelInitializer, ModelProvider, ModelType, MongoTokenStore, OAuthTokenManager, PROMPT_CACHE_MIN_VERSIONS, RetrieverSearchType, RetrieverService, SAMPLING_PARAM_FREE_THRESHOLDS, SmartCallbackRouter, StaticDiscovery, StreamChannel, TOOL_SEARCH_NAME, TelegramPatchHandler, ToolSearchCatalog, UIDispatchController, UIEndpoint, UIEndpointsDiscoveryService, UniversalCallbackService, UniversalGraphModule, UniversalGraphService, VersionedGraphService, VoyageAIRerank, WebPatchHandler, WithCallbacks, WithEndpoints, WithUIEndpoints, _internals, bindToolsWithSearch, bootstrap, buildEffortRequestFields, buildOAuthAuthorizationUrl, buildOpenAIModelConfig, clearAttachmentDataStore, createEndpointDescriptors, createGraphAttachment, createMongoClientAdapter, createStaticMessage, createToolSearchTool, decryptTokens, dispatchAttachments, encryptTokens, executeToolWithAttachments, findCallbackMethod, findEndpointMethod, flutchFetch, flutchHeaders, flutchMistralHook, formatToolSearchResult, generateAttachmentSummary, generateModelCacheKey, getAttachmentData, getCallbackMetadata, getEndpointMetadata, getFlutchContext, getOAuthProvider, getOAuthProviderNames, getUIEndpointClassMetadata, getUIEndpointMethodsMetadata, hasCallbacks, hasUIEndpoints, hashToolsConfig, isInternalMode, isReasoningBlock, isReasoningModel, isSendableReasoningBlock, isToolSearchCall, joinTextSteps, loadOAuthProviders, loadedToolNames, modelAcceptsSamplingParams, modelSupportsPromptCache, normalizeToolConfigs, parseToolSearchResult, redactConnectionString, registerFinanceExampleCallback, registerUIEndpointsFromClass, resolveOAuthProviderConfig, resolvePromptCacheControl, resolveRouterURL, resolveSamplingParams, rewriteToolReferences, sanitizeMessageReasoning, sanitizeReasoningForBedrock, sanitizeTraceData, splitTools, storeAttachmentData, toOptionalNumber, toolSearchApplies, toolSearchTerms, traceApiCall, withFlutchContext, withToolReferences, wrapCohereFetcher };
|
|
8620
9022
|
//# sourceMappingURL=index.js.map
|
|
8621
9023
|
//# sourceMappingURL=index.js.map
|