@yourgpt/llm-sdk 2.1.3 → 2.1.4-alpha.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.
Files changed (58) hide show
  1. package/README.md +59 -0
  2. package/dist/adapters/index.d.mts +9 -2
  3. package/dist/adapters/index.d.ts +9 -2
  4. package/dist/adapters/index.js +421 -19
  5. package/dist/adapters/index.js.map +1 -1
  6. package/dist/adapters/index.mjs +421 -19
  7. package/dist/adapters/index.mjs.map +1 -1
  8. package/dist/index.d.mts +164 -11
  9. package/dist/index.d.ts +164 -11
  10. package/dist/index.js +638 -54
  11. package/dist/index.js.map +1 -1
  12. package/dist/index.mjs +635 -55
  13. package/dist/index.mjs.map +1 -1
  14. package/dist/providers/anthropic/index.d.mts +1 -1
  15. package/dist/providers/anthropic/index.d.ts +1 -1
  16. package/dist/providers/anthropic/index.js +95 -1
  17. package/dist/providers/anthropic/index.js.map +1 -1
  18. package/dist/providers/anthropic/index.mjs +95 -1
  19. package/dist/providers/anthropic/index.mjs.map +1 -1
  20. package/dist/providers/azure/index.d.mts +1 -1
  21. package/dist/providers/azure/index.d.ts +1 -1
  22. package/dist/providers/azure/index.js +51 -5
  23. package/dist/providers/azure/index.js.map +1 -1
  24. package/dist/providers/azure/index.mjs +51 -5
  25. package/dist/providers/azure/index.mjs.map +1 -1
  26. package/dist/providers/google/index.d.mts +1 -1
  27. package/dist/providers/google/index.d.ts +1 -1
  28. package/dist/providers/google/index.js +76 -0
  29. package/dist/providers/google/index.js.map +1 -1
  30. package/dist/providers/google/index.mjs +76 -0
  31. package/dist/providers/google/index.mjs.map +1 -1
  32. package/dist/providers/ollama/index.d.mts +2 -2
  33. package/dist/providers/ollama/index.d.ts +2 -2
  34. package/dist/providers/ollama/index.js +51 -8
  35. package/dist/providers/ollama/index.js.map +1 -1
  36. package/dist/providers/ollama/index.mjs +51 -8
  37. package/dist/providers/ollama/index.mjs.map +1 -1
  38. package/dist/providers/openai/index.d.mts +1 -1
  39. package/dist/providers/openai/index.d.ts +1 -1
  40. package/dist/providers/openai/index.js +301 -3
  41. package/dist/providers/openai/index.js.map +1 -1
  42. package/dist/providers/openai/index.mjs +301 -3
  43. package/dist/providers/openai/index.mjs.map +1 -1
  44. package/dist/providers/openrouter/index.d.mts +1 -1
  45. package/dist/providers/openrouter/index.d.ts +1 -1
  46. package/dist/providers/openrouter/index.js +301 -3
  47. package/dist/providers/openrouter/index.js.map +1 -1
  48. package/dist/providers/openrouter/index.mjs +301 -3
  49. package/dist/providers/openrouter/index.mjs.map +1 -1
  50. package/dist/providers/xai/index.d.mts +1 -1
  51. package/dist/providers/xai/index.d.ts +1 -1
  52. package/dist/providers/xai/index.js +51 -5
  53. package/dist/providers/xai/index.js.map +1 -1
  54. package/dist/providers/xai/index.mjs +51 -5
  55. package/dist/providers/xai/index.mjs.map +1 -1
  56. package/dist/{types-D20jKwJW.d.mts → types-COAOEe_y.d.mts} +68 -8
  57. package/dist/{types-D20jKwJW.d.ts → types-COAOEe_y.d.ts} +68 -8
  58. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -1147,6 +1147,279 @@ var GenerateResult = class {
1147
1147
  }
1148
1148
  };
1149
1149
 
1150
+ // src/server/tool-selection.ts
1151
+ var BM25_K1 = 1.2;
1152
+ var BM25_B = 0.75;
1153
+ var MIN_SCORE = 0.1;
1154
+ function unique(values) {
1155
+ return [...new Set(values)];
1156
+ }
1157
+ function tokenize(text) {
1158
+ return text.toLowerCase().replace(/[^a-z0-9_\s-]/g, " ").split(/\s+/).filter((token) => token.length > 1);
1159
+ }
1160
+ function stringifyContent(content) {
1161
+ if (typeof content === "string") return content;
1162
+ if (!content) return "";
1163
+ try {
1164
+ return JSON.stringify(content);
1165
+ } catch {
1166
+ return String(content);
1167
+ }
1168
+ }
1169
+ function buildToolQuery(messages) {
1170
+ return messages.filter((m) => m.role === "user" || m.role === "assistant").slice(-3).map((m) => stringifyContent(m.content)).filter(Boolean).join(" ");
1171
+ }
1172
+ function buildSearchText(tool2) {
1173
+ return [
1174
+ tool2.name.replace(/_/g, " "),
1175
+ tool2.description,
1176
+ tool2.category ?? "",
1177
+ tool2.group ?? "",
1178
+ ...tool2.profiles ?? [],
1179
+ ...tool2.searchKeywords ?? []
1180
+ ].filter(Boolean).join(" ");
1181
+ }
1182
+ function matchesSelector(tool2, selector, activeProfile) {
1183
+ const normalized = selector.trim().toLowerCase();
1184
+ if (!normalized) return false;
1185
+ if (normalized === "*" || normalized === "all") return true;
1186
+ if (normalized === tool2.name.toLowerCase()) return true;
1187
+ if (normalized.startsWith("group:")) {
1188
+ return (tool2.group ?? "").toLowerCase() === normalized.slice(6);
1189
+ }
1190
+ if (normalized.startsWith("category:")) {
1191
+ return (tool2.category ?? "").toLowerCase() === normalized.slice(9);
1192
+ }
1193
+ if (normalized.startsWith("profile:")) {
1194
+ return (tool2.profiles ?? []).map((v) => v.toLowerCase()).includes(normalized.slice(8));
1195
+ }
1196
+ if (activeProfile && normalized === activeProfile.toLowerCase()) {
1197
+ return (tool2.profiles ?? []).map((v) => v.toLowerCase()).includes(normalized);
1198
+ }
1199
+ return false;
1200
+ }
1201
+ function scoreTool(tool2, queryTokens, activeProfile) {
1202
+ const haystack = [
1203
+ tool2.name,
1204
+ tool2.description,
1205
+ tool2.category,
1206
+ tool2.group,
1207
+ ...tool2.profiles ?? [],
1208
+ ...tool2.searchKeywords ?? []
1209
+ ].filter(Boolean).join(" ").toLowerCase();
1210
+ let score = tool2.deferLoading ? 0 : 2;
1211
+ if (activeProfile && tool2.profiles?.includes(activeProfile)) score += 2;
1212
+ for (const token of queryTokens) {
1213
+ if (tool2.name.toLowerCase() === token) score += 6;
1214
+ else if (tool2.name.toLowerCase().includes(token)) score += 4;
1215
+ else if (haystack.includes(token)) score += 2;
1216
+ }
1217
+ return score;
1218
+ }
1219
+ function filterToolsByProfile(params) {
1220
+ const available = params.tools.filter((tool2) => tool2.available !== false);
1221
+ const config = params.config;
1222
+ if (!config) return available;
1223
+ const activeProfile = params.activeProfile ?? config.defaultProfile;
1224
+ const includeUnprofiled = config.includeUnprofiled ?? true;
1225
+ const profile = activeProfile ? config.profiles?.[activeProfile] : void 0;
1226
+ let filtered = available;
1227
+ if (profile?.include?.length) {
1228
+ filtered = filtered.filter(
1229
+ (tool2) => profile.include.some(
1230
+ (selector) => matchesSelector(tool2, selector, activeProfile)
1231
+ ) || !!activeProfile && tool2.profiles?.includes(activeProfile)
1232
+ );
1233
+ } else if (activeProfile) {
1234
+ filtered = filtered.filter((tool2) => {
1235
+ if (tool2.profiles?.length) return tool2.profiles.includes(activeProfile);
1236
+ return includeUnprofiled;
1237
+ });
1238
+ }
1239
+ if (profile?.exclude?.length) {
1240
+ filtered = filtered.filter(
1241
+ (tool2) => !profile.exclude.some(
1242
+ (selector) => matchesSelector(tool2, selector, activeProfile)
1243
+ )
1244
+ );
1245
+ }
1246
+ return filtered;
1247
+ }
1248
+ function calculateBM25Score(tool2, queryTerms, idf, avgDocLength, activeProfile) {
1249
+ const text = buildSearchText(tool2);
1250
+ const tokens = tokenize(text);
1251
+ const docLength = Math.max(1, tokens.length);
1252
+ let score = 0;
1253
+ for (const term of queryTerms) {
1254
+ const termFreq = tokens.filter((t) => t === term).length;
1255
+ if (termFreq === 0) continue;
1256
+ const termIDF = idf.get(term) ?? 0;
1257
+ const numerator = termFreq * (BM25_K1 + 1);
1258
+ const denominator = termFreq + BM25_K1 * (1 - BM25_B + BM25_B * (docLength / avgDocLength));
1259
+ score += termIDF * (numerator / denominator);
1260
+ }
1261
+ const nameLower = tool2.name.toLowerCase();
1262
+ for (const term of queryTerms) {
1263
+ if (nameLower === term) score += 3;
1264
+ else if (nameLower.includes(term)) score += 1.5;
1265
+ }
1266
+ if (activeProfile && tool2.profiles?.includes(activeProfile)) score += 0.75;
1267
+ return score;
1268
+ }
1269
+ function selectTools(params) {
1270
+ const config = params.config;
1271
+ const available = filterToolsByProfile({
1272
+ tools: params.tools,
1273
+ config,
1274
+ activeProfile: params.activeProfile
1275
+ });
1276
+ if (!config) return available;
1277
+ const activeProfile = params.activeProfile ?? config.defaultProfile;
1278
+ const forceIncludeNames = new Set(params.forceIncludeNames ?? []);
1279
+ let filtered = available.filter(
1280
+ (tool2) => !tool2.deferLoading || forceIncludeNames.has(tool2.name)
1281
+ );
1282
+ if (filtered.length === 0) return filtered;
1283
+ const maxTools = Math.max(1, Math.min(config.maxEagerTools, filtered.length));
1284
+ const queryTokens = unique(tokenize(buildToolQuery(params.messages)));
1285
+ const ranked = [...filtered].sort((a, b) => {
1286
+ const diff = scoreTool(b, queryTokens, activeProfile) - scoreTool(a, queryTokens, activeProfile);
1287
+ return diff !== 0 ? diff : a.name.localeCompare(b.name);
1288
+ });
1289
+ if (forceIncludeNames.size === 0) return ranked.slice(0, maxTools);
1290
+ const forced = ranked.filter((t) => forceIncludeNames.has(t.name));
1291
+ const others = ranked.filter((t) => !forceIncludeNames.has(t.name));
1292
+ const remaining = Math.max(0, maxTools - forced.length);
1293
+ return [...forced, ...others.slice(0, remaining)];
1294
+ }
1295
+ function searchTools(params) {
1296
+ const queryTerms = unique(tokenize(params.query));
1297
+ if (queryTerms.length === 0) return [];
1298
+ const candidates = filterToolsByProfile({
1299
+ tools: params.tools,
1300
+ config: params.config,
1301
+ activeProfile: params.activeProfile
1302
+ }).filter((tool2) => {
1303
+ if ((params.excludeNames ?? []).includes(tool2.name)) return false;
1304
+ if (params.includeSelected) return true;
1305
+ return tool2.deferLoading === true;
1306
+ });
1307
+ if (candidates.length === 0) return [];
1308
+ const docs = candidates.map((tool2) => tokenize(buildSearchText(tool2)));
1309
+ const avgDocLength = docs.reduce((sum, tokens) => sum + Math.max(1, tokens.length), 0) / docs.length;
1310
+ const idf = /* @__PURE__ */ new Map();
1311
+ for (const term of queryTerms) {
1312
+ const docFreq = docs.reduce(
1313
+ (count, tokens) => count + (tokens.includes(term) ? 1 : 0),
1314
+ 0
1315
+ );
1316
+ idf.set(
1317
+ term,
1318
+ Math.log((docs.length - docFreq + 0.5) / (docFreq + 0.5) + 1)
1319
+ );
1320
+ }
1321
+ const limit = Math.max(1, params.limit ?? params.config?.maxResults ?? 8);
1322
+ const activeProfile = params.activeProfile ?? params.config?.defaultProfile;
1323
+ return candidates.map((tool2) => ({
1324
+ tool: tool2,
1325
+ score: calculateBM25Score(
1326
+ tool2,
1327
+ queryTerms,
1328
+ idf,
1329
+ avgDocLength,
1330
+ activeProfile
1331
+ )
1332
+ })).filter((entry) => entry.score >= MIN_SCORE).sort((a, b) => {
1333
+ const diff = b.score - a.score;
1334
+ return diff !== 0 ? diff : a.tool.name.localeCompare(b.tool.name);
1335
+ }).slice(0, limit).map(({ tool: tool2, score }) => ({
1336
+ name: tool2.name,
1337
+ description: tool2.description,
1338
+ location: tool2.location,
1339
+ category: tool2.category,
1340
+ group: tool2.group,
1341
+ profiles: tool2.profiles,
1342
+ searchKeywords: tool2.searchKeywords,
1343
+ score: Number(score.toFixed(4))
1344
+ }));
1345
+ }
1346
+ function normalizeModelName(modelName) {
1347
+ return (modelName ?? "").trim().toLowerCase();
1348
+ }
1349
+ function supportsAnthropicNativeToolSearch(modelName) {
1350
+ const model = normalizeModelName(modelName);
1351
+ if (!model || model.includes("haiku")) return false;
1352
+ return /(?:^|[-_ ])(?:sonnet|opus)[-_ ]?4(?:$|[-_. ])/.test(model) || /claude[-_ ](?:sonnet|opus)[-_ ]?4/.test(model) || /claude[-_ ]?4[-_ ](?:sonnet|opus)/.test(model);
1353
+ }
1354
+ function supportsOpenAINativeToolSearch(modelName) {
1355
+ const model = normalizeModelName(modelName);
1356
+ if (!model) return false;
1357
+ const match = model.match(/^gpt-5(?:[._-](\d+))?(?:$|[._-])/);
1358
+ if (!match) return false;
1359
+ const minorVersion = match[1] ? Number.parseInt(match[1], 10) : Number.NaN;
1360
+ if (!Number.isFinite(minorVersion)) return false;
1361
+ return minorVersion >= 4;
1362
+ }
1363
+ function resolveNativeToolSearch(params) {
1364
+ if (!params.config) return null;
1365
+ if (params.providerName === "anthropic" && supportsAnthropicNativeToolSearch(params.modelName)) {
1366
+ return { provider: "anthropic", variant: "bm25" };
1367
+ }
1368
+ if (params.providerName === "openai" && supportsOpenAINativeToolSearch(params.modelName)) {
1369
+ return { provider: "openai", useResponsesApi: true };
1370
+ }
1371
+ return null;
1372
+ }
1373
+ function shouldExposeToolSearch(params) {
1374
+ if (!params.config) return false;
1375
+ const deferredCount = params.tools.filter((t) => t.deferLoading).length;
1376
+ if (deferredCount === 0) return false;
1377
+ return params.tools.length >= params.config.exposeWhenExceeds;
1378
+ }
1379
+ function buildProviderToolOptions(params) {
1380
+ const { toolChoice, parallelCalls } = params.config ?? {};
1381
+ const resolvedNativeSearch = resolveNativeToolSearch({
1382
+ providerName: params.providerName,
1383
+ modelName: params.modelName,
1384
+ config: params.config
1385
+ });
1386
+ if (params.providerName === "openai") {
1387
+ if (toolChoice === void 0 && parallelCalls === void 0 && !resolvedNativeSearch) {
1388
+ return void 0;
1389
+ }
1390
+ let oaiToolChoice;
1391
+ if (toolChoice === "required") oaiToolChoice = "required";
1392
+ else if (toolChoice === "auto") oaiToolChoice = "auto";
1393
+ return {
1394
+ openai: {
1395
+ toolChoice: oaiToolChoice,
1396
+ parallelToolCalls: parallelCalls,
1397
+ nativeToolSearch: resolvedNativeSearch?.provider === "openai" ? {
1398
+ enabled: true,
1399
+ useResponsesApi: resolvedNativeSearch.useResponsesApi
1400
+ } : void 0
1401
+ }
1402
+ };
1403
+ }
1404
+ if (params.providerName === "anthropic") {
1405
+ if (toolChoice === void 0 && parallelCalls === void 0 && !resolvedNativeSearch) {
1406
+ return void 0;
1407
+ }
1408
+ let anthropicToolChoice;
1409
+ if (toolChoice === "required") anthropicToolChoice = "any";
1410
+ else if (toolChoice === "auto") anthropicToolChoice = "auto";
1411
+ return {
1412
+ anthropic: {
1413
+ toolChoice: anthropicToolChoice,
1414
+ // parallelCalls: false → disableParallelToolUse: true
1415
+ disableParallelToolUse: parallelCalls === false ? true : void 0,
1416
+ nativeToolSearch: resolvedNativeSearch?.provider === "anthropic" ? { enabled: true, variant: resolvedNativeSearch.variant ?? "bm25" } : void 0
1417
+ }
1418
+ };
1419
+ }
1420
+ return void 0;
1421
+ }
1422
+
1150
1423
  // src/server/runtime.ts
1151
1424
  function buildToolResultForAI(tool2, result, args) {
1152
1425
  const typedResult = result;
@@ -1271,7 +1544,8 @@ var Runtime = class {
1271
1544
  systemPrompt: request.systemPrompt || this.config.systemPrompt,
1272
1545
  config: request.config,
1273
1546
  signal,
1274
- webSearch: this.getWebSearchConfig()
1547
+ webSearch: this.getWebSearchConfig(),
1548
+ debug: this.config.debug
1275
1549
  };
1276
1550
  const stream = this.adapter.stream(completionRequest);
1277
1551
  for await (const event of stream) {
@@ -1328,11 +1602,18 @@ var Runtime = class {
1328
1602
  try {
1329
1603
  const body = await request.json();
1330
1604
  if (this.config.debug) {
1331
- console.log("[Copilot SDK] Request:", JSON.stringify(body, null, 2));
1605
+ console.log("[Copilot SDK] Request:", {
1606
+ messageCount: body.messages?.length ?? 0,
1607
+ toolCount: body.tools?.length ?? 0,
1608
+ hasSystemPrompt: Boolean(body.systemPrompt),
1609
+ threadId: body.threadId,
1610
+ streaming: body.streaming !== false,
1611
+ toolProfile: body.toolProfile
1612
+ });
1332
1613
  }
1333
1614
  const signal = request.signal;
1334
1615
  const hasTools = body.tools && body.tools.length > 0 || this.tools.size > 0;
1335
- const useAgentLoop = hasTools || this.config.agentLoop?.enabled;
1616
+ const useAgentLoop = hasTools;
1336
1617
  if (body.streaming === false) {
1337
1618
  return this.handleNonStreamingRequest(
1338
1619
  body,
@@ -1588,6 +1869,170 @@ var Runtime = class {
1588
1869
  }
1589
1870
  return void 0;
1590
1871
  }
1872
+ /**
1873
+ * Resolve effective tool selection config for a request.
1874
+ */
1875
+ resolveEffectiveToolSelectionConfig(request) {
1876
+ const toolSearch = "toolSearch" in this.config ? this.config.toolSearch : void 0;
1877
+ const hasDeferredServerTool = [...this.tools.values()].some(
1878
+ (t) => t.deferLoading
1879
+ );
1880
+ const hasDeferredInRequest = request.tools?.some((t) => t.deferLoading);
1881
+ if (!hasDeferredServerTool && !hasDeferredInRequest && !toolSearch) {
1882
+ return void 0;
1883
+ }
1884
+ return {
1885
+ maxEagerTools: toolSearch?.maxEagerTools ?? 20,
1886
+ maxResults: toolSearch?.maxResults ?? 8,
1887
+ exposeWhenExceeds: toolSearch?.exposeWhenExceeds ?? 8,
1888
+ toolChoice: toolSearch?.toolChoice,
1889
+ parallelCalls: toolSearch?.parallelCalls,
1890
+ defaultProfile: toolSearch?.defaultProfile,
1891
+ profiles: toolSearch?.profiles,
1892
+ includeUnprofiled: toolSearch?.includeUnprofiled
1893
+ };
1894
+ }
1895
+ collectToolsForRequest(request) {
1896
+ const allTools = [...this.tools.values()];
1897
+ if (request.tools) {
1898
+ for (const tool2 of request.tools) {
1899
+ allTools.push({
1900
+ name: tool2.name,
1901
+ description: tool2.description,
1902
+ location: "client",
1903
+ category: tool2.category,
1904
+ group: tool2.group,
1905
+ deferLoading: tool2.deferLoading,
1906
+ profiles: tool2.profiles,
1907
+ searchKeywords: tool2.searchKeywords,
1908
+ inputSchema: tool2.inputSchema
1909
+ });
1910
+ }
1911
+ }
1912
+ return allTools;
1913
+ }
1914
+ selectToolsForRequest(request, allTools, toolSearchState) {
1915
+ return selectTools({
1916
+ tools: allTools,
1917
+ messages: request.messages,
1918
+ config: this.resolveEffectiveToolSelectionConfig(request),
1919
+ activeProfile: request.toolProfile,
1920
+ forceIncludeNames: toolSearchState?.loadedToolNames
1921
+ });
1922
+ }
1923
+ resolveNativeToolSearchForRequest(request) {
1924
+ return resolveNativeToolSearch({
1925
+ providerName: this.adapter.provider,
1926
+ modelName: this.getModel(),
1927
+ config: this.resolveEffectiveToolSelectionConfig(request)
1928
+ });
1929
+ }
1930
+ buildNativeToolCatalogForRequest(request, allTools) {
1931
+ return filterToolsByProfile({
1932
+ tools: allTools,
1933
+ config: this.resolveEffectiveToolSelectionConfig(request),
1934
+ activeProfile: request.toolProfile
1935
+ });
1936
+ }
1937
+ buildProviderToolOptionsForRequest(selectedTools, request) {
1938
+ return buildProviderToolOptions({
1939
+ providerName: this.adapter.provider,
1940
+ modelName: this.getModel(),
1941
+ config: this.resolveEffectiveToolSelectionConfig(request),
1942
+ metaToolName: this.getToolSearchMetaToolName()
1943
+ });
1944
+ }
1945
+ getToolSearchMetaToolName() {
1946
+ const toolSearch = "toolSearch" in this.config ? this.config.toolSearch : void 0;
1947
+ return toolSearch?.name ?? "search_tools";
1948
+ }
1949
+ createToolSearchTool(request, allTools, selectedTools) {
1950
+ if (!shouldExposeToolSearch({
1951
+ tools: allTools,
1952
+ config: this.resolveEffectiveToolSelectionConfig(request)
1953
+ })) {
1954
+ return null;
1955
+ }
1956
+ const toolName = this.getToolSearchMetaToolName();
1957
+ const excludedNames = selectedTools.map((tool2) => tool2.name);
1958
+ return {
1959
+ name: toolName,
1960
+ description: "toolSearch" in this.config && this.config.toolSearch?.description || "Search available deferred tools and load the most relevant ones for the next step when the right tool is not currently exposed.",
1961
+ location: "server",
1962
+ hidden: true,
1963
+ inputSchema: {
1964
+ type: "object",
1965
+ properties: {
1966
+ query: {
1967
+ type: "string",
1968
+ description: "Describe the tool capability you need to find."
1969
+ },
1970
+ limit: {
1971
+ type: "number",
1972
+ description: "Maximum number of matching tools to load."
1973
+ }
1974
+ },
1975
+ required: ["query"]
1976
+ },
1977
+ handler: async (params) => {
1978
+ const args = params;
1979
+ const results = searchTools({
1980
+ tools: allTools,
1981
+ query: args.query,
1982
+ config: this.resolveEffectiveToolSelectionConfig(request),
1983
+ activeProfile: request.toolProfile,
1984
+ limit: args.limit,
1985
+ excludeNames: excludedNames
1986
+ });
1987
+ if (this.config.debug) {
1988
+ console.log("[Copilot SDK] search_tools result:", {
1989
+ query: args.query,
1990
+ activeProfile: request.toolProfile,
1991
+ selectedToolCount: selectedTools.length,
1992
+ catalogCount: allTools.length,
1993
+ loadedTools: results.map((result) => result.name),
1994
+ results: results.map((result) => ({
1995
+ name: result.name,
1996
+ location: result.location,
1997
+ category: result.category,
1998
+ group: result.group,
1999
+ score: result.score
2000
+ }))
2001
+ });
2002
+ }
2003
+ return {
2004
+ success: true,
2005
+ query: args.query,
2006
+ loadedTools: results.map((result) => result.name),
2007
+ results
2008
+ };
2009
+ }
2010
+ };
2011
+ }
2012
+ extendLoadedToolNames(current, results) {
2013
+ const loaded = new Set(current?.loadedToolNames ?? []);
2014
+ const searchToolName = this.getToolSearchMetaToolName();
2015
+ for (const result of results) {
2016
+ if (result.name !== searchToolName) {
2017
+ continue;
2018
+ }
2019
+ const typedResult = result.result;
2020
+ if (!Array.isArray(typedResult?.loadedTools)) {
2021
+ continue;
2022
+ }
2023
+ for (const toolName of typedResult.loadedTools) {
2024
+ if (typeof toolName === "string" && toolName) {
2025
+ loaded.add(toolName);
2026
+ }
2027
+ }
2028
+ }
2029
+ if (loaded.size === 0) {
2030
+ return current;
2031
+ }
2032
+ return {
2033
+ loadedToolNames: [...loaded]
2034
+ };
2035
+ }
1591
2036
  /**
1592
2037
  * Process a chat request with tool support (Vercel AI SDK pattern)
1593
2038
  *
@@ -1599,8 +2044,8 @@ var Runtime = class {
1599
2044
  * 5. Loop continues until no more tool calls or max iterations reached
1600
2045
  * 6. Returns all new messages in the done event for client to append
1601
2046
  */
1602
- async *processChatWithLoop(request, signal, _accumulatedMessages, _isRecursive, _httpRequest) {
1603
- const debug = this.config.debug || this.config.agentLoop?.debug;
2047
+ async *processChatWithLoop(request, signal, _accumulatedMessages, _isRecursive, _httpRequest, _toolSearchState) {
2048
+ const debug = this.config.debug;
1604
2049
  if (request.streaming === false) {
1605
2050
  if (debug) {
1606
2051
  console.log("[Copilot SDK] Using non-streaming mode");
@@ -1610,29 +2055,41 @@ var Runtime = class {
1610
2055
  signal,
1611
2056
  _accumulatedMessages,
1612
2057
  _isRecursive,
1613
- _httpRequest
2058
+ _httpRequest,
2059
+ _toolSearchState
1614
2060
  )) {
1615
2061
  yield event;
1616
2062
  }
1617
2063
  return;
1618
2064
  }
1619
2065
  const newMessages = _accumulatedMessages || [];
1620
- this.config.agentLoop?.maxIterations || 20;
1621
- const allTools = [...this.tools.values()];
1622
- if (request.tools) {
1623
- for (const tool2 of request.tools) {
1624
- allTools.push({
1625
- name: tool2.name,
1626
- description: tool2.description,
1627
- location: "client",
1628
- inputSchema: tool2.inputSchema
1629
- });
1630
- }
1631
- }
2066
+ this.config.maxIterations ?? 20;
2067
+ const allTools = this.collectToolsForRequest(request);
2068
+ const nativeToolSearch = this.resolveNativeToolSearchForRequest(request);
2069
+ const nativeToolCatalog = nativeToolSearch ? this.buildNativeToolCatalogForRequest(request, allTools) : null;
2070
+ const selectedTools = nativeToolCatalog ?? this.selectToolsForRequest(request, allTools, _toolSearchState);
2071
+ const toolSearchTool = nativeToolSearch ? null : this.createToolSearchTool(request, allTools, selectedTools);
2072
+ const effectiveSelectedTools = nativeToolCatalog ? nativeToolCatalog : toolSearchTool ? [...selectedTools, toolSearchTool] : selectedTools;
2073
+ const providerToolOptions = this.buildProviderToolOptionsForRequest(
2074
+ effectiveSelectedTools,
2075
+ request
2076
+ );
2077
+ const selectedToolMap = new Map(
2078
+ effectiveSelectedTools.map((tool2) => [tool2.name, tool2])
2079
+ );
1632
2080
  if (debug) {
1633
2081
  console.log(
1634
2082
  `[Copilot SDK] Processing chat with ${allTools.length} tools`
1635
2083
  );
2084
+ if (effectiveSelectedTools.length !== allTools.length) {
2085
+ console.log(
2086
+ `[Copilot SDK] Tool selection active: ${effectiveSelectedTools.length}/${allTools.length} tools`,
2087
+ {
2088
+ activeProfile: request.toolProfile,
2089
+ nativeSearch: nativeToolSearch?.provider ?? null
2090
+ }
2091
+ );
2092
+ }
1636
2093
  for (let i = 0; i < request.messages.length; i++) {
1637
2094
  const msg = request.messages[i];
1638
2095
  const hasAttachments = msg.attachments && msg.attachments.length > 0;
@@ -1657,11 +2114,14 @@ var Runtime = class {
1657
2114
  messages: [],
1658
2115
  // Not used when rawMessages is provided
1659
2116
  rawMessages: request.messages,
1660
- actions: this.convertToolsToActions(allTools),
2117
+ actions: nativeToolSearch ? void 0 : this.convertToolsToActions(effectiveSelectedTools),
2118
+ toolDefinitions: nativeToolSearch ? effectiveSelectedTools : void 0,
1661
2119
  systemPrompt,
1662
2120
  config: request.config,
1663
2121
  signal,
1664
- webSearch: this.getWebSearchConfig()
2122
+ webSearch: this.getWebSearchConfig(),
2123
+ providerToolOptions,
2124
+ debug
1665
2125
  };
1666
2126
  const stream = this.adapter.stream(completionRequest);
1667
2127
  for await (const event of stream) {
@@ -1738,7 +2198,7 @@ var Runtime = class {
1738
2198
  const serverToolCalls = [];
1739
2199
  const clientToolCalls = [];
1740
2200
  for (const tc of toolCalls) {
1741
- const tool2 = allTools.find((t) => t.name === tc.name);
2201
+ const tool2 = selectedToolMap.get(tc.name);
1742
2202
  if (tool2?.location === "server" && tool2.handler) {
1743
2203
  serverToolCalls.push(tc);
1744
2204
  } else {
@@ -1748,7 +2208,7 @@ var Runtime = class {
1748
2208
  const serverToolResults = [];
1749
2209
  const toolContextData = "toolContext" in this.config ? this.config.toolContext : void 0;
1750
2210
  for (const tc of serverToolCalls) {
1751
- const tool2 = allTools.find((t) => t.name === tc.name);
2211
+ const tool2 = selectedToolMap.get(tc.name);
1752
2212
  if (tool2?.handler) {
1753
2213
  if (debug) {
1754
2214
  console.log(`[Copilot SDK] Executing server-side tool: ${tc.name}`);
@@ -1772,6 +2232,7 @@ var Runtime = class {
1772
2232
  yield {
1773
2233
  type: "action:end",
1774
2234
  id: tc.id,
2235
+ name: tc.name,
1775
2236
  result
1776
2237
  };
1777
2238
  } catch (error) {
@@ -1789,6 +2250,7 @@ var Runtime = class {
1789
2250
  yield {
1790
2251
  type: "action:end",
1791
2252
  id: tc.id,
2253
+ name: tc.name,
1792
2254
  error: error instanceof Error ? error.message : "Tool execution failed"
1793
2255
  };
1794
2256
  }
@@ -1834,6 +2296,13 @@ var Runtime = class {
1834
2296
  ...request,
1835
2297
  messages: messagesWithResults
1836
2298
  };
2299
+ const nextToolSearchState = this.extendLoadedToolNames(
2300
+ _toolSearchState,
2301
+ serverToolResults.map((result) => ({
2302
+ name: result.name,
2303
+ result: result.result
2304
+ }))
2305
+ );
1837
2306
  yield { type: "message:end" };
1838
2307
  for await (const event of this.processChatWithLoop(
1839
2308
  nextRequest,
@@ -1841,7 +2310,8 @@ var Runtime = class {
1841
2310
  newMessages,
1842
2311
  true,
1843
2312
  // Mark as recursive
1844
- _httpRequest
2313
+ _httpRequest,
2314
+ nextToolSearchState
1845
2315
  )) {
1846
2316
  yield event;
1847
2317
  }
@@ -1900,22 +2370,14 @@ var Runtime = class {
1900
2370
  * - Easier debugging (full response at once)
1901
2371
  * - More predictable retry behavior
1902
2372
  */
1903
- async *processChatWithLoopNonStreaming(request, signal, _accumulatedMessages, _isRecursive, _httpRequest) {
2373
+ async *processChatWithLoopNonStreaming(request, signal, _accumulatedMessages, _isRecursive, _httpRequest, _toolSearchState) {
1904
2374
  const newMessages = _accumulatedMessages || [];
1905
- const debug = this.config.debug || this.config.agentLoop?.debug;
1906
- const maxIterations = this.config.agentLoop?.maxIterations || 20;
2375
+ const debug = this.config.debug;
2376
+ const maxIterations = this.config.maxIterations ?? 20;
1907
2377
  let accumulatedUsage = { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 };
1908
- const allTools = [...this.tools.values()];
1909
- if (request.tools) {
1910
- for (const tool2 of request.tools) {
1911
- allTools.push({
1912
- name: tool2.name,
1913
- description: tool2.description,
1914
- location: "client",
1915
- inputSchema: tool2.inputSchema
1916
- });
1917
- }
1918
- }
2378
+ const allTools = this.collectToolsForRequest(request);
2379
+ const nativeToolSearch = this.resolveNativeToolSearchForRequest(request);
2380
+ let toolSearchState = _toolSearchState;
1919
2381
  const systemPrompt = request.systemPrompt || this.config.systemPrompt || "";
1920
2382
  let iteration = 0;
1921
2383
  let conversationMessages = request.messages;
@@ -1944,20 +2406,35 @@ var Runtime = class {
1944
2406
  signal,
1945
2407
  _accumulatedMessages,
1946
2408
  _isRecursive,
1947
- _httpRequest
2409
+ _httpRequest,
2410
+ toolSearchState
1948
2411
  )) {
1949
2412
  yield event;
1950
2413
  }
1951
2414
  return;
1952
2415
  }
2416
+ const nativeToolCatalog = nativeToolSearch ? this.buildNativeToolCatalogForRequest(request, allTools) : null;
2417
+ const selectedTools = nativeToolCatalog ?? this.selectToolsForRequest(request, allTools, toolSearchState);
2418
+ const toolSearchTool = nativeToolSearch ? null : this.createToolSearchTool(request, allTools, selectedTools);
2419
+ const effectiveSelectedTools = nativeToolCatalog ? nativeToolCatalog : toolSearchTool ? [...selectedTools, toolSearchTool] : selectedTools;
2420
+ const providerToolOptions = this.buildProviderToolOptionsForRequest(
2421
+ effectiveSelectedTools,
2422
+ request
2423
+ );
2424
+ const selectedToolMap = new Map(
2425
+ effectiveSelectedTools.map((tool2) => [tool2.name, tool2])
2426
+ );
1953
2427
  const completionRequest = {
1954
2428
  messages: [],
1955
2429
  rawMessages: conversationMessages,
1956
- actions: this.convertToolsToActions(allTools),
2430
+ actions: nativeToolSearch ? void 0 : this.convertToolsToActions(effectiveSelectedTools),
2431
+ toolDefinitions: nativeToolSearch ? effectiveSelectedTools : void 0,
1957
2432
  systemPrompt,
1958
2433
  config: request.config,
1959
2434
  signal,
1960
- webSearch: this.getWebSearchConfig()
2435
+ webSearch: this.getWebSearchConfig(),
2436
+ providerToolOptions,
2437
+ debug
1961
2438
  };
1962
2439
  try {
1963
2440
  const result = await this.adapter.complete(completionRequest);
@@ -1983,7 +2460,7 @@ var Runtime = class {
1983
2460
  const serverToolCalls = [];
1984
2461
  const clientToolCalls = [];
1985
2462
  for (const tc of result.toolCalls) {
1986
- const tool2 = allTools.find((t) => t.name === tc.name);
2463
+ const tool2 = selectedToolMap.get(tc.name);
1987
2464
  if (tool2?.location === "server" && tool2.handler) {
1988
2465
  serverToolCalls.push(tc);
1989
2466
  } else {
@@ -1995,7 +2472,7 @@ var Runtime = class {
1995
2472
  }
1996
2473
  }
1997
2474
  for (const tc of result.toolCalls) {
1998
- const tool2 = allTools.find((t) => t.name === tc.name);
2475
+ const tool2 = selectedToolMap.get(tc.name);
1999
2476
  yield {
2000
2477
  type: "action:start",
2001
2478
  id: tc.id,
@@ -2011,7 +2488,7 @@ var Runtime = class {
2011
2488
  const serverToolResults = [];
2012
2489
  const toolContextData = "toolContext" in this.config ? this.config.toolContext : void 0;
2013
2490
  for (const tc of serverToolCalls) {
2014
- const tool2 = allTools.find((t) => t.name === tc.name);
2491
+ const tool2 = selectedToolMap.get(tc.name);
2015
2492
  if (tool2?.handler) {
2016
2493
  if (debug) {
2017
2494
  console.log(`[Copilot SDK] Executing tool: ${tc.name}`);
@@ -2035,6 +2512,7 @@ var Runtime = class {
2035
2512
  yield {
2036
2513
  type: "action:end",
2037
2514
  id: tc.id,
2515
+ name: tc.name,
2038
2516
  result: toolResult
2039
2517
  };
2040
2518
  } catch (error) {
@@ -2052,6 +2530,7 @@ var Runtime = class {
2052
2530
  yield {
2053
2531
  type: "action:end",
2054
2532
  id: tc.id,
2533
+ name: tc.name,
2055
2534
  error: error instanceof Error ? error.message : "Tool execution failed"
2056
2535
  };
2057
2536
  }
@@ -2090,6 +2569,13 @@ var Runtime = class {
2090
2569
  assistantWithToolCalls,
2091
2570
  ...toolResultMessages
2092
2571
  ];
2572
+ toolSearchState = this.extendLoadedToolNames(
2573
+ toolSearchState,
2574
+ serverToolResults.map((toolResult) => ({
2575
+ name: toolResult.name,
2576
+ result: toolResult.result
2577
+ }))
2578
+ );
2093
2579
  continue;
2094
2580
  }
2095
2581
  if (clientToolCalls.length > 0) {
@@ -2552,7 +3038,11 @@ function transformTools(tools) {
2552
3038
  function: {
2553
3039
  name: tool2.name,
2554
3040
  description: tool2.description,
2555
- parameters: tool2.inputSchema
3041
+ parameters: tool2.inputSchema ? {
3042
+ type: "object",
3043
+ properties: tool2.inputSchema.properties ?? {},
3044
+ required: tool2.inputSchema.required
3045
+ } : { type: "object", properties: {} }
2556
3046
  }
2557
3047
  }));
2558
3048
  }
@@ -2641,7 +3131,11 @@ function transformTools2(tools) {
2641
3131
  return tools.map((tool2) => ({
2642
3132
  name: tool2.name,
2643
3133
  description: tool2.description,
2644
- input_schema: tool2.inputSchema
3134
+ input_schema: tool2.inputSchema ? {
3135
+ type: "object",
3136
+ properties: tool2.inputSchema.properties ?? {},
3137
+ required: tool2.inputSchema.required
3138
+ } : { type: "object", properties: {} }
2645
3139
  }));
2646
3140
  }
2647
3141
  function parseToolCalls2(response) {
@@ -2722,7 +3216,11 @@ function transformTools3(tools) {
2722
3216
  functionDeclarations: tools.map((tool2) => ({
2723
3217
  name: tool2.name,
2724
3218
  description: tool2.description,
2725
- parameters: tool2.inputSchema
3219
+ parameters: tool2.inputSchema ? {
3220
+ type: "object",
3221
+ properties: tool2.inputSchema.properties ?? {},
3222
+ required: tool2.inputSchema.required
3223
+ } : { type: "object", properties: {} }
2726
3224
  }))
2727
3225
  }
2728
3226
  ];
@@ -2871,29 +3369,34 @@ async function* runAgentLoop(options) {
2871
3369
  systemPrompt,
2872
3370
  provider,
2873
3371
  signal,
2874
- config,
3372
+ maxIterations: optMaxIterations,
3373
+ debug: optDebug,
3374
+ toolSelectionConfig,
3375
+ toolProfile,
2875
3376
  callLLM,
2876
3377
  executeServerTool,
2877
3378
  waitForClientToolResult
2878
3379
  } = options;
2879
- const maxIterations = config?.maxIterations ?? DEFAULT_MAX_ITERATIONS;
2880
- const debug = config?.debug ?? false;
3380
+ const maxIterations = optMaxIterations ?? DEFAULT_MAX_ITERATIONS;
3381
+ const debug = optDebug ?? false;
2881
3382
  const formatter = getFormatter(provider.name);
3383
+ const toolSearchMetaToolName = "search_tools";
2882
3384
  const serverTools = tools.filter((t) => t.location === "server");
2883
3385
  const clientTools = tools.filter((t) => t.location === "client");
2884
3386
  const allTools = [...serverTools, ...clientTools];
2885
- const providerTools = formatter.transformTools(allTools);
2886
3387
  const conversation = buildConversation(
2887
3388
  messages,
2888
3389
  systemPrompt
2889
3390
  );
2890
3391
  let iteration = 0;
3392
+ let loadedToolNames = /* @__PURE__ */ new Set();
2891
3393
  if (debug) {
2892
3394
  console.log("[AgentLoop] Starting with", {
2893
3395
  messageCount: messages.length,
2894
- toolCount: allTools.length,
3396
+ availableToolCount: allTools.length,
2895
3397
  serverToolCount: serverTools.length,
2896
3398
  clientToolCount: clientTools.length,
3399
+ activeProfile: toolProfile ?? toolSelectionConfig?.defaultProfile,
2897
3400
  maxIterations
2898
3401
  });
2899
3402
  }
@@ -2912,11 +3415,71 @@ async function* runAgentLoop(options) {
2912
3415
  iteration,
2913
3416
  maxIterations
2914
3417
  };
3418
+ const selectedTools = selectTools({
3419
+ tools: allTools,
3420
+ messages,
3421
+ config: toolSelectionConfig,
3422
+ activeProfile: toolProfile,
3423
+ forceIncludeNames: [...loadedToolNames]
3424
+ });
3425
+ const toolSearchTool = shouldExposeToolSearch({
3426
+ tools: allTools,
3427
+ config: toolSelectionConfig
3428
+ }) ? {
3429
+ name: toolSearchMetaToolName,
3430
+ description: "Search available deferred tools and load the most relevant ones for the next step when the required tool is not currently exposed.",
3431
+ location: "server",
3432
+ hidden: true,
3433
+ inputSchema: {
3434
+ type: "object",
3435
+ properties: {
3436
+ query: {
3437
+ type: "string",
3438
+ description: "Describe the tool capability you need to find."
3439
+ },
3440
+ limit: {
3441
+ type: "number",
3442
+ description: "Maximum number of matching tools to load."
3443
+ }
3444
+ },
3445
+ required: ["query"]
3446
+ },
3447
+ handler: async (params) => {
3448
+ const query = typeof params.query === "string" ? params.query : "";
3449
+ const limit = typeof params.limit === "number" ? params.limit : void 0;
3450
+ const results = searchTools({
3451
+ tools: allTools,
3452
+ query,
3453
+ config: toolSelectionConfig,
3454
+ activeProfile: toolProfile,
3455
+ limit,
3456
+ excludeNames: selectedTools.map((tool2) => tool2.name)
3457
+ });
3458
+ return {
3459
+ success: true,
3460
+ query,
3461
+ loadedTools: results.map((result) => result.name),
3462
+ results
3463
+ };
3464
+ }
3465
+ } : null;
3466
+ const effectiveSelectedTools = toolSearchTool ? [...selectedTools, toolSearchTool] : selectedTools;
3467
+ const providerToolOptions = buildProviderToolOptions({
3468
+ providerName: provider.name,
3469
+ config: toolSelectionConfig});
3470
+ const providerTools = formatter.transformTools(effectiveSelectedTools);
2915
3471
  if (debug) {
2916
- console.log(`[AgentLoop] Iteration ${iteration}/${maxIterations}`);
3472
+ console.log(`[AgentLoop] Iteration ${iteration}/${maxIterations}`, {
3473
+ selectedToolCount: effectiveSelectedTools.length,
3474
+ loadedDeferredTools: [...loadedToolNames]
3475
+ });
2917
3476
  }
2918
3477
  try {
2919
- const response = await callLLM(conversation, providerTools);
3478
+ const response = await callLLM(
3479
+ conversation,
3480
+ providerTools,
3481
+ providerToolOptions
3482
+ );
2920
3483
  const toolCalls = formatter.parseToolCalls(response);
2921
3484
  const textContent = formatter.extractTextContent(response);
2922
3485
  if (textContent) {
@@ -2934,7 +3497,7 @@ async function* runAgentLoop(options) {
2934
3497
  }
2935
3498
  const results = await executeToolCalls(
2936
3499
  toolCalls,
2937
- tools,
3500
+ effectiveSelectedTools,
2938
3501
  executeServerTool,
2939
3502
  waitForClientToolResult,
2940
3503
  function* (event) {
@@ -2953,6 +3516,23 @@ async function* runAgentLoop(options) {
2953
3516
  };
2954
3517
  }
2955
3518
  }
3519
+ for (const result of results) {
3520
+ const toolCall = toolCalls.find((tc) => tc.id === result.toolCallId);
3521
+ if (!toolCall || toolCall.name !== toolSearchMetaToolName) {
3522
+ continue;
3523
+ }
3524
+ try {
3525
+ const parsed = JSON.parse(result.content);
3526
+ if (Array.isArray(parsed.loadedTools)) {
3527
+ for (const toolName of parsed.loadedTools) {
3528
+ if (typeof toolName === "string" && toolName) {
3529
+ loadedToolNames.add(toolName);
3530
+ }
3531
+ }
3532
+ }
3533
+ } catch {
3534
+ }
3535
+ }
2956
3536
  const assistantMessage = formatter.buildAssistantToolMessage(
2957
3537
  toolCalls,
2958
3538
  textContent
@@ -3103,6 +3683,6 @@ async function executeToolCalls(toolCalls, tools, executeServerTool, waitForClie
3103
3683
  return results;
3104
3684
  }
3105
3685
 
3106
- export { DEFAULT_CAPABILITIES, DEFAULT_MAX_ITERATIONS, GenerateResult, Runtime, StreamResult, createEventStream, createExpressHandler, createExpressMiddleware, createHonoApp, createNextHandler, createNodeHandler, createRuntime, createSSEHeaders, createSSEResponse, createStreamResult, createTextStreamHeaders, createTextStreamResponse, formatSSEData, formatToolsForAnthropic, formatToolsForGoogle, formatToolsForOpenAI, generateMessageId, generateText, generateThreadId, generateToolCallId, pipeSSEToResponse, pipeTextToResponse, runAgentLoop, streamText, tool };
3686
+ export { DEFAULT_CAPABILITIES, DEFAULT_MAX_ITERATIONS, GenerateResult, Runtime, StreamResult, buildProviderToolOptions, createEventStream, createExpressHandler, createExpressMiddleware, createHonoApp, createNextHandler, createNodeHandler, createRuntime, createSSEHeaders, createSSEResponse, createStreamResult, createTextStreamHeaders, createTextStreamResponse, formatSSEData, formatToolsForAnthropic, formatToolsForGoogle, formatToolsForOpenAI, generateMessageId, generateText, generateThreadId, generateToolCallId, pipeSSEToResponse, pipeTextToResponse, runAgentLoop, searchTools, selectTools, shouldExposeToolSearch, streamText, tool };
3107
3687
  //# sourceMappingURL=index.mjs.map
3108
3688
  //# sourceMappingURL=index.mjs.map