@cognipeer/agent-sdk 0.8.4 → 0.8.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -6922,6 +6922,42 @@ async function resolveAvailableSkills(skills, opts = {}) {
6922
6922
  }
6923
6923
  return out;
6924
6924
  }
6925
+ var WORD_SPLIT = /[^\p{L}\p{N}]+/u;
6926
+ var MIN_TERM_LENGTH = 3;
6927
+ var FIELD_WEIGHTS = { key: 4, title: 3, header: 2 };
6928
+ var wordsOf = (text) => text.toLowerCase().split(WORD_SPLIT).filter((word) => word.length >= 2);
6929
+ var termHitsWord = (term, word) => word === term || word.startsWith(term) || word.length >= 3 && term.startsWith(word) || term.length >= 5 && word.length >= 5 && word.slice(0, 4) === term.slice(0, 4);
6930
+ function searchSkills(skills, query, limit = 10) {
6931
+ const cap = Math.max(1, limit);
6932
+ const normalized = (query || "").trim().toLowerCase();
6933
+ const terms = [
6934
+ ...new Set(normalized.split(WORD_SPLIT).filter((term) => term.length >= MIN_TERM_LENGTH))
6935
+ ];
6936
+ if (terms.length === 0) return skills.slice(0, cap);
6937
+ const scored = skills.map((skill, index) => {
6938
+ const fields = {
6939
+ key: wordsOf(skill.key),
6940
+ title: wordsOf(skill.title || ""),
6941
+ header: wordsOf(skill.header || "")
6942
+ };
6943
+ const exact = skill.key.toLowerCase() === normalized || (skill.title || "").toLowerCase() === normalized;
6944
+ let score = exact ? 100 : 0;
6945
+ let coverage = 0;
6946
+ for (const term of terms) {
6947
+ let hit = false;
6948
+ for (const [field, weight] of Object.entries(FIELD_WEIGHTS)) {
6949
+ if (fields[field].some((word) => termHitsWord(term, word))) {
6950
+ score += weight;
6951
+ hit = true;
6952
+ }
6953
+ }
6954
+ if (hit) coverage += 1;
6955
+ }
6956
+ return { skill, score, coverage, index };
6957
+ }).filter((entry) => entry.score > 0);
6958
+ scored.sort((a, b) => b.coverage - a.coverage || b.score - a.score || a.index - b.index);
6959
+ return scored.slice(0, cap).map((entry) => entry.skill);
6960
+ }
6925
6961
  function buildSkillHeaderBlock(skills) {
6926
6962
  if (skills.length === 0) return "";
6927
6963
  const lines = skills.map((skill) => `- ${skill.key}: ${skill.header}`);
@@ -6945,24 +6981,65 @@ function dedupeToolsByName(tools) {
6945
6981
 
6946
6982
  // src/smart/skills/skillTools.ts
6947
6983
  var MAX_RETURNED_INDEX = 40;
6948
- var OPEN_SKILL_DESCRIPTION = "Load a capability on demand. Pass a skillKey from <available_skills>. A small skill binds all its tools immediately; a large one returns a tool index \u2014 then call bind_skill_tools with only the tools you need. Open only what the task needs.";
6984
+ var DEFAULT_SEARCH_LIMIT = 10;
6985
+ var MAX_SEARCH_LIMIT = 25;
6986
+ var isSearchDisclosure = (policy) => policy.disclosure === "search";
6987
+ var keySource = (policy) => isSearchDisclosure(policy) ? "search_skills" : "<available_skills>";
6988
+ var openSkillDescription = (policy) => `Load a capability on demand. Pass a skillKey from ${keySource(policy)}. A small skill binds all its tools immediately; a large one returns a tool index \u2014 then call bind_skill_tools with only the tools you need. Open only what the task needs.`;
6949
6989
  var BIND_SKILL_TOOLS_DESCRIPTION = "After open_skill on a large skill, bind a chosen subset of its tools by name. Pick the few tools the task actually needs.";
6990
+ var SEARCH_SKILLS_DESCRIPTION = 'Find a reusable playbook (a "skill") for the task at hand. Skills are proven, pre-written procedures for specific kinds of work \u2014 each with its own tools, which are NOT in your tool list until you open the skill. Call this early whenever a request looks like an established procedure, or when you seem to be missing a capability you would expect to have: describe the task in `query`. Returns matching skill keys; pass one to open_skill to load its instructions and tools. An empty query lists what exists.';
6950
6991
  function findSkill(deps, key) {
6951
6992
  return deps.skills.find((skill) => skill.key === key);
6952
6993
  }
6994
+ function createSearchSkillsTool(deps) {
6995
+ const tool = createTool({
6996
+ name: "search_skills",
6997
+ description: SEARCH_SKILLS_DESCRIPTION,
6998
+ schema: zod.z.object({
6999
+ query: zod.z.string().optional().describe("What you are trying to do, in a few words. Omit to list available skills."),
7000
+ limit: zod.z.number().int().positive().optional().describe(`Max results to return (default ${DEFAULT_SEARCH_LIMIT}).`)
7001
+ }).strict(),
7002
+ func: async ({ query, limit }) => {
7003
+ const { skills, policy, registryRef: ref } = tool._deps;
7004
+ const available = await resolveAvailableSkills(skills, { modelTier: policy.modelTier });
7005
+ if (available.length === 0) {
7006
+ return { skills: [], total: 0, hint: "No skills are available in this workspace." };
7007
+ }
7008
+ const capped = Math.min(limit || DEFAULT_SEARCH_LIMIT, MAX_SEARCH_LIMIT);
7009
+ const matches = searchSkills(available, query, capped);
7010
+ const missed = matches.length === 0;
7011
+ const shown = missed ? available.slice(0, capped) : matches;
7012
+ return {
7013
+ skills: shown.map((skill) => ({
7014
+ skillKey: skill.key,
7015
+ title: skill.title,
7016
+ header: skill.header,
7017
+ ...ref.openedSkillKeys.includes(skill.key) ? { alreadyOpen: true } : {}
7018
+ })),
7019
+ total: available.length,
7020
+ hint: missed ? `Nothing matched "${query}" literally \u2014 listing ${shown.length} of ${available.length} instead. Judge them by their headers; call open_skill(skillKey) if one fits, otherwise carry on without a skill.` : "Call open_skill(skillKey) to load the one that fits."
7021
+ };
7022
+ }
7023
+ });
7024
+ tool._deps = deps;
7025
+ tool.__source = "smart-skills";
7026
+ return tool;
7027
+ }
6953
7028
  function createOpenSkillTool(deps) {
6954
7029
  const tool = createTool({
6955
7030
  name: "open_skill",
6956
- description: OPEN_SKILL_DESCRIPTION,
7031
+ description: openSkillDescription(deps.policy),
6957
7032
  schema: zod.z.object({
6958
- skillKey: zod.z.string().min(1).describe("A key from <available_skills>."),
7033
+ skillKey: zod.z.string().min(1).describe(`A key from ${keySource(deps.policy)}.`),
6959
7034
  query: zod.z.string().optional().describe("What you need from the skill \u2014 used to rank a large skill's tools.")
6960
7035
  }).strict(),
6961
7036
  func: async ({ skillKey, query }) => {
6962
7037
  const { registryRef: ref, policy } = tool._deps;
6963
7038
  const skill = findSkill(tool._deps, skillKey);
6964
7039
  if (!skill) {
6965
- return { error: `Unknown skill: ${skillKey}. Choose a key listed in <available_skills>.` };
7040
+ return {
7041
+ error: `Unknown skill: ${skillKey}. ${isSearchDisclosure(policy) ? "Call search_skills to get a valid key." : "Choose a key listed in <available_skills>."}`
7042
+ };
6966
7043
  }
6967
7044
  if (skill.isAvailable && !await skill.isAvailable()) {
6968
7045
  return { error: `Skill ${skillKey} is not available in this workspace.` };
@@ -7051,7 +7128,9 @@ function createBindSkillToolsTool(deps) {
7051
7128
  return tool;
7052
7129
  }
7053
7130
  function createSkillTools(deps) {
7054
- return [createOpenSkillTool(deps), createBindSkillToolsTool(deps)];
7131
+ const tools = [createOpenSkillTool(deps), createBindSkillToolsTool(deps)];
7132
+ if (isSearchDisclosure(deps.policy)) tools.unshift(createSearchSkillsTool(deps));
7133
+ return tools;
7055
7134
  }
7056
7135
 
7057
7136
  // src/smart/subagents/types.ts
@@ -7731,7 +7810,8 @@ function createSmartAgent(opts) {
7731
7810
  if (changed) toolSet.skillRegistryRef.__onToolsChanged?.();
7732
7811
  }
7733
7812
  const syncPlanFromRef = (state2) => syncPlanStateWith(stateRef, state2);
7734
- const availableSkills = skillsEnabled ? await resolveAvailableSkills(skills, { modelTier: skillPolicy.modelTier }) : [];
7813
+ const catalogDisclosure = skillPolicy.disclosure !== "search";
7814
+ const availableSkills = skillsEnabled && catalogDisclosure ? await resolveAvailableSkills(skills, { modelTier: skillPolicy.modelTier }) : [];
7735
7815
  const skillBlock = availableSkills.length > 0 ? buildSkillHeaderBlock(availableSkills) : void 0;
7736
7816
  let subagentBlock;
7737
7817
  if (subagentsEnabled) {
@@ -11008,6 +11088,7 @@ exports.createParallelTool = createParallelTool;
11008
11088
  exports.createProvider = createProvider;
11009
11089
  exports.createRegexGuardrail = createRegexGuardrail;
11010
11090
  exports.createResolverNode = createResolverNode;
11091
+ exports.createSearchSkillsTool = createSearchSkillsTool;
11011
11092
  exports.createSkillRegistryRef = createSkillRegistryRef;
11012
11093
  exports.createSkillTools = createSkillTools;
11013
11094
  exports.createSmartAgent = createSmartAgent;
@@ -11059,6 +11140,7 @@ exports.resolveUserQuestionState = resolveUserQuestionState;
11059
11140
  exports.restoreSnapshot = restoreSnapshot;
11060
11141
  exports.runSmartAgentEvalHarness = runSmartAgentEvalHarness;
11061
11142
  exports.scoreItemsByRelevance = scoreItemsByRelevance;
11143
+ exports.searchSkills = searchSkills;
11062
11144
  exports.seedChildMessages = seedChildMessages;
11063
11145
  exports.selectTopIndicesInOrder = selectTopIndicesInOrder;
11064
11146
  exports.setTokenCounter = setTokenCounter;