blun-king-cli 9.1.594 → 9.1.596
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/blun.mjs +708 -31
- package/package.json +1 -1
- package/worker-host.mjs +672 -33
package/worker-host.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// BLUN_BUILD_INPUT_SHA256:
|
|
2
|
+
// BLUN_BUILD_INPUT_SHA256:2c4b3f451c41d328bb5eb43ffb226f0f3b0c458270217cecb6e1ffc63287e8bd
|
|
3
3
|
import { fileURLToPath as __cjsShimFileURLToPath } from 'node:url';
|
|
4
4
|
import { dirname as __cjsShimDirname } from 'node:path';
|
|
5
5
|
const __filename = __cjsShimFileURLToPath(import.meta.url);
|
|
@@ -233816,10 +233816,11 @@ var ContextMemory = class {
|
|
|
233816
233816
|
const openStepIndex = openStep === void 0 ? -1 : this._history.indexOf(openStep);
|
|
233817
233817
|
const coveredCount = openStepIndex === -1 ? this._history.length : openStepIndex + 1;
|
|
233818
233818
|
const totalUsage = event.usage.inputCacheRead + event.usage.inputCacheCreation + event.usage.inputOther + event.usage.output;
|
|
233819
|
-
if (totalUsage > 0) this._tokenCount = totalUsage;
|
|
233819
|
+
if (totalUsage > 0 && event.contextCoverage !== "partial") this._tokenCount = totalUsage;
|
|
233820
233820
|
else {
|
|
233821
233821
|
const previousCoveredCount = this.tokenCountCoveredMessageCount;
|
|
233822
233822
|
this._tokenCount += estimateTokensForMessages(this._history.slice(previousCoveredCount, coveredCount));
|
|
233823
|
+
this._tokenCount = Math.max(this._tokenCount, totalUsage);
|
|
233823
233824
|
}
|
|
233824
233825
|
this.tokenCountCoveredMessageCount = coveredCount;
|
|
233825
233826
|
}
|
|
@@ -237788,6 +237789,518 @@ var AutoModeAskUserQuestionDenyPermissionPolicy = class {
|
|
|
237788
237789
|
};
|
|
237789
237790
|
//#endregion
|
|
237790
237791
|
//#region ../../packages/agent-core/src/agent/permission/policies/default-tool-approve.ts
|
|
237792
|
+
var import_turn_tool_performance_policy = (/* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
237793
|
+
const TOOL_SCHEMA_BUDGET_RATIO = .25;
|
|
237794
|
+
const TOOL_SCHEMA_MAX_TOKENS = 64e3;
|
|
237795
|
+
const DEFERRED_TOOL_LOADER_NAME = "ToolSearch";
|
|
237796
|
+
const MAX_PERSISTENT_DEFERRED_TOOLS = 12;
|
|
237797
|
+
const MAX_TOOL_SEARCH_QUERY_CHARS = 1e3;
|
|
237798
|
+
const MAX_AUTO_RANKED_TOOLS = 6;
|
|
237799
|
+
const deferredToolLoaders = /* @__PURE__ */ new WeakSet();
|
|
237800
|
+
const TOOL_RANK_EMBEDDED_CONTENT_RE = /<(attached_documents?|attachment_content|document_content|file_content)\b[^>]*>[\s\S]*?<\/\1>/giu;
|
|
237801
|
+
const TOOL_RANK_STOP_WORDS = new Set([
|
|
237802
|
+
"aber",
|
|
237803
|
+
"also",
|
|
237804
|
+
"and",
|
|
237805
|
+
"aus",
|
|
237806
|
+
"bitte",
|
|
237807
|
+
"can",
|
|
237808
|
+
"das",
|
|
237809
|
+
"den",
|
|
237810
|
+
"der",
|
|
237811
|
+
"des",
|
|
237812
|
+
"die",
|
|
237813
|
+
"dies",
|
|
237814
|
+
"diese",
|
|
237815
|
+
"du",
|
|
237816
|
+
"ein",
|
|
237817
|
+
"eine",
|
|
237818
|
+
"einer",
|
|
237819
|
+
"eines",
|
|
237820
|
+
"for",
|
|
237821
|
+
"fuer",
|
|
237822
|
+
"für",
|
|
237823
|
+
"haben",
|
|
237824
|
+
"ich",
|
|
237825
|
+
"ist",
|
|
237826
|
+
"kann",
|
|
237827
|
+
"kannst",
|
|
237828
|
+
"mal",
|
|
237829
|
+
"me",
|
|
237830
|
+
"mein",
|
|
237831
|
+
"meine",
|
|
237832
|
+
"mir",
|
|
237833
|
+
"mit",
|
|
237834
|
+
"of",
|
|
237835
|
+
"please",
|
|
237836
|
+
"soll",
|
|
237837
|
+
"the",
|
|
237838
|
+
"und",
|
|
237839
|
+
"uns",
|
|
237840
|
+
"von",
|
|
237841
|
+
"was",
|
|
237842
|
+
"wir",
|
|
237843
|
+
"with",
|
|
237844
|
+
"you",
|
|
237845
|
+
"zeige",
|
|
237846
|
+
"zeig",
|
|
237847
|
+
"pruefe",
|
|
237848
|
+
"prüfe",
|
|
237849
|
+
"lies",
|
|
237850
|
+
"read",
|
|
237851
|
+
"show",
|
|
237852
|
+
"get"
|
|
237853
|
+
]);
|
|
237854
|
+
const TOOL_SEARCH_INTENT_WORDS = new Set([
|
|
237855
|
+
"find",
|
|
237856
|
+
"fetch",
|
|
237857
|
+
"get",
|
|
237858
|
+
"holen",
|
|
237859
|
+
"list",
|
|
237860
|
+
"read",
|
|
237861
|
+
"search",
|
|
237862
|
+
"show",
|
|
237863
|
+
"anzeigen",
|
|
237864
|
+
"lesen",
|
|
237865
|
+
"suchen"
|
|
237866
|
+
]);
|
|
237867
|
+
const TOOL_SEARCH_RELATED_TERM_GROUPS = Object.freeze([
|
|
237868
|
+
Object.freeze([
|
|
237869
|
+
"checklist",
|
|
237870
|
+
"list",
|
|
237871
|
+
"liste",
|
|
237872
|
+
"listen"
|
|
237873
|
+
]),
|
|
237874
|
+
Object.freeze([
|
|
237875
|
+
"aufgabe",
|
|
237876
|
+
"aufgaben",
|
|
237877
|
+
"aufgabenliste",
|
|
237878
|
+
"todo",
|
|
237879
|
+
"todos"
|
|
237880
|
+
]),
|
|
237881
|
+
Object.freeze([
|
|
237882
|
+
"current",
|
|
237883
|
+
"inbox",
|
|
237884
|
+
"latest",
|
|
237885
|
+
"message",
|
|
237886
|
+
"messages",
|
|
237887
|
+
"nachricht",
|
|
237888
|
+
"nachrichten",
|
|
237889
|
+
"queue",
|
|
237890
|
+
"queued",
|
|
237891
|
+
"recent",
|
|
237892
|
+
"letzte",
|
|
237893
|
+
"letzten",
|
|
237894
|
+
"letzter",
|
|
237895
|
+
"vergangen",
|
|
237896
|
+
"update",
|
|
237897
|
+
"updates"
|
|
237898
|
+
]),
|
|
237899
|
+
Object.freeze([
|
|
237900
|
+
"chat",
|
|
237901
|
+
"conversation",
|
|
237902
|
+
"history",
|
|
237903
|
+
"log",
|
|
237904
|
+
"logs",
|
|
237905
|
+
"processed",
|
|
237906
|
+
"protokoll",
|
|
237907
|
+
"transcript",
|
|
237908
|
+
"verlauf"
|
|
237909
|
+
]),
|
|
237910
|
+
Object.freeze([
|
|
237911
|
+
"fact",
|
|
237912
|
+
"facts",
|
|
237913
|
+
"fakt",
|
|
237914
|
+
"fakten",
|
|
237915
|
+
"memory",
|
|
237916
|
+
"memories",
|
|
237917
|
+
"merk",
|
|
237918
|
+
"merken",
|
|
237919
|
+
"note",
|
|
237920
|
+
"notes",
|
|
237921
|
+
"persist",
|
|
237922
|
+
"persistent",
|
|
237923
|
+
"profile",
|
|
237924
|
+
"remember",
|
|
237925
|
+
"save",
|
|
237926
|
+
"speichern",
|
|
237927
|
+
"store"
|
|
237928
|
+
])
|
|
237929
|
+
]);
|
|
237930
|
+
const TOOL_SEARCH_SINGLE_TERM_RELATED_FALLBACKS = new Set([
|
|
237931
|
+
"fact",
|
|
237932
|
+
"facts",
|
|
237933
|
+
"fakt",
|
|
237934
|
+
"fakten",
|
|
237935
|
+
"memory",
|
|
237936
|
+
"memories",
|
|
237937
|
+
"merk",
|
|
237938
|
+
"merken",
|
|
237939
|
+
"note",
|
|
237940
|
+
"notes",
|
|
237941
|
+
"persist",
|
|
237942
|
+
"persistent",
|
|
237943
|
+
"profile",
|
|
237944
|
+
"remember",
|
|
237945
|
+
"save",
|
|
237946
|
+
"speichern",
|
|
237947
|
+
"store",
|
|
237948
|
+
"transcript"
|
|
237949
|
+
]);
|
|
237950
|
+
const CORE_TOOL_NAMES = Object.freeze([
|
|
237951
|
+
"Bash",
|
|
237952
|
+
"Read",
|
|
237953
|
+
"ReadBatch",
|
|
237954
|
+
"Edit",
|
|
237955
|
+
"Grep",
|
|
237956
|
+
"Write",
|
|
237957
|
+
"Glob",
|
|
237958
|
+
"TodoList",
|
|
237959
|
+
"mcp__plugin-telegram_telegram__reply"
|
|
237960
|
+
]);
|
|
237961
|
+
const IMAGE_MEDIA_TERM_RE = /(?:^|[^\p{L}])(?:bild(?:er)?|foto(?:s)?|grafik(?:en)?|illustration(?:en)?|logo(?:s)?|image|images|photo|photos|picture|pictures|illustration|illustrations|visual|visuals)(?=$|[^\p{L}])/u;
|
|
237962
|
+
const VIDEO_MEDIA_TERM_RE = /(?:^|[^\p{L}])(?:video(?:s)?|clip(?:s)?|film(?:e)?|animation(?:en)?|movie|movies)(?=$|[^\p{L}])/u;
|
|
237963
|
+
const ANIMATE_ACTION_RE = /(?:^|[^\p{L}])(?:animier(?:e|en|t)?|animate|animated|animating)(?=$|[^\p{L}])/u;
|
|
237964
|
+
const CREATE_ACTION_RE = /(?:^|[^\p{L}])(?:erstell(?:e|en|t)?|generier(?:e|en|t)?|erzeug(?:e|en|t)?|produzier(?:e|en|t)?|zeichn(?:e|en|et)?|mal(?:e|en|t)?|render(?:e|n|t)?|mach(?:e|en|t)?|create|creates|creating|generate|generates|generating|make|makes|making|draw|draws|drawing|paint|paints|painting|render|renders|rendering|produce|produces|producing)(?=$|[^\p{L}])/u;
|
|
237965
|
+
const REQUEST_PREFIX_RE = /^(?:bitte\s+|please\s+)?(?:erstell|generier|erzeug|produzier|zeichn|mal|render|mach|animier|create|generate|make|draw|paint|render|produce|animate)/u;
|
|
237966
|
+
const REQUEST_PHRASE_RE = /(?:^|[^\p{L}])(?:bitte|kannst du|könntest du|ich möchte|ich will|ich brauche|please|can you|could you|i want|i need)(?=$|[^\p{L}])/u;
|
|
237967
|
+
function mediaGenerationToolNamesForText(value) {
|
|
237968
|
+
const text = String(value || "").normalize("NFKC").trim().toLowerCase();
|
|
237969
|
+
const selected = /* @__PURE__ */ new Set();
|
|
237970
|
+
if (!text) return selected;
|
|
237971
|
+
if (/(?:^|[^a-z])generateimage(?=$|[^a-z])/u.test(text)) selected.add("GenerateImage");
|
|
237972
|
+
if (/(?:^|[^a-z])generatevideo(?=$|[^a-z])/u.test(text)) selected.add("GenerateVideo");
|
|
237973
|
+
if (selected.size > 0) return selected;
|
|
237974
|
+
const animate = ANIMATE_ACTION_RE.test(text);
|
|
237975
|
+
const create = CREATE_ACTION_RE.test(text);
|
|
237976
|
+
if (!(REQUEST_PREFIX_RE.test(text) || REQUEST_PHRASE_RE.test(text)) || !create && !animate) return selected;
|
|
237977
|
+
if (animate && (IMAGE_MEDIA_TERM_RE.test(text) || VIDEO_MEDIA_TERM_RE.test(text))) {
|
|
237978
|
+
selected.add("GenerateVideo");
|
|
237979
|
+
return selected;
|
|
237980
|
+
}
|
|
237981
|
+
if (IMAGE_MEDIA_TERM_RE.test(text)) selected.add("GenerateImage");
|
|
237982
|
+
if (VIDEO_MEDIA_TERM_RE.test(text)) selected.add("GenerateVideo");
|
|
237983
|
+
return selected;
|
|
237984
|
+
}
|
|
237985
|
+
function mediaToolNamesForTurnText(value) {
|
|
237986
|
+
const text = String(value || "");
|
|
237987
|
+
const selected = /* @__PURE__ */ new Set();
|
|
237988
|
+
const channelBodies = [...text.matchAll(/(?:^|\r?\n)<channel\b[^>]*>\r?\n([\s\S]*?)\r?\n<\/channel>(?=\r?\n|$)/giu)].map((match) => match[1]);
|
|
237989
|
+
const intentTexts = channelBodies.length > 0 ? channelBodies : [text];
|
|
237990
|
+
for (const intentText of intentTexts) for (const name of mediaGenerationToolNamesForText(intentText)) selected.add(name);
|
|
237991
|
+
if (/\bimage_path\s*=\s*["'][^"']+["']/iu.test(text)) {
|
|
237992
|
+
selected.add("ReadMediaFile");
|
|
237993
|
+
selected.add("UnderstandImage");
|
|
237994
|
+
}
|
|
237995
|
+
if (/\battachment_file_id\s*=\s*["'][^"']+["']/iu.test(text)) {
|
|
237996
|
+
selected.add("mcp__plugin-telegram_telegram__download_attachment");
|
|
237997
|
+
selected.add("UnderstandImage");
|
|
237998
|
+
}
|
|
237999
|
+
return selected;
|
|
238000
|
+
}
|
|
238001
|
+
function toolSchemaBudgetTokens(maxContextTokens) {
|
|
238002
|
+
const context = Number(maxContextTokens);
|
|
238003
|
+
if (!Number.isFinite(context) || context <= 0) return TOOL_SCHEMA_MAX_TOKENS;
|
|
238004
|
+
return Math.min(TOOL_SCHEMA_MAX_TOKENS, Math.floor(context * TOOL_SCHEMA_BUDGET_RATIO));
|
|
238005
|
+
}
|
|
238006
|
+
function deferredToolNames(tools) {
|
|
238007
|
+
return [...new Set((Array.isArray(tools) ? tools : []).map((tool) => String(tool?.name || "").trim()).filter(Boolean))].sort((left, right) => left.localeCompare(right));
|
|
238008
|
+
}
|
|
238009
|
+
function deferredToolCatalog(tools) {
|
|
238010
|
+
const names = deferredToolNames(tools);
|
|
238011
|
+
const leaves = names.map((name) => name.split(/__|:/).at(-1) || name);
|
|
238012
|
+
const leafCounts = /* @__PURE__ */ new Map();
|
|
238013
|
+
for (const leaf of leaves) leafCounts.set(leaf, (leafCounts.get(leaf) || 0) + 1);
|
|
238014
|
+
return names.map((name, index) => leafCounts.get(leaves[index]) === 1 ? leaves[index] : name).sort((left, right) => left.localeCompare(right));
|
|
238015
|
+
}
|
|
238016
|
+
function normalizeDeferredToolQuery(value) {
|
|
238017
|
+
const query = String(value ?? "").trim();
|
|
238018
|
+
if (query.length <= MAX_TOOL_SEARCH_QUERY_CHARS) return query;
|
|
238019
|
+
const bounded = query.slice(0, MAX_TOOL_SEARCH_QUERY_CHARS);
|
|
238020
|
+
const wordBoundary = bounded.lastIndexOf(" ");
|
|
238021
|
+
return (wordBoundary >= MAX_TOOL_SEARCH_QUERY_CHARS * .8 ? bounded.slice(0, wordBoundary) : bounded).trimEnd();
|
|
238022
|
+
}
|
|
238023
|
+
function searchDeferredTools(tools, query) {
|
|
238024
|
+
const normalized = normalizeDeferredToolQuery(query).toLowerCase();
|
|
238025
|
+
if (!normalized) return [];
|
|
238026
|
+
if (normalized.startsWith("select:")) {
|
|
238027
|
+
const selector = normalized.slice(7).trim();
|
|
238028
|
+
if (!selector) return [];
|
|
238029
|
+
const exact = tools.find((tool) => String(tool?.name || "").toLowerCase() === selector);
|
|
238030
|
+
if (exact) return [exact];
|
|
238031
|
+
return tools.filter((tool) => {
|
|
238032
|
+
return String(tool?.name || "").toLowerCase().split(/__|:/).at(-1) === selector;
|
|
238033
|
+
});
|
|
238034
|
+
}
|
|
238035
|
+
const tokens = normalized.split(/\s+/).filter(Boolean);
|
|
238036
|
+
const requiredNameTokens = tokens.filter((token) => token.startsWith("+")).map((token) => token.slice(1)).filter(Boolean);
|
|
238037
|
+
const searchTokens = tokens.filter((token) => !token.startsWith("+"));
|
|
238038
|
+
const eligibleTools = tools.filter((tool) => {
|
|
238039
|
+
const name = String(tool?.name || "").toLowerCase();
|
|
238040
|
+
return requiredNameTokens.every((token) => name.includes(token));
|
|
238041
|
+
});
|
|
238042
|
+
const firstSelector = searchTokens[0];
|
|
238043
|
+
if (firstSelector) {
|
|
238044
|
+
const exactNameMatches = eligibleTools.filter((tool) => String(tool?.name || "").toLowerCase() === firstSelector);
|
|
238045
|
+
if (exactNameMatches.length === 1) return exactNameMatches;
|
|
238046
|
+
const exactLeafMatches = eligibleTools.filter((tool) => {
|
|
238047
|
+
return String(tool?.name || "").toLowerCase().split(/__|:/).at(-1) === firstSelector;
|
|
238048
|
+
});
|
|
238049
|
+
if (exactLeafMatches.length === 1) return exactLeafMatches;
|
|
238050
|
+
}
|
|
238051
|
+
return tools.map((tool) => {
|
|
238052
|
+
const name = String(tool?.name || "").toLowerCase();
|
|
238053
|
+
const description = String(tool?.description || "").toLowerCase();
|
|
238054
|
+
if (!requiredNameTokens.every((token) => name.includes(token))) return null;
|
|
238055
|
+
if (!searchTokens.every((token) => name.includes(token) || description.includes(token))) return null;
|
|
238056
|
+
return {
|
|
238057
|
+
tool,
|
|
238058
|
+
score: searchTokens.reduce((total, token) => total + (name.includes(token) ? 5 : 1), 0) + requiredNameTokens.length * 5
|
|
238059
|
+
};
|
|
238060
|
+
}).filter(Boolean).sort((left, right) => right.score - left.score || String(left.tool.name).localeCompare(String(right.tool.name))).slice(0, 5).map((entry) => entry.tool);
|
|
238061
|
+
}
|
|
238062
|
+
function relatedSearchTerms(token) {
|
|
238063
|
+
return TOOL_SEARCH_RELATED_TERM_GROUPS.find((terms) => terms.includes(token)) || [token];
|
|
238064
|
+
}
|
|
238065
|
+
function rankingIntentTexts(value) {
|
|
238066
|
+
const text = String(value || "");
|
|
238067
|
+
const channelBodies = [...text.matchAll(/(?:^|\r?\n)<channel\b[^>]*>\r?\n([\s\S]*?)\r?\n<\/channel>(?=\r?\n|$)/giu)].map((match) => match[1]);
|
|
238068
|
+
return (channelBodies.length > 0 ? channelBodies : [text]).map((intentText) => normalizeDeferredToolQuery(intentText.replace(TOOL_RANK_EMBEDDED_CONTENT_RE, " ")));
|
|
238069
|
+
}
|
|
238070
|
+
function rankingTokens(value) {
|
|
238071
|
+
return [...new Set(String(value || "").normalize("NFKC").toLowerCase().match(/[\p{L}\p{N}]{3,}/gu) || [])].filter((token) => !TOOL_RANK_STOP_WORDS.has(token));
|
|
238072
|
+
}
|
|
238073
|
+
function toolRankingDocument(tool) {
|
|
238074
|
+
const name = String(tool?.name || "");
|
|
238075
|
+
const leaf = name.split(/__|:/).at(-1) || name;
|
|
238076
|
+
const splitToolName = (value) => String(value || "").replace(/([a-z0-9])([A-Z])/g, "$1 $2").replaceAll("_", " ");
|
|
238077
|
+
const nameTokens = rankingTokens(`${splitToolName(name)} ${splitToolName(leaf)}`);
|
|
238078
|
+
const descriptionTokens = rankingTokens(tool?.description);
|
|
238079
|
+
const parameterText = [];
|
|
238080
|
+
const properties = tool?.parameters?.properties;
|
|
238081
|
+
if (properties && typeof properties === "object") for (const [parameterName, definition] of Object.entries(properties)) parameterText.push(parameterName, definition?.description || "");
|
|
238082
|
+
const exampleText = Array.isArray(tool?.examples) ? tool.examples.map((example) => example?.prompt || "").join(" ") : "";
|
|
238083
|
+
return {
|
|
238084
|
+
name,
|
|
238085
|
+
nameTokens: new Set(nameTokens),
|
|
238086
|
+
descriptionTokens: new Set(descriptionTokens),
|
|
238087
|
+
detailTokens: new Set(rankingTokens(`${parameterText.join(" ")} ${exampleText}`))
|
|
238088
|
+
};
|
|
238089
|
+
}
|
|
238090
|
+
function tokenMatchScore(document, token) {
|
|
238091
|
+
if (document.nameTokens.has(token)) return 10;
|
|
238092
|
+
if (document.descriptionTokens.has(token)) return 5;
|
|
238093
|
+
if (document.detailTokens.has(token)) return 4;
|
|
238094
|
+
const related = relatedSearchTerms(token).filter((term) => term !== token);
|
|
238095
|
+
if (related.some((term) => document.nameTokens.has(term))) return 5;
|
|
238096
|
+
if (related.some((term) => document.descriptionTokens.has(term))) return 3;
|
|
238097
|
+
if (related.some((term) => document.detailTokens.has(term))) return 2;
|
|
238098
|
+
return 0;
|
|
238099
|
+
}
|
|
238100
|
+
/**
|
|
238101
|
+
* Select a tiny, high-confidence subset of deferred schemas for the current
|
|
238102
|
+
* request. This mirrors AnythingLLM's tool-reranker boundary without adding an
|
|
238103
|
+
* embedding runtime: King reuses the descriptions it already owns and keeps
|
|
238104
|
+
* ToolSearch available whenever the lexical evidence is weak or ambiguous.
|
|
238105
|
+
*/
|
|
238106
|
+
function rankedToolNamesForTurnText(tools, value, options = {}) {
|
|
238107
|
+
const maxTools = Math.max(0, Math.min(MAX_AUTO_RANKED_TOOLS, Number.isInteger(options.maxTools) ? options.maxTools : MAX_AUTO_RANKED_TOOLS));
|
|
238108
|
+
if (maxTools === 0) return /* @__PURE__ */ new Set();
|
|
238109
|
+
const queryTokens = [...new Set(rankingIntentTexts(value).flatMap(rankingTokens))];
|
|
238110
|
+
if (queryTokens.length === 0) return /* @__PURE__ */ new Set();
|
|
238111
|
+
const ranked = (Array.isArray(tools) ? tools : []).map((tool) => {
|
|
238112
|
+
const document = toolRankingDocument(tool);
|
|
238113
|
+
if (!document.name) return null;
|
|
238114
|
+
let score = 0;
|
|
238115
|
+
let matchedTokens = 0;
|
|
238116
|
+
let exactNameMatches = 0;
|
|
238117
|
+
let relatedNameMatches = 0;
|
|
238118
|
+
for (const token of queryTokens) {
|
|
238119
|
+
const tokenScore = tokenMatchScore(document, token);
|
|
238120
|
+
if (tokenScore === 0) continue;
|
|
238121
|
+
score += tokenScore;
|
|
238122
|
+
matchedTokens += 1;
|
|
238123
|
+
if (document.nameTokens.has(token)) exactNameMatches += 1;
|
|
238124
|
+
else if (relatedSearchTerms(token).some((term) => document.nameTokens.has(term))) relatedNameMatches += 1;
|
|
238125
|
+
}
|
|
238126
|
+
return matchedTokens >= 2 || exactNameMatches >= 1 && score >= 10 || relatedNameMatches >= 1 && score >= 5 ? {
|
|
238127
|
+
name: document.name,
|
|
238128
|
+
score,
|
|
238129
|
+
matchedTokens,
|
|
238130
|
+
exactNameMatches
|
|
238131
|
+
} : null;
|
|
238132
|
+
}).filter(Boolean).sort((left, right) => right.matchedTokens - left.matchedTokens || right.score - left.score || right.exactNameMatches - left.exactNameMatches || left.name.localeCompare(right.name));
|
|
238133
|
+
return new Set(ranked.slice(0, maxTools).map((entry) => entry.name));
|
|
238134
|
+
}
|
|
238135
|
+
function rankedSupportToolNamesForGoal(tools, goal, origin) {
|
|
238136
|
+
if (origin?.kind !== "system_trigger" || origin?.name !== "goal_continuation") return /* @__PURE__ */ new Set();
|
|
238137
|
+
if (goal?.status !== "active") return /* @__PURE__ */ new Set();
|
|
238138
|
+
const checkpoint = goal.actionCheckpoint;
|
|
238139
|
+
if (checkpoint?.phase === "wait" || checkpoint?.nextTrigger?.kind !== "immediate") return /* @__PURE__ */ new Set();
|
|
238140
|
+
const supportChoice = String(checkpoint?.problemFrame?.supportChoice ?? "").trim();
|
|
238141
|
+
if (!supportChoice.match(/^(?:tool|skill)\s*:\s*(.+)$/iu)?.[1]) return /* @__PURE__ */ new Set();
|
|
238142
|
+
return rankedToolNamesForTurnText(tools, supportChoice, { maxTools: 1 });
|
|
238143
|
+
}
|
|
238144
|
+
function searchRelatedDeferredTools(tools, query, options = {}) {
|
|
238145
|
+
const normalized = normalizeDeferredToolQuery(query).toLowerCase();
|
|
238146
|
+
if (!normalized || normalized.startsWith("select:")) return [];
|
|
238147
|
+
const tokens = normalized.split(/\s+/).filter(Boolean);
|
|
238148
|
+
const requestedNameTokens = tokens.filter((token) => token.startsWith("+")).map((token) => token.slice(1)).filter(Boolean);
|
|
238149
|
+
const relaxRequiredNameTokens = options.relaxRequiredNameTokens === true && requestedNameTokens.length > 0;
|
|
238150
|
+
const requiredNameTokens = relaxRequiredNameTokens ? [] : requestedNameTokens;
|
|
238151
|
+
const searchTokens = [...tokens.filter((token) => !token.startsWith("+")), ...relaxRequiredNameTokens ? requestedNameTokens : []].filter((token) => !TOOL_SEARCH_INTENT_WORDS.has(token));
|
|
238152
|
+
if (searchTokens.length < 2 && !TOOL_SEARCH_SINGLE_TERM_RELATED_FALLBACKS.has(searchTokens[0])) return [];
|
|
238153
|
+
const minimumMatchedTokens = searchTokens.length === 1 ? 1 : Math.max(2, Math.ceil(searchTokens.length * .75));
|
|
238154
|
+
const ranked = tools.map((tool) => {
|
|
238155
|
+
const name = String(tool?.name || "").toLowerCase();
|
|
238156
|
+
const description = String(tool?.description || "").toLowerCase();
|
|
238157
|
+
if (!requiredNameTokens.every((token) => name.includes(token))) return null;
|
|
238158
|
+
let matchedTokens = 0;
|
|
238159
|
+
let score = requiredNameTokens.length * 8;
|
|
238160
|
+
for (const token of searchTokens) {
|
|
238161
|
+
if (name.includes(token)) {
|
|
238162
|
+
matchedTokens += 1;
|
|
238163
|
+
score += 8;
|
|
238164
|
+
continue;
|
|
238165
|
+
}
|
|
238166
|
+
if (description.includes(token)) {
|
|
238167
|
+
matchedTokens += 1;
|
|
238168
|
+
score += 4;
|
|
238169
|
+
continue;
|
|
238170
|
+
}
|
|
238171
|
+
const related = relatedSearchTerms(token).filter((term) => term !== token);
|
|
238172
|
+
if (related.some((term) => name.includes(term))) {
|
|
238173
|
+
matchedTokens += 1;
|
|
238174
|
+
score += 3;
|
|
238175
|
+
} else if (related.some((term) => description.includes(term))) {
|
|
238176
|
+
matchedTokens += 1;
|
|
238177
|
+
score += 2;
|
|
238178
|
+
}
|
|
238179
|
+
}
|
|
238180
|
+
return matchedTokens >= minimumMatchedTokens ? {
|
|
238181
|
+
tool,
|
|
238182
|
+
score,
|
|
238183
|
+
matchedTokens
|
|
238184
|
+
} : null;
|
|
238185
|
+
}).filter(Boolean).sort((left, right) => right.matchedTokens - left.matchedTokens || right.score - left.score || String(left.tool.name).localeCompare(String(right.tool.name)));
|
|
238186
|
+
if (relaxRequiredNameTokens && ranked.length > 0) {
|
|
238187
|
+
const best = ranked[0];
|
|
238188
|
+
return ranked.filter((entry) => entry.matchedTokens === best.matchedTokens && entry.score === best.score).slice(0, 5).map((entry) => entry.tool);
|
|
238189
|
+
}
|
|
238190
|
+
return ranked.slice(0, 5).map((entry) => entry.tool);
|
|
238191
|
+
}
|
|
238192
|
+
function rememberLoadedTool(loadedToolNames, name) {
|
|
238193
|
+
loadedToolNames.delete(name);
|
|
238194
|
+
loadedToolNames.add(name);
|
|
238195
|
+
while (loadedToolNames.size > MAX_PERSISTENT_DEFERRED_TOOLS) loadedToolNames.delete(loadedToolNames.values().next().value);
|
|
238196
|
+
}
|
|
238197
|
+
function rememberDeferredToolAfterNotFound(loadedToolNames, toolName, result) {
|
|
238198
|
+
if (!(loadedToolNames instanceof Set) || result?.isError !== true) return false;
|
|
238199
|
+
const name = String(toolName || "").trim();
|
|
238200
|
+
if (!name || String(result?.output || "").trim() !== `Tool "${name}" not found`) return false;
|
|
238201
|
+
rememberLoadedTool(loadedToolNames, name);
|
|
238202
|
+
return true;
|
|
238203
|
+
}
|
|
238204
|
+
function createDeferredToolLoader(selectedTools, deferredTools, loadedToolNames = /* @__PURE__ */ new Set()) {
|
|
238205
|
+
if (!Array.isArray(selectedTools)) throw new TypeError("selectedTools must be an array");
|
|
238206
|
+
if (!(loadedToolNames instanceof Set)) throw new TypeError("loadedToolNames must be a Set");
|
|
238207
|
+
const available = /* @__PURE__ */ new Map();
|
|
238208
|
+
for (const tool of Array.isArray(deferredTools) ? deferredTools : []) {
|
|
238209
|
+
const name = String(tool?.name || "").trim();
|
|
238210
|
+
if (name && !available.has(name)) available.set(name, tool);
|
|
238211
|
+
}
|
|
238212
|
+
const deferredCount = available.size;
|
|
238213
|
+
const loader = {
|
|
238214
|
+
name: DEFERRED_TOOL_LOADER_NAME,
|
|
238215
|
+
description: [
|
|
238216
|
+
`Search ${deferredCount} deferred ${deferredCount === 1 ? "tool schema" : "tool schemas"} without loading all definitions.`,
|
|
238217
|
+
"Use select:leaf_name for one known tool, plain keywords to search, or +word to require that word in the tool name.",
|
|
238218
|
+
`Loaded tools are available in the next step; the ${MAX_PERSISTENT_DEFERRED_TOOLS} most recently selected schemas remain loaded.`
|
|
238219
|
+
].join("\n"),
|
|
238220
|
+
parameters: {
|
|
238221
|
+
type: "object",
|
|
238222
|
+
properties: { query: {
|
|
238223
|
+
type: "string",
|
|
238224
|
+
maxLength: MAX_TOOL_SEARCH_QUERY_CHARS,
|
|
238225
|
+
description: "Exact selection or keyword query, for example select:download_attachment or +slack send."
|
|
238226
|
+
} },
|
|
238227
|
+
required: ["query"],
|
|
238228
|
+
additionalProperties: false
|
|
238229
|
+
},
|
|
238230
|
+
resolveExecution(args) {
|
|
238231
|
+
const query = normalizeDeferredToolQuery(args?.query);
|
|
238232
|
+
return {
|
|
238233
|
+
description: query ? `Searching tool schemas for ${query}` : "Searching tool schemas",
|
|
238234
|
+
approvalRule: DEFERRED_TOOL_LOADER_NAME,
|
|
238235
|
+
execute: async () => {
|
|
238236
|
+
let matches = searchDeferredTools([...available.values()], query);
|
|
238237
|
+
let relatedFallback = false;
|
|
238238
|
+
if (matches.length === 0) {
|
|
238239
|
+
matches = searchRelatedDeferredTools([...available.values()], query);
|
|
238240
|
+
relatedFallback = matches.length > 0;
|
|
238241
|
+
}
|
|
238242
|
+
if (matches.length === 0) {
|
|
238243
|
+
matches = searchRelatedDeferredTools([...available.values()], query, { relaxRequiredNameTokens: true });
|
|
238244
|
+
relatedFallback = matches.length > 0;
|
|
238245
|
+
}
|
|
238246
|
+
if (matches.length === 0) {
|
|
238247
|
+
const alreadyLoaded = query.toLowerCase().startsWith("select:") ? searchDeferredTools(selectedTools.filter((tool) => tool?.name !== DEFERRED_TOOL_LOADER_NAME), query) : [];
|
|
238248
|
+
if (alreadyLoaded.length === 1) return {
|
|
238249
|
+
isError: false,
|
|
238250
|
+
output: `Tool schema already loaded: ${alreadyLoaded[0].name}. Invoke it now.`
|
|
238251
|
+
};
|
|
238252
|
+
return {
|
|
238253
|
+
isError: false,
|
|
238254
|
+
output: [
|
|
238255
|
+
`No eligible deferred tool is available for: ${query || "[empty query]"}.`,
|
|
238256
|
+
"Use a loaded alternative or report this integration as unavailable.",
|
|
238257
|
+
"ToolSearch remains available for a different tool needed later."
|
|
238258
|
+
].join(" ")
|
|
238259
|
+
};
|
|
238260
|
+
}
|
|
238261
|
+
if (query.toLowerCase().startsWith("select:") && matches.length !== 1) return {
|
|
238262
|
+
isError: true,
|
|
238263
|
+
output: `Tool selection is ambiguous: ${matches.map((tool) => tool.name).join(", ")}`
|
|
238264
|
+
};
|
|
238265
|
+
const loaded = [];
|
|
238266
|
+
for (const tool of matches) {
|
|
238267
|
+
const name = String(tool.name);
|
|
238268
|
+
if (!selectedTools.some((candidate) => candidate?.name === name)) selectedTools.push(tool);
|
|
238269
|
+
rememberLoadedTool(loadedToolNames, name);
|
|
238270
|
+
loaded.push(name);
|
|
238271
|
+
}
|
|
238272
|
+
return {
|
|
238273
|
+
isError: false,
|
|
238274
|
+
output: `${relatedFallback ? "Loaded related tool schemas" : "Loaded tool schemas"}: ${loaded.join(", ")}. Invoke them in the next step.`
|
|
238275
|
+
};
|
|
238276
|
+
}
|
|
238277
|
+
};
|
|
238278
|
+
}
|
|
238279
|
+
};
|
|
238280
|
+
deferredToolLoaders.add(loader);
|
|
238281
|
+
return loader;
|
|
238282
|
+
}
|
|
238283
|
+
module.exports = {
|
|
238284
|
+
isDeferredToolLoader: (tool) => deferredToolLoaders.has(tool),
|
|
238285
|
+
CORE_TOOL_NAMES,
|
|
238286
|
+
DEFERRED_TOOL_LOADER_NAME,
|
|
238287
|
+
MAX_PERSISTENT_DEFERRED_TOOLS,
|
|
238288
|
+
MAX_AUTO_RANKED_TOOLS,
|
|
238289
|
+
MAX_TOOL_SEARCH_QUERY_CHARS,
|
|
238290
|
+
TOOL_SCHEMA_BUDGET_RATIO,
|
|
238291
|
+
TOOL_SCHEMA_MAX_TOKENS,
|
|
238292
|
+
createDeferredToolLoader,
|
|
238293
|
+
deferredToolCatalog,
|
|
238294
|
+
deferredToolNames,
|
|
238295
|
+
mediaGenerationToolNamesForText,
|
|
238296
|
+
mediaToolNamesForTurnText,
|
|
238297
|
+
normalizeDeferredToolQuery,
|
|
238298
|
+
rankedSupportToolNamesForGoal,
|
|
238299
|
+
rankedToolNamesForTurnText,
|
|
238300
|
+
rememberDeferredToolAfterNotFound,
|
|
238301
|
+
toolSchemaBudgetTokens
|
|
238302
|
+
};
|
|
238303
|
+
})))();
|
|
237791
238304
|
const DEFAULT_APPROVE_TOOLS = new Set([
|
|
237792
238305
|
"Read",
|
|
237793
238306
|
"Grep",
|
|
@@ -237810,7 +238323,7 @@ const DEFAULT_APPROVE_TOOLS = new Set([
|
|
|
237810
238323
|
var DefaultToolApprovePermissionPolicy = class {
|
|
237811
238324
|
name = "default-tool-approve";
|
|
237812
238325
|
evaluate(context) {
|
|
237813
|
-
if (!DEFAULT_APPROVE_TOOLS.has(context.toolCall.name)) return;
|
|
238326
|
+
if (!DEFAULT_APPROVE_TOOLS.has(context.toolCall.name) && !(0, import_turn_tool_performance_policy.isDeferredToolLoader)(context.tool)) return;
|
|
237814
238327
|
return { kind: "approve" };
|
|
237815
238328
|
}
|
|
237816
238329
|
};
|
|
@@ -239495,6 +240008,7 @@ function isWithin$1(child, parent) {
|
|
|
239495
240008
|
//#endregion
|
|
239496
240009
|
//#region ../../packages/agent-core/src/skill/registry.ts
|
|
239497
240010
|
const LISTING_DESC_MAX = 250;
|
|
240011
|
+
const MODEL_SKILL_LISTING_MAX_CHARS = 8e3;
|
|
239498
240012
|
var SessionSkillRegistry = class {
|
|
239499
240013
|
byName = /* @__PURE__ */ new Map();
|
|
239500
240014
|
byPluginAndName = /* @__PURE__ */ new Map();
|
|
@@ -239574,10 +240088,58 @@ var SessionSkillRegistry = class {
|
|
|
239574
240088
|
getModelSkillListing() {
|
|
239575
240089
|
const lines = ["DISREGARD any earlier skill listings. Current available skills:"];
|
|
239576
240090
|
const listing = renderGroupedSkills(this.listInvocableSkills().filter((skill) => skill.metadata.isSubSkill !== true), formatModelSkill);
|
|
240091
|
+
if (listing.length > MODEL_SKILL_LISTING_MAX_CHARS) {
|
|
240092
|
+
const count = this.listInvocableSkills().filter((skill) => skill.metadata.isSubSkill !== true).length;
|
|
240093
|
+
return [
|
|
240094
|
+
lines[0],
|
|
240095
|
+
`${count} skills are available on demand.`,
|
|
240096
|
+
"Before specialized work, search descriptions with Skill({skill: \"task keywords\", search: true}).",
|
|
240097
|
+
"Search returns names and metadata only. Invoke Skill({skill: \"exact-name\", args: \"...\"}) to load instructions.",
|
|
240098
|
+
"Use an empty search string to browse; follow nextOffset with offset to see more results.",
|
|
240099
|
+
"A search miss is not proof that no skill exists; try its exact name or browse the catalog."
|
|
240100
|
+
].join("\n");
|
|
240101
|
+
}
|
|
239577
240102
|
if (listing.length > 0) lines.push(listing);
|
|
239578
240103
|
return lines.length === 1 ? "" : lines.join("\n");
|
|
239579
240104
|
}
|
|
239580
240105
|
};
|
|
240106
|
+
function compactLegacyModelSkillListing(prompt, registry) {
|
|
240107
|
+
const header = "DISREGARD any earlier skill listings. Current available skills:";
|
|
240108
|
+
if (!prompt.includes(header)) return prompt;
|
|
240109
|
+
const listing = renderGroupedSkills(registry.listInvocableSkills().filter((skill) => skill.metadata.isSubSkill !== true), formatModelSkill);
|
|
240110
|
+
if (listing.length <= MODEL_SKILL_LISTING_MAX_CHARS) return prompt;
|
|
240111
|
+
const legacy = `${header}\n${listing}`;
|
|
240112
|
+
const start = prompt.indexOf(legacy);
|
|
240113
|
+
if (start < 0) return prompt;
|
|
240114
|
+
const end = start + legacy.length;
|
|
240115
|
+
if (end < prompt.length && !prompt.startsWith("\n\n", end)) return prompt;
|
|
240116
|
+
return prompt.slice(0, start) + registry.getModelSkillListing() + prompt.slice(end);
|
|
240117
|
+
}
|
|
240118
|
+
function searchModelSkills(skills, query, offset = 0) {
|
|
240119
|
+
const normalize = (value) => value.normalize("NFKC").toLowerCase();
|
|
240120
|
+
const words = normalize(query.slice(0, 1e3)).match(/[\p{L}\p{N}_-]+/gu) ?? [];
|
|
240121
|
+
const matches = skills.filter((skill) => skill.metadata.disableModelInvocation !== true && skill.metadata.isSubSkill !== true && isInlineSkillType(skill.metadata.type)).map((skill) => {
|
|
240122
|
+
const name = normalize(skill.name);
|
|
240123
|
+
const metadata = normalize(`${skill.name} ${skill.description} ${skill.metadata.whenToUse ?? ""}`);
|
|
240124
|
+
return {
|
|
240125
|
+
skill,
|
|
240126
|
+
matches: words.every((word) => metadata.includes(word)),
|
|
240127
|
+
score: words.filter((word) => name.includes(word)).length
|
|
240128
|
+
};
|
|
240129
|
+
}).filter((item) => item.matches).sort((a, b) => b.score - a.score || a.skill.name.localeCompare(b.skill.name));
|
|
240130
|
+
const start = Number.isSafeInteger(offset) && offset >= 0 ? offset : 0;
|
|
240131
|
+
const page = matches.slice(start, start + 10);
|
|
240132
|
+
return JSON.stringify({
|
|
240133
|
+
total: matches.length,
|
|
240134
|
+
offset: start,
|
|
240135
|
+
nextOffset: start + page.length < matches.length ? start + page.length : null,
|
|
240136
|
+
matches: page.map(({ skill }) => ({
|
|
240137
|
+
name: skill.name,
|
|
240138
|
+
description: truncate(skill.description, LISTING_DESC_MAX),
|
|
240139
|
+
path: skill.path
|
|
240140
|
+
}))
|
|
240141
|
+
});
|
|
240142
|
+
}
|
|
239581
240143
|
function pluginSkillKey(pluginId, skillName) {
|
|
239582
240144
|
return `${pluginId}\0${normalizeSkillName(skillName)}`;
|
|
239583
240145
|
}
|
|
@@ -256149,7 +256711,7 @@ function isQuestionResponse(result) {
|
|
|
256149
256711
|
}
|
|
256150
256712
|
//#endregion
|
|
256151
256713
|
//#region ../../packages/agent-core/src/tools/builtin/collaboration/skill-tool.md?raw
|
|
256152
|
-
var skill_tool_default = "Invoke a registered skill from the current skill listing. BLOCKING REQUIREMENT: when a skill from the listing matches the user's request, you MUST call this tool (not free-form text). Do not re-invoke a skill to repeat work already done: if a `<blun-skill-loaded>` block for it with the same `args` is already present in the conversation, follow those instructions directly instead of calling the tool again. Do call the tool again when you need the skill with different arguments — the loaded block was expanded with the earlier `args` and will not reflect new inputs.\n\nAUTO-SKILL-ROUTING — you MUST proactively use skills WITHOUT being asked:\n- Before responding to any user request, check if an available skill matches the task. If it does, call this tool FIRST — do not attempt the task without the skill.\n- Images/screenshots → use the image/vision skill (e.g. \"screenshot-lesen\") to read and understand the image content before responding.\n- Design/UI tasks → use the appropriate design skill (e.g. \"design-taste-frontend\", \"high-end-visual-design\", \"apple-design\", \"huashu-design\", \"emil-design-eng\", \"motion-design-taste\", \"stitch-design-taste\", \"minimalist-ui\", \"industrial-brutalist-ui\", \"redesign-existing-projects\").\n- FOR ANY UI/frontend/visual output you MUST first load a design skill — never produce raw/default-styled UI. Gradients-everywhere, random emoji-icons, generic AI-looking layouts = FORBIDDEN slop. Always use a design skill before writing UI code.\n- Video/media tasks → use \"ffmpeg\" or the relevant media skill.\n- Web scraping/reading → use \"web-lesen\".\n- PDF/document tasks → use the PDF or document skill.\n- When in doubt whether a skill applies, call it — using a skill when not needed is harmless; NOT using a skill when it would help is a failure.\n- Never tell the user \"I don't have the right tool\" if a matching skill exists in the listing — use it.\n- This is automatic: do not ask the user \"should I use a skill?\" — just use it.\n";
|
|
256714
|
+
var skill_tool_default = "Invoke a registered skill from the current skill listing. BLOCKING REQUIREMENT: when a skill from the listing matches the user's request, you MUST call this tool (not free-form text). Do not re-invoke a skill to repeat work already done: if a `<blun-skill-loaded>` block for it with the same `args` is already present in the conversation, follow those instructions directly instead of calling the tool again. Do call the tool again when you need the skill with different arguments — the loaded block was expanded with the earlier `args` and will not reflect new inputs.\n\nFor a deferred catalog, call `Skill({skill: \"task keywords\", search: true})` first. Search returns at most 10 eligible names and descriptions without loading skill instructions. An empty search browses the catalog; pass `nextOffset` as `offset` for the next page. Then invoke the chosen exact name with `search` omitted.\n\nAUTO-SKILL-ROUTING — you MUST proactively use skills WITHOUT being asked:\n- Before responding to any user request, check if an available skill matches the task. If it does, call this tool FIRST — do not attempt the task without the skill.\n- Images/screenshots → use the image/vision skill (e.g. \"screenshot-lesen\") to read and understand the image content before responding.\n- Design/UI tasks → use the appropriate design skill (e.g. \"design-taste-frontend\", \"high-end-visual-design\", \"apple-design\", \"huashu-design\", \"emil-design-eng\", \"motion-design-taste\", \"stitch-design-taste\", \"minimalist-ui\", \"industrial-brutalist-ui\", \"redesign-existing-projects\").\n- FOR ANY UI/frontend/visual output you MUST first load a design skill — never produce raw/default-styled UI. Gradients-everywhere, random emoji-icons, generic AI-looking layouts = FORBIDDEN slop. Always use a design skill before writing UI code.\n- Video/media tasks → use \"ffmpeg\" or the relevant media skill.\n- Web scraping/reading → use \"web-lesen\".\n- PDF/document tasks → use the PDF or document skill.\n- When in doubt whether a skill applies, call it — using a skill when not needed is harmless; NOT using a skill when it would help is a failure.\n- Never tell the user \"I don't have the right tool\" if a matching skill exists in the listing — use it.\n- This is automatic: do not ask the user \"should I use a skill?\" — just use it.\n";
|
|
256153
256715
|
var NestedSkillTooDeepError = class extends Error {
|
|
256154
256716
|
skillName;
|
|
256155
256717
|
depth;
|
|
@@ -256163,7 +256725,9 @@ var NestedSkillTooDeepError = class extends Error {
|
|
|
256163
256725
|
};
|
|
256164
256726
|
const SkillToolInputSchema = object({
|
|
256165
256727
|
skill: string().describe("The exact name of the skill to invoke, spelled as it appears in the current skill listing (e.g. \"commit\", \"pdf\")."),
|
|
256166
|
-
args: string().optional().describe("Optional argument string for the skill, written like a command line (e.g. `-m \"fix bug\"`, `123`, a file path). It is split on whitespace (quotes group a token) and expanded into the skill's placeholders ($NAME, $1, $ARGUMENTS); if the skill body has no placeholders, the whole string is still appended as a trailing `ARGUMENTS:` line. Omit it only when there is nothing to pass.")
|
|
256728
|
+
args: string().optional().describe("Optional argument string for the skill, written like a command line (e.g. `-m \"fix bug\"`, `123`, a file path). It is split on whitespace (quotes group a token) and expanded into the skill's placeholders ($NAME, $1, $ARGUMENTS); if the skill body has no placeholders, the whole string is still appended as a trailing `ARGUMENTS:` line. Omit it only when there is nothing to pass."),
|
|
256729
|
+
search: boolean$1().optional().describe("Search eligible skill metadata using skill as keywords, without activating a skill."),
|
|
256730
|
+
offset: number$1().int().min(0).optional().describe("For search only: nextOffset from a previous page. Each page has at most 10 skills.")
|
|
256167
256731
|
});
|
|
256168
256732
|
var SkillTool = class SkillTool {
|
|
256169
256733
|
agent;
|
|
@@ -256176,6 +256740,12 @@ var SkillTool = class SkillTool {
|
|
|
256176
256740
|
this.options = options;
|
|
256177
256741
|
}
|
|
256178
256742
|
resolveExecution(args) {
|
|
256743
|
+
if (args.search === true) return {
|
|
256744
|
+
description: `Search skill metadata: ${args.skill}`,
|
|
256745
|
+
approvalRule: this.name,
|
|
256746
|
+
matchesRule: (ruleArgs) => matchesGlobRuleSubject(ruleArgs, args.skill),
|
|
256747
|
+
execute: async () => ({ output: searchModelSkills(this.agent.skills?.registry.listInvocableSkills() ?? [], args.skill, args.offset) })
|
|
256748
|
+
};
|
|
256179
256749
|
return {
|
|
256180
256750
|
description: `Invoke skill ${args.skill}`,
|
|
256181
256751
|
display: {
|
|
@@ -263653,6 +264223,26 @@ function blunThinkingIntentInput(input) {
|
|
|
263653
264223
|
text: channelText
|
|
263654
264224
|
}];
|
|
263655
264225
|
}
|
|
264226
|
+
function blunTurnHasAttachment(input) {
|
|
264227
|
+
return input.some((part) => part.type !== "text") || /\b(?:image_path|attachment_file_id)\s*=/i.test(blunExtractText(input));
|
|
264228
|
+
}
|
|
264229
|
+
function greetingHistory(history, anchor) {
|
|
264230
|
+
const start = anchor === void 0 ? -1 : history.indexOf(anchor);
|
|
264231
|
+
if (start < 0) return history;
|
|
264232
|
+
const recent = [];
|
|
264233
|
+
let chars = 0;
|
|
264234
|
+
for (let i = start - 1; i >= 0 && recent.length < 6; i -= 1) {
|
|
264235
|
+
const message = history[i];
|
|
264236
|
+
if (message.role === "tool" || message.toolCalls.length > 0) break;
|
|
264237
|
+
if (message.role !== "assistant" && message.origin?.kind !== "user") continue;
|
|
264238
|
+
const size = blunExtractText(message.content).length;
|
|
264239
|
+
if (chars + size > 12e3 || message.content.some((part) => part.type !== "text")) break;
|
|
264240
|
+
recent.unshift(message);
|
|
264241
|
+
chars += size;
|
|
264242
|
+
}
|
|
264243
|
+
while (recent.length > 0 && recent[0].role !== "user") recent.shift();
|
|
264244
|
+
return [...recent, ...history.slice(start)];
|
|
264245
|
+
}
|
|
263656
264246
|
/**
|
|
263657
264247
|
* BLUN: builtin tools kept when the full schema set would overflow a small
|
|
263658
264248
|
* context window. The essential read / edit / run / track loop — enough for
|
|
@@ -263663,12 +264253,14 @@ function blunThinkingIntentInput(input) {
|
|
|
263663
264253
|
*/
|
|
263664
264254
|
const BLUN_LEAN_TOOL_NAMES = new Set([
|
|
263665
264255
|
"Read",
|
|
264256
|
+
"ReadBatch",
|
|
263666
264257
|
"Write",
|
|
263667
264258
|
"Edit",
|
|
263668
264259
|
"Grep",
|
|
263669
264260
|
"Glob",
|
|
263670
264261
|
"Bash",
|
|
263671
264262
|
"TodoList",
|
|
264263
|
+
"Skill",
|
|
263672
264264
|
"CompactConversation",
|
|
263673
264265
|
"MistakeRecord"
|
|
263674
264266
|
]);
|
|
@@ -263694,25 +264286,20 @@ function blunToolsForOrigin(tools, origin) {
|
|
|
263694
264286
|
return tools.filter((tool) => !BLUN_TELEGRAM_OUTBOUND_TOOL_RE.test(tool.name));
|
|
263695
264287
|
}
|
|
263696
264288
|
/**
|
|
263697
|
-
*
|
|
263698
|
-
*
|
|
263699
|
-
*
|
|
263700
|
-
* models (King) fall back — so the guard is self-tuning and never touches a
|
|
263701
|
-
* config where tools comfortably fit.
|
|
263702
|
-
*/
|
|
263703
|
-
const BLUN_TOOL_BUDGET_RATIO = .25;
|
|
263704
|
-
/**
|
|
263705
|
-
* Choose the tool set for a task turn. Returns the full set unless the model
|
|
263706
|
-
* window is small enough that the schemas alone blow the context budget, in
|
|
263707
|
-
* which case the lean essential set is used. Never returns an empty list when
|
|
263708
|
-
* tools were requested: a profile with no lean-set matches keeps the full set
|
|
263709
|
-
* rather than sending a tool-less task turn.
|
|
264289
|
+
* Restore bounded schema disclosure even on large-context models. Only tools
|
|
264290
|
+
* already eligible for this turn enter the loader; execution still follows
|
|
264291
|
+
* the ordinary permission pipeline.
|
|
263710
264292
|
*/
|
|
263711
|
-
function blunSelectTurnTools(tools, maxContextTokens) {
|
|
263712
|
-
if (
|
|
263713
|
-
|
|
263714
|
-
|
|
263715
|
-
|
|
264293
|
+
function blunSelectTurnTools(tools, maxContextTokens, loadedToolNames = /* @__PURE__ */ new Set(), requiredToolNames = /* @__PURE__ */ new Set(), selected = []) {
|
|
264294
|
+
if (estimateTokensForTools(tools) <= (0, import_turn_tool_performance_policy.toolSchemaBudgetTokens)(maxContextTokens) || tools.some((tool) => tool.name === "ToolSearch")) {
|
|
264295
|
+
selected.splice(0, selected.length, ...tools);
|
|
264296
|
+
return selected;
|
|
264297
|
+
}
|
|
264298
|
+
selected.splice(0, selected.length, ...tools.filter((tool) => BLUN_LEAN_TOOL_NAMES.has(tool.name) || BLUN_LEAN_KEEP_RE.test(tool.name) || BLUN_LANGUAGE_REVIEW_TOOL_NAMES.has(tool.name) || loadedToolNames.has(tool.name) || requiredToolNames.has(tool.name)));
|
|
264299
|
+
const names = new Set(selected.map((tool) => tool.name));
|
|
264300
|
+
const deferred = tools.filter((tool) => !names.has(tool.name));
|
|
264301
|
+
if (deferred.length > 0) selected.push((0, import_turn_tool_performance_policy.createDeferredToolLoader)(selected, deferred, loadedToolNames));
|
|
264302
|
+
return selected;
|
|
263716
264303
|
}
|
|
263717
264304
|
const LLM_NOT_SET_MESSAGE = "LLM not set, send \"/login\" to login";
|
|
263718
264305
|
/** Origin tag for the synthetic "continue" prompt that drives each goal turn. */
|
|
@@ -263770,6 +264357,8 @@ const GOAL_CONTINUATION_PROMPT = [
|
|
|
263770
264357
|
var TurnFlow = class {
|
|
263771
264358
|
agent;
|
|
263772
264359
|
admissionClosed = false;
|
|
264360
|
+
loadedToolNames = /* @__PURE__ */ new Set();
|
|
264361
|
+
refreshSelectedTools;
|
|
263773
264362
|
executions = new ExecutionLedger();
|
|
263774
264363
|
executingControllers = /* @__PURE__ */ new Set();
|
|
263775
264364
|
steerBuffer = [];
|
|
@@ -264006,6 +264595,9 @@ var TurnFlow = class {
|
|
|
264006
264595
|
if (snapshot.throughSequence < 0) return false;
|
|
264007
264596
|
return this.flushSteerBuffer(turnId, snapshot.throughSequence);
|
|
264008
264597
|
}
|
|
264598
|
+
refreshRequestTools(snapshot) {
|
|
264599
|
+
return this.refreshSelectedTools?.(snapshot);
|
|
264600
|
+
}
|
|
264009
264601
|
bufferSteer(input, origin, targetTurnId) {
|
|
264010
264602
|
this.steerBuffer.push({
|
|
264011
264603
|
sequence: this.nextSteerSequence,
|
|
@@ -264389,17 +264981,41 @@ var TurnFlow = class {
|
|
|
264389
264981
|
const personalMemoryRecall = await this.agent.injection.injectPersonalMemoryForTurn(turnId, input, origin, signal);
|
|
264390
264982
|
await this.agent.injection.injectGoal();
|
|
264391
264983
|
this.setActiveSteerAcceptance(turnId, true);
|
|
264392
|
-
const turnNeedsTools = blunTurnNeedsTools(input, origin);
|
|
264393
264984
|
const turnNeedsThinking = blunTurnNeedsTools(blunThinkingIntentInput(input), origin);
|
|
264985
|
+
let toolInput = input;
|
|
264986
|
+
let taskToolsNeeded = turnNeedsThinking || blunTurnHasAttachment(input);
|
|
264987
|
+
const greetingAnchor = this.agent.context.history.findLast((message) => message.role === "user" && message.origin?.kind === "user");
|
|
264988
|
+
let partialContext = false;
|
|
264989
|
+
const turnHistory = () => {
|
|
264990
|
+
const history = personalMemoryRecall === void 0 ? this.agent.context.history : [...this.agent.context.history, personalMemoryRecall];
|
|
264991
|
+
const selected = taskToolsNeeded ? history : greetingHistory(history, greetingAnchor);
|
|
264992
|
+
partialContext = selected.length < history.length;
|
|
264993
|
+
return selected;
|
|
264994
|
+
};
|
|
264394
264995
|
const turnLLM = this.agent.llmForTurn(turnNeedsThinking ? void 0 : "off");
|
|
264996
|
+
const turnTools = this.agent.tools.captureTurnTools();
|
|
264395
264997
|
while (true) {
|
|
264396
264998
|
signal.throwIfAborted();
|
|
264397
264999
|
const model = this.agent.config.model;
|
|
264398
265000
|
const loopControl = this.agent.blunConfig?.loopControl;
|
|
264399
265001
|
let stopForGoalBudget = false;
|
|
264400
265002
|
try {
|
|
264401
|
-
const
|
|
264402
|
-
|
|
265003
|
+
const selectedTools = [];
|
|
265004
|
+
this.refreshSelectedTools = (snapshot) => {
|
|
265005
|
+
if (snapshot.messages.length > 0) toolInput = snapshot.messages.flatMap((message) => message.content);
|
|
265006
|
+
const eligibleTools = blunToolsForOrigin(this.agent.injection.filterPersonalMemoryToolsForTurn(turnId, input, origin, turnTools()), origin);
|
|
265007
|
+
const intent = blunThinkingIntentInput(toolInput);
|
|
265008
|
+
taskToolsNeeded ||= blunTurnNeedsTools(intent, origin) || blunTurnHasAttachment(toolInput);
|
|
265009
|
+
const required = (0, import_turn_tool_performance_policy.mediaToolNamesForTurnText)(blunExtractText(toolInput));
|
|
265010
|
+
if (taskToolsNeeded) {
|
|
265011
|
+
blunSelectTurnTools(eligibleTools, this.agent.config.modelCapabilities?.max_context_tokens, this.loadedToolNames, required, selectedTools);
|
|
265012
|
+
for (const name of (0, import_turn_tool_performance_policy.rankedToolNamesForTurnText)(eligibleTools, blunExtractText(intent))) {
|
|
265013
|
+
const tool = eligibleTools.find((candidate) => candidate.name === name);
|
|
265014
|
+
if (tool !== void 0 && !selectedTools.some((candidate) => candidate.name === name) && estimateTokensForTools([...selectedTools, tool]) <= (0, import_turn_tool_performance_policy.toolSchemaBudgetTokens)(this.agent.config.modelCapabilities?.max_context_tokens)) selectedTools.push(tool);
|
|
265015
|
+
}
|
|
265016
|
+
} else selectedTools.splice(0, selectedTools.length, ...eligibleTools.filter((tool) => BLUN_LANGUAGE_REVIEW_TOOL_NAMES.has(tool.name) || BLUN_TELEGRAM_OUTBOUND_TOOL_RE.test(tool.name)));
|
|
265017
|
+
return selectedTools;
|
|
265018
|
+
};
|
|
264403
265019
|
return (await runTurn({
|
|
264404
265020
|
turnId: String(turnId),
|
|
264405
265021
|
signal,
|
|
@@ -264410,15 +265026,15 @@ var TurnFlow = class {
|
|
|
264410
265026
|
}, completion);
|
|
264411
265027
|
},
|
|
264412
265028
|
llm: turnLLM,
|
|
264413
|
-
buildMessages: () => this.agent.context.project(
|
|
264414
|
-
buildMessagesStrict: () => this.agent.context.project(
|
|
265029
|
+
buildMessages: () => this.agent.context.project(turnHistory(), { dropOrphanResults: true }),
|
|
265030
|
+
buildMessagesStrict: () => this.agent.context.project(turnHistory(), {
|
|
264415
265031
|
synthesizeMissing: true,
|
|
264416
265032
|
dropOrphanResults: true,
|
|
264417
265033
|
dedupeDuplicateToolCalls: true,
|
|
264418
265034
|
dropLeadingNonUser: true,
|
|
264419
265035
|
mergeConsecutiveAssistants: true
|
|
264420
265036
|
}),
|
|
264421
|
-
dispatchEvent: this.buildDispatchEvent(turnId, signal, onFinalResponse),
|
|
265037
|
+
dispatchEvent: this.buildDispatchEvent(turnId, signal, onFinalResponse, () => partialContext),
|
|
264422
265038
|
tools: selectedTools,
|
|
264423
265039
|
log: this.agent.log,
|
|
264424
265040
|
maxSteps: loopControl?.maxStepsPerTurn,
|
|
@@ -264535,6 +265151,8 @@ var TurnFlow = class {
|
|
|
264535
265151
|
error
|
|
264536
265152
|
});
|
|
264537
265153
|
throw error;
|
|
265154
|
+
} finally {
|
|
265155
|
+
this.refreshSelectedTools = void 0;
|
|
264538
265156
|
}
|
|
264539
265157
|
}
|
|
264540
265158
|
}
|
|
@@ -264555,13 +265173,16 @@ var TurnFlow = class {
|
|
|
264555
265173
|
this.agent.log.warn("failed to close abandoned tool exchange", { error });
|
|
264556
265174
|
}
|
|
264557
265175
|
}
|
|
264558
|
-
buildDispatchEvent(turnId, signal, onFinalResponse) {
|
|
265176
|
+
buildDispatchEvent(turnId, signal, onFinalResponse, usesPartialContext) {
|
|
264559
265177
|
let responseStepUuid;
|
|
264560
265178
|
let responseParts = [];
|
|
264561
265179
|
let responseHasToolCall = false;
|
|
264562
265180
|
const dispatch = createLoopEventDispatcher({
|
|
264563
265181
|
appendTranscriptRecord: async (event) => {
|
|
264564
|
-
this.agent.context.appendLoopEvent(event)
|
|
265182
|
+
this.agent.context.appendLoopEvent(event.type === "step.end" && usesPartialContext?.() ? {
|
|
265183
|
+
...event,
|
|
265184
|
+
contextCoverage: "partial"
|
|
265185
|
+
} : event);
|
|
264565
265186
|
},
|
|
264566
265187
|
emitLiveEvent: (event) => {
|
|
264567
265188
|
this.agent.cron?.observeLoopEvent(turnId, event);
|
|
@@ -267507,6 +268128,17 @@ var ToolManager = class {
|
|
|
267507
268128
|
const names = uniq([...this.enabledTools, ...mcpNames]).toSorted((a, b) => a.localeCompare(b)).filter((name) => !(hideGoalMutationTools && (name === "SetGoalBudget" || name === "UpdateGoal")));
|
|
267508
268129
|
return (allowedTools !== void 0 && allowedTools.length > 0 ? names.filter((name) => allowedTools.includes(name)) : names).map((name) => this.userTools.get(name) ?? this.mcpTools.get(name)?.tool ?? this.builtinTools.get(name)).filter((tool) => !!tool);
|
|
267509
268130
|
}
|
|
268131
|
+
captureTurnTools() {
|
|
268132
|
+
if (this.loopToolsOverride !== void 0) {
|
|
268133
|
+
const tools = this.loopToolsOverride;
|
|
268134
|
+
return () => tools;
|
|
268135
|
+
}
|
|
268136
|
+
const fixed = this.loopTools.filter((tool) => this.mcpTools.get(tool.name)?.tool !== tool);
|
|
268137
|
+
const fixedNames = new Set(fixed.map((tool) => tool.name));
|
|
268138
|
+
const patterns = [...this.mcpAccessPatterns];
|
|
268139
|
+
const allowed = this.allowedTools === void 0 ? void 0 : new Set(this.allowedTools);
|
|
268140
|
+
return () => [...fixed, ...[...this.mcpTools.entries()].filter(([name]) => !fixedNames.has(name) && patterns.some((pattern) => import_picomatch.default.isMatch(name, pattern)) && (allowed === void 0 || allowed.has(name))).map(([, entry]) => entry.tool)].toSorted((a, b) => a.name.localeCompare(b.name));
|
|
268141
|
+
}
|
|
267510
268142
|
};
|
|
267511
268143
|
//#endregion
|
|
267512
268144
|
//#region ../../packages/agent-core/src/agent/response-review-mcp.ts
|
|
@@ -268301,6 +268933,12 @@ var Agent$1 = class {
|
|
|
268301
268933
|
this.setActiveResponderModel(alias);
|
|
268302
268934
|
}, async (_candidate, params, rebuildMessages) => {
|
|
268303
268935
|
const steers = this.turn.snapshotPendingSteers();
|
|
268936
|
+
const requestTools = this.turn.refreshRequestTools(steers) ?? params.tools;
|
|
268937
|
+
params = {
|
|
268938
|
+
...params,
|
|
268939
|
+
tools: requestTools,
|
|
268940
|
+
messages: await rebuildMessages()
|
|
268941
|
+
};
|
|
268304
268942
|
let systemPrompt = this.effectiveSystemPrompt;
|
|
268305
268943
|
const compacted = await this.fullCompaction.beforeStep(params.signal, {
|
|
268306
268944
|
messages: params.messages,
|
|
@@ -268340,7 +268978,7 @@ var Agent$1 = class {
|
|
|
268340
268978
|
capability: runtimeModel.modelCapabilities,
|
|
268341
268979
|
generate: this.generateForModel(modelAlias),
|
|
268342
268980
|
completionBudgetConfig,
|
|
268343
|
-
reportedContextTokens: () => this.context.
|
|
268981
|
+
reportedContextTokens: () => this.context.tokenCountWithPending,
|
|
268344
268982
|
idleTimeoutMs: this.blunConfig?.timeout ? this.blunConfig.timeout * 1e3 : void 0,
|
|
268345
268983
|
onMediaDropped: this.onMediaDropped,
|
|
268346
268984
|
visionReader: this.visionReader,
|
|
@@ -268361,7 +268999,8 @@ var Agent$1 = class {
|
|
|
268361
268999
|
this.emitStatusUpdated();
|
|
268362
269000
|
}
|
|
268363
269001
|
get effectiveSystemPrompt() {
|
|
268364
|
-
const
|
|
269002
|
+
const registry = this.skills?.registry;
|
|
269003
|
+
const base = registry === void 0 ? this.config.systemPrompt : compactLegacyModelSkillListing(this.config.systemPrompt, registry);
|
|
268365
269004
|
if (this.runtimeSystemPromptAppend.length === 0) return base;
|
|
268366
269005
|
return base.length === 0 ? this.runtimeSystemPromptAppend : `${base}\n\n${this.runtimeSystemPromptAppend}`;
|
|
268367
269006
|
}
|