@amical/aiagent-sdk 0.1.10 → 0.1.11

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.
@@ -516,6 +516,44 @@ var toolParamNames = [
516
516
  "start_line",
517
517
  "end_line"
518
518
  ];
519
+
520
+ // src/shared/custom-tools.ts
521
+ function isCustomToolGroup(tool) {
522
+ return Array.isArray(tool.children) && tool.children.length > 0;
523
+ }
524
+ function collectCustomToolNames(tools) {
525
+ const names = [];
526
+ const visit = (list) => {
527
+ for (const tool of list) {
528
+ names.push(tool.name);
529
+ if (Array.isArray(tool.children) && tool.children.length > 0) {
530
+ visit(tool.children);
531
+ }
532
+ }
533
+ };
534
+ visit(tools);
535
+ return names;
536
+ }
537
+ function renderCustomToolPrompt(tool, cwd = "") {
538
+ const params = tool.params ? Object.entries(tool.params) : [];
539
+ const replaceCwd = (text) => String(text).replaceAll("${context.cwd}", cwd);
540
+ const paramLines = params.map(([name, description]) => `- ${name}: ${replaceCwd(description)}`).join("\n");
541
+ const usageLines = params.map(([name, description]) => `<${name}>${replaceCwd(description)}</${name}>`).join("\n");
542
+ return `### ${tool.name}
543
+ Description: ${tool.description}
544
+ Parameters:
545
+ ${paramLines}
546
+ - task_progress: (optional) A checklist showing task progress after this tool use is completed. The task_progress parameter must be included as a separate parameter inside of the parent tool call, it must be separate from other parameters such as content, arguments, etc. (See 'UPDATING TASK PROGRESS' section for more details)
547
+ Usage:
548
+ <${tool.name}>
549
+ ${usageLines}
550
+ <task_progress>Checklist here (optional)</task_progress>
551
+ </${tool.name}>
552
+ `;
553
+ }
554
+ function renderCustomToolsPrompt(tools, cwd = "") {
555
+ return tools.map((tool) => renderCustomToolPrompt(tool, cwd)).join("\n");
556
+ }
519
557
  var TEXT_FILE_EXTENSIONS = /* @__PURE__ */ new Set([
520
558
  "txt",
521
559
  "md",
@@ -599,9 +637,19 @@ var ClineAgent = class {
599
637
  skillDir;
600
638
  rulesDir;
601
639
  customTools;
640
+ /** 当前可用(已展开集合)的顶层工具列表,传给 PromptManager 渲染 */
641
+ activeCustomTools;
642
+ /** 所有已知工具名(含未激活 children),便于查找定义 */
643
+ customToolsByName;
602
644
  customToolNames;
603
645
  allowDefaultTools;
604
646
  customInstructions;
647
+ /** 已激活的工具集入口名 */
648
+ activatedGroups = /* @__PURE__ */ new Set();
649
+ /** activeCustomTools 变更版本号,用于 Prompt 缓存失效 */
650
+ activeToolsVersion = 0;
651
+ /** 缓存 sysPrompt 时记录的版本号 */
652
+ promptActiveToolsVersion = -1;
605
653
  sysPrompt;
606
654
  noUseTollSysPrompt;
607
655
  // 简单的事件回调系统,供宿主环境注册以监听 Agent 内部事件
@@ -621,31 +669,38 @@ var ClineAgent = class {
621
669
  this.allowDefaultTools.push("agent_attempt_completion" /* ATTEMPT */);
622
670
  }
623
671
  this.customInstructions = options.customInstructions;
672
+ this.customToolsByName = /* @__PURE__ */ new Map();
673
+ this.activeCustomTools = [...this.customTools];
674
+ this.customToolNames = new Set(collectCustomToolNames(this.customTools));
624
675
  if (this.customTools.length > 0) {
625
- const dynamicToolNames = /* @__PURE__ */ new Set();
626
676
  const customToolParams = /* @__PURE__ */ new Set();
627
- for (const customTool of this.customTools) {
628
- dynamicToolNames.add(customTool.name);
629
- if (customTool.params) {
630
- for (const key in customTool.params) {
631
- if (!Object.hasOwn(customTool.params, key)) continue;
632
- customToolParams.add(key);
677
+ const visit = (tools) => {
678
+ for (const customTool of tools) {
679
+ this.customToolsByName.set(customTool.name, customTool);
680
+ if (customTool.params) {
681
+ for (const key in customTool.params) {
682
+ if (!Object.hasOwn(customTool.params, key)) continue;
683
+ customToolParams.add(key);
684
+ }
685
+ }
686
+ if (Array.isArray(customTool.children) && customTool.children.length > 0) {
687
+ visit(customTool.children);
633
688
  }
634
689
  }
635
- }
690
+ };
691
+ visit(this.customTools);
636
692
  const defaultToolNames = Object.values(AgentDefaultTool);
637
- const overlappingTools = Array.from(dynamicToolNames).filter((name) => defaultToolNames.includes(name));
693
+ const overlappingTools = Array.from(this.customToolNames).filter((name) => defaultToolNames.includes(name));
638
694
  if (overlappingTools.length > 0) {
639
695
  throw new Error(`Custom tools and default tools have overlapping names: ${overlappingTools.join(", ")}`);
640
696
  }
641
- if (dynamicToolNames.size > 0) {
642
- setDynamicToolUseNames("customUser", Array.from(dynamicToolNames));
697
+ if (this.customToolNames.size > 0) {
698
+ setDynamicToolUseNames("customUser", Array.from(this.customToolNames));
643
699
  }
644
700
  if (customToolParams.size > 0) {
645
701
  this.allToolParamNames = Array.from(/* @__PURE__ */ new Set([...this.allToolParamNames, ...Array.from(customToolParams)]));
646
702
  }
647
703
  }
648
- this.customToolNames = new Set(this.customTools.map((t) => t.name));
649
704
  this.skillDir = this.runtime.path.join(this.runtime.env.cwd(), ".agents/skills");
650
705
  this.rulesDir = this.runtime.path.join(this.runtime.env.cwd(), ".agents/rules");
651
706
  }
@@ -669,10 +724,11 @@ var ClineAgent = class {
669
724
  shell: this.runtime.env.shell(),
670
725
  skills: await this.getSkills(),
671
726
  agentRules: await this.getAgentRules(),
672
- customTools: this.customTools,
727
+ customTools: this.activeCustomTools,
673
728
  allowDefaultTools: this.allowDefaultTools,
674
729
  customInstructions: this.customInstructions
675
730
  };
731
+ this.promptActiveToolsVersion = this.activeToolsVersion;
676
732
  this.sysPrompt = await this.promptManager.getSystemPrompt(context);
677
733
  this.noUseTollSysPrompt = this.promptManager.getNoUseToolInstructions(context);
678
734
  return { sysPrompt: this.sysPrompt, noUseTollSysPrompt: this.noUseTollSysPrompt };
@@ -781,9 +837,9 @@ ${content.trim()}\`\`\``);
781
837
  * 核心任务循环
782
838
  */
783
839
  async loop() {
784
- const { sysPrompt, noUseTollSysPrompt } = await this.getPrompt(true);
785
- const { customTools, customToolNames } = this;
840
+ const { customToolsByName, customToolNames } = this;
786
841
  while (this.state === "thinking" /* THINKING */) {
842
+ const { sysPrompt, noUseTollSysPrompt } = await this.getCurrentPrompt();
787
843
  this.loopCount++;
788
844
  if (this.loopCount > this.maxLoopCount) {
789
845
  await this.memory.appendMessage({
@@ -828,7 +884,33 @@ ${content.trim()}\`\`\``);
828
884
  }
829
885
  }
830
886
  if (customToolNames.has(tool.name)) {
831
- const customTool = customTools.find((t) => t.name === tool.name);
887
+ const customTool = customToolsByName.get(tool.name);
888
+ if (!customTool) {
889
+ toolResults.push({ tool, result: `Error: Custom tool "${tool.name}" not found.` });
890
+ continue;
891
+ }
892
+ if (isCustomToolGroup(customTool)) {
893
+ let groupResult;
894
+ if (customTool.onCall) {
895
+ try {
896
+ groupResult = await customTool.onCall(tool.params);
897
+ } catch (error) {
898
+ toolResults.push({ tool, result: `Error: ${error.message}` });
899
+ continue;
900
+ }
901
+ }
902
+ const childrenPrompt = this.activateCustomToolGroup(customTool);
903
+ const finalPrompt = `# New Available Tools
904
+
905
+ The following are instructions for using the new available tools.
906
+
907
+ ${childrenPrompt}`;
908
+ const promptBlock = groupResult !== void 0 ? `${typeof groupResult === "string" ? groupResult : JSON.stringify(groupResult)}
909
+
910
+ ${finalPrompt}` : finalPrompt;
911
+ toolResults.push({ tool, result: promptBlock });
912
+ continue;
913
+ }
832
914
  if (customTool.onCall) {
833
915
  try {
834
916
  const res = await customTool.onCall(tool.params);
@@ -1089,6 +1171,27 @@ ${this.promptManager.getUsedToolResultInstructions()}`;
1089
1171
  }
1090
1172
  }
1091
1173
  }
1174
+ /**
1175
+ * 激活自定义工具集:将入口的 children 注册到活跃工具列表并返回渲染后的 prompt。
1176
+ */
1177
+ activateCustomToolGroup(group) {
1178
+ if (this.activatedGroups.has(group.name)) {
1179
+ return renderCustomToolsPrompt(group.children || [], this.runtime.env.cwd());
1180
+ }
1181
+ this.activatedGroups.add(group.name);
1182
+ this.activeCustomTools = [...this.activeCustomTools, ...group.children || []];
1183
+ this.activeToolsVersion++;
1184
+ return renderCustomToolsPrompt(group.children || [], this.runtime.env.cwd());
1185
+ }
1186
+ /**
1187
+ * 检查自上次获取 prompt 后是否有工具集被激活,若有则刷新缓存。
1188
+ */
1189
+ async getCurrentPrompt() {
1190
+ if (this.promptActiveToolsVersion !== this.activeToolsVersion) {
1191
+ return this.getPrompt(true);
1192
+ }
1193
+ return this.getPrompt();
1194
+ }
1092
1195
  /**
1093
1196
  * 简单的 Diff 解析与替换辅助方法
1094
1197
  */
@@ -1450,10 +1553,11 @@ ${context.customInstructions}
1450
1553
  if (allowDefaultTools) {
1451
1554
  useDefaultTools = defaultTools.filter((tool) => allowDefaultTools.includes(tool.name));
1452
1555
  }
1556
+ const renderedCustomTools = renderCustomToolsPrompt(customTools, context.cwd);
1453
1557
  return `# Available Tools
1454
1558
  You can use the following tools by formatting your output as XML blocks. Only use ONE tool per message, and ALWAYS wait for the user's response with the execution result before proceeding.
1455
1559
 
1456
- ${[...useDefaultTools, ...customTools].map((tool) => {
1560
+ ${[...useDefaultTools].map((tool) => {
1457
1561
  return `### ${tool.name}
1458
1562
  Description: ${tool.description}
1459
1563
  Parameters:
@@ -1466,6 +1570,8 @@ ${Object.entries(tool.params).map(([name, description]) => `<${name}>${descripti
1466
1570
  </${tool.name}>
1467
1571
  `;
1468
1572
  }).join("\n")}
1573
+ ${renderedCustomTools ? `
1574
+ ${renderedCustomTools}` : ""}
1469
1575
 
1470
1576
  # Tool Use Examples
1471
1577
  ${useDefaultTools.filter((item) => Boolean(item.example)).map((item) => item.example).join("\n")}}
@@ -1913,10 +2019,14 @@ exports.NodePromptManager = NodePromptManager;
1913
2019
  exports.READ_ONLY_TOOLS = READ_ONLY_TOOLS;
1914
2020
  exports.TOOL_RESULT_BLOCK = TOOL_RESULT_BLOCK;
1915
2021
  exports.VERSION = VERSION;
2022
+ exports.collectCustomToolNames = collectCustomToolNames;
1916
2023
  exports.createNodeAgent = createNodeAgent;
1917
2024
  exports.defaultTools = defaultTools;
1918
2025
  exports.getToolUseNames = getToolUseNames;
2026
+ exports.isCustomToolGroup = isCustomToolGroup;
1919
2027
  exports.parseAssistantMessageV2 = parseAssistantMessageV2;
2028
+ exports.renderCustomToolPrompt = renderCustomToolPrompt;
2029
+ exports.renderCustomToolsPrompt = renderCustomToolsPrompt;
1920
2030
  exports.setDynamicToolUseNames = setDynamicToolUseNames;
1921
2031
  exports.toolParamNames = toolParamNames;
1922
2032
  exports.toolUseNames = toolUseNames;