foliko 1.1.6 → 1.1.7

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 (79) hide show
  1. package/.agent/data/email/processed-emails.json +1 -0
  2. package/.agent/data/plugins-state.json +5 -1
  3. package/.agent/data/web/web-config.json +5 -0
  4. package/.agent/memory/feedback/mnt7jrlt-d67qs7.md +15 -0
  5. package/.agent/memory/feedback/mnt88ja3-al4fuy.md +9 -0
  6. package/.agent/plugins/test-plugin.py +108 -0
  7. package/.agent/sessions/cli_default.json +514 -5298
  8. package/.claude/settings.local.json +2 -1
  9. package/SPEC.md +735 -696
  10. package/output/zen_silence.png +0 -0
  11. package/package.json +2 -2
  12. package/plugins/ambient-agent/EventWatcher.js +33 -37
  13. package/plugins/ambient-agent/ExplorerLoop.js +338 -36
  14. package/plugins/ambient-agent/GoalManager.js +7 -3
  15. package/plugins/ambient-agent/StateStore.js +30 -1
  16. package/plugins/ambient-agent/constants.js +15 -1
  17. package/plugins/ambient-agent/index.js +26 -33
  18. package/plugins/coordinator-plugin.js +3 -3
  19. package/plugins/default-plugins.js +2 -2
  20. package/plugins/email/index.js +150 -36
  21. package/plugins/email/monitor.js +79 -5
  22. package/plugins/email/reply.js +15 -25
  23. package/plugins/extension-executor-plugin.js +160 -31
  24. package/plugins/file-system-plugin.js +57 -24
  25. package/plugins/memory-plugin.js +176 -64
  26. package/plugins/python-plugin-loader.js +79 -9
  27. package/plugins/scheduler-plugin.js +64 -24
  28. package/plugins/think-plugin.js +7 -2
  29. package/plugins/web-plugin.js +263 -4
  30. package/skills/ambient-agent/SKILL.md +342 -314
  31. package/src/core/agent-chat.js +64 -9
  32. package/src/core/agent.js +118 -59
  33. package/src/core/tool-registry.js +5 -5
  34. package/src/executors/mcp-executor.js +188 -26
  35. package/src/utils/id.js +5 -0
  36. package/system.md +3480 -0
  37. package/.agent/data/ambient/goals.json +0 -50
  38. package/.agent/data/ambient/memories.json +0 -7
  39. package/.agent/memory/core.md +0 -1
  40. package/.agent/memory/feedback/mnrsiuoc-e1ru74.md +0 -9
  41. package/.agent/memory/feedback/mnrt2mmz-98az6n.md +0 -9
  42. package/.agent/memory/feedback/mnrtqrhm-kxsicz.md +0 -9
  43. package/.agent/memory/feedback/mnrts8vg-i0ngzp.md +0 -15
  44. package/.agent/memory/feedback/mnrtt7jt-c0trb2.md +0 -9
  45. package/.agent/memory/feedback/mnruc2f0-5s52la.md +0 -16
  46. package/.agent/memory/feedback/mnrumbmx-63sa0v.md +0 -9
  47. package/.agent/memory/project/mnn93ogy-ypjn27.md +0 -9
  48. package/.agent/memory/project/mnn98fqy-5nhc1u.md +0 -25
  49. package/.agent/memory/project/mnrp7p5n-8enm2a.md +0 -31
  50. package/.agent/memory/project/mnrp9ifb-yynks0.md +0 -40
  51. package/.agent/memory/project/mnrpb3b8-f617s4.md +0 -25
  52. package/.agent/memory/project/mnrrmqgg-focprv.md +0 -9
  53. package/.agent/memory/project/mnrtykbh-6atsor.md +0 -9
  54. package/.agent/memory/project/mnru9jiu-kgau16.md +0 -35
  55. package/.agent/memory/reference/mnq3oenw-46haj6.md +0 -63
  56. package/.agent/memory/reference/mnq5qxm2-mjoooh.md +0 -116
  57. package/.agent/memory/reference/mnrnvpwo-rcqv9m.md +0 -52
  58. package/.agent/memory/reference/mnrovxvz-zy9xqm.md +0 -25
  59. package/.agent/memory/reference/mnroxabj-1b3930.md +0 -68
  60. package/.agent/memory/reference/mnrpjtlp-mnb9od.md +0 -35
  61. package/.agent/memory/reference/mnrps1x3-6b8xfm.md +0 -28
  62. package/.agent/memory/reference/mnrpt9ov-15er5w.md +0 -22
  63. package/.agent/memory/reference/mnrq82dn-y9tv9e.md +0 -50
  64. package/.agent/memory/reference/mnrqnr5v-v75drf.md +0 -34
  65. package/.agent/memory/reference/mnrrfzys-urudaf.md +0 -31
  66. package/.agent/memory/reference/mnrrocha-t0027n.md +0 -21
  67. package/.agent/memory/reference/mnrukklc-bxndsb.md +0 -35
  68. package/.agent/memory/user/mnm67t9m-x8rekk.md +0 -9
  69. package/.agent/memory/user/mnn5mmqh-w6aktx.md +0 -11
  70. package/.agent/memory/user/mnnbfhhn-dk1bd1.md +0 -22
  71. package/.agent/memory/user/mnrt39t8-8eosy0.md +0 -9
  72. package/foliko-cloud-rising.png +0 -0
  73. package/foliko-dawn-of-ai.png +0 -0
  74. package/foliko-mindful-observation.png +0 -0
  75. package/foliko-stellar-dreams.png +0 -0
  76. package/foliko-zen-jing.png +0 -0
  77. package/foliko-zen-kong.png +0 -0
  78. package/foliko-zen-wu.png +0 -0
  79. package/zen_karesansui.png +0 -0
@@ -10,7 +10,7 @@ const path = require('path');
10
10
  const { z } = require('zod');
11
11
  const { createMCPClient } = require('@ai-sdk/mcp');
12
12
  const { StdioClientTransport } = require('@modelcontextprotocol/sdk/client/stdio.js');
13
- const { zodSchemaToTable } = require('@chnak/zod-to-markdown');
13
+ const { zodSchemaToMarkdown } = require('@chnak/zod-to-markdown');
14
14
  const { logger } = require('../utils/logger');
15
15
 
16
16
  const log = logger.child('MCPExecutor');
@@ -193,7 +193,7 @@ class MCPClientWrapper {
193
193
  class MCPExecutorPlugin extends Plugin {
194
194
  constructor(config = {}) {
195
195
  super();
196
- this.name = 'mcp-executor';
196
+ this.name = 'mcp';
197
197
  this.version = '1.0.0';
198
198
  this.description = 'MCP (Model Context Protocol) 执行器';
199
199
  this.priority = 11;
@@ -203,6 +203,9 @@ class MCPExecutorPlugin extends Plugin {
203
203
  // serverName -> { client, tools: [{ name, description, inputSchema }], toolObjects: { toolName: actualTool } }
204
204
  this._clients = new Map();
205
205
  this._config = config;
206
+ // 注册的工具对象(extension-executor 会扫描这个)
207
+ // 格式: { 'server_toolname': { name, description, inputSchema, execute } }
208
+ this.tools = {};
206
209
  }
207
210
 
208
211
  install(framework) {
@@ -520,6 +523,8 @@ class MCPExecutorPlugin extends Plugin {
520
523
  if (!inputSchema) return {};
521
524
  // 处理 {jsonSchema: {...}} 格式
522
525
  if (inputSchema.jsonSchema) return inputSchema.jsonSchema;
526
+ // 处理 {inputSchema: {...}} 格式 (某些 MCP 服务器返回这种格式)
527
+ if (inputSchema.inputSchema) return inputSchema.inputSchema;
523
528
  // 处理直接是 schema 的格式
524
529
  return inputSchema;
525
530
  }
@@ -532,49 +537,71 @@ class MCPExecutorPlugin extends Plugin {
532
537
  return '';
533
538
  }
534
539
 
535
- let desc = '【MCP Servers】 工具合集\n\n';
536
- desc += '你可以通过 `mcp_call` 工具调用以下 MCP 服务器的工具。\n\n';
540
+ let desc = '## 【MCP Servers】 工具合集\n\n';
541
+ desc += 'MCP 服务器工具已注册为 `服务器_工具名` 格式(如 github_search)。\n';
542
+ desc += '通过 `ext_call` 调用:\n\n';
537
543
 
538
544
  for (const [serverName, info] of this._clients) {
539
545
  desc += `### ${serverName}\n\n`;
540
546
  for (const tool of info.tools) {
541
- desc += `#### ${tool.name}\n`;
542
- desc += `${tool.description || '无描述'}\n\n`;
547
+ const fullName = `${serverName}_${tool.name}`;
548
+ desc += `- **${fullName}**: ${tool.description || '无描述'}\n`;
543
549
 
544
550
  // 使用 zodSchemaToMarkdown 生成参数文档
545
- const schema = tool.inputSchema;
551
+ const rawSchema = tool.inputSchema;
552
+ const schema = this._extractSchema(rawSchema);
546
553
  if (schema) {
547
554
  try {
548
- if (typeof schema.toJSON === 'function') {
555
+ let schemaResult = null;
556
+ let zodSchemaForFallback = null; // 保存 Zod schema 供 fallback 使用
557
+ // 检查是否是 Zod schema (有 shape 方法或 _def 属性)
558
+ const isZodSchema =
559
+ typeof schema.shape === 'function' || (schema._def && schema._def.typeName);
560
+ if (isZodSchema) {
549
561
  // Zod schema 直接转换
550
- desc += `**参数:**\n\n`;
551
- desc += zodSchemaToTable(schema) + '\n\n';
562
+ schemaResult = zodSchemaToMarkdown(schema);
563
+ zodSchemaForFallback = schema;
552
564
  } else if (schema.jsonSchema) {
553
565
  // JSON Schema 格式,尝试转换为 Zod schema
554
566
  const zodSchema = this._jsonSchemaToZod(schema.jsonSchema || schema);
555
567
  if (zodSchema) {
556
- desc += `**参数:**\n\n`;
557
- desc += zodSchemaToTable(zodSchema) + '\n\n';
568
+ schemaResult = zodSchemaToMarkdown(zodSchema);
569
+ zodSchemaForFallback = zodSchema;
558
570
  }
559
571
  } else if (schema.properties) {
560
572
  // 已经是对象格式
561
573
  const zodSchema = this._jsonSchemaToZod(schema);
562
574
  if (zodSchema) {
575
+ schemaResult = zodSchemaToMarkdown(zodSchema);
576
+ zodSchemaForFallback = zodSchema;
577
+ }
578
+ }
579
+
580
+ // 检查是否包含未解析的原始 Zod 类型名或只有类型信息没有参数
581
+ if (schemaResult) {
582
+ const hasUnparsedTypes = /\|.*\bZod\w+\b.*\|/.test(schemaResult);
583
+ // 检查是否只有类型信息而没有实际参数(如 "Type: Object" 或 "Type: ZodAny")
584
+ const hasOnlyType =
585
+ /^-\s+\w+:\s+.+\n?$/.test(schemaResult.trim()) && !schemaResult.includes('`');
586
+ if (hasUnparsedTypes || hasOnlyType) {
587
+ // zodSchemaToMarkdown 未正确解析,使用 fallback
588
+ desc += this._fallbackParamsDesc(zodSchemaForFallback || schema);
589
+ } else {
563
590
  desc += `**参数:**\n\n`;
564
- desc += zodSchemaToTable(zodSchema) + '\n\n';
591
+ desc += schemaResult + '\n\n';
565
592
  }
566
593
  }
567
594
  } catch (e) {
568
595
  // 如果转换失败,使用简化格式
569
- desc += this._fallbackParamsDesc(schema);
596
+ desc += this._fallbackParamsDesc(zodSchemaForFallback || schema);
570
597
  }
571
598
  }
572
599
  }
573
- desc += '---\n\n';
600
+ desc += '\n';
574
601
  }
575
602
 
576
603
  desc += '**调用格式:**\n';
577
- desc += '```\nmcp_call({ server: "服务器", tool: "工具", args_json: \'{"参数": "值"}\' })\n';
604
+ desc += '```\next_call({ plugin: "mcp", tool: "服务器_工具名", args: {参数} })\n';
578
605
  desc += '```\n';
579
606
  return desc.trim();
580
607
  }
@@ -648,21 +675,126 @@ class MCPExecutorPlugin extends Plugin {
648
675
  * 回退的参数描述(当 zodSchemaToMarkdown 失败时)
649
676
  */
650
677
  _fallbackParamsDesc(schema) {
678
+ // 优先尝试 JSON Schema 格式
651
679
  const props = schema.properties || {};
652
680
  const required = schema.required || [];
653
681
 
654
- if (Object.keys(props).length === 0) {
655
- return '';
682
+ if (Object.keys(props).length > 0) {
683
+ let desc = '**参数:**\n\n';
684
+ for (const [key, prop] of Object.entries(props)) {
685
+ const isRequired = required.includes(key);
686
+ const type = prop.type || 'any';
687
+ const desc_text = prop.description || '';
688
+ desc += `- \`${key}\`${isRequired ? ' (必填)' : ''}: ${type} ${desc_text}\n`;
689
+ }
690
+ return desc + '\n';
656
691
  }
657
692
 
658
- let desc = '**参数:**\n\n';
659
- for (const [key, prop] of Object.entries(props)) {
660
- const isRequired = required.includes(key);
661
- const type = prop.type || 'any';
662
- const desc_text = prop.description || '';
663
- desc += `- \`${key}\`${isRequired ? ' (必填)' : ''}: ${type} ${desc_text}\n`;
693
+ // 尝试 Zod schema 格式
694
+ if (typeof schema.shape === 'function' || (schema._def && schema._def.shape)) {
695
+ const shape = typeof schema.shape === 'function' ? schema.shape() : schema._def.shape();
696
+ if (shape && typeof shape === 'object') {
697
+ let desc = '**参数:**\n\n';
698
+ for (const [key, field] of Object.entries(shape)) {
699
+ const typeInfo = this._extractZodFieldType(field);
700
+ const isOptional = typeInfo.isOptional ? ' (可选)' : ' (必填)';
701
+ desc += `- \`${key}\`${isOptional}: ${typeInfo.type}\n`;
702
+ }
703
+ return desc + '\n';
704
+ }
705
+ }
706
+
707
+ return '';
708
+ }
709
+
710
+ /**
711
+ * 从 Zod schema 字段提取类型信息
712
+ */
713
+ _extractZodFieldType(field) {
714
+ const typeName = field._def?.typeName || field.constructor?.name || '';
715
+ const description = field.description || field._def?.description || '';
716
+
717
+ switch (typeName) {
718
+ case 'ZodOptional': {
719
+ const inner = field._def.innerType;
720
+ return this._extractZodFieldType(inner);
721
+ }
722
+ case 'ZodArray': {
723
+ const innerInfo = this._extractZodFieldType(field._def.type);
724
+ return { type: `${innerInfo.type}[]`, isOptional: false, description };
725
+ }
726
+ case 'ZodObject': {
727
+ const shape = field._def.shape();
728
+ const props = Object.keys(shape).join(', ');
729
+ return { type: `object{${props}}`, isOptional: false, description };
730
+ }
731
+ case 'ZodString':
732
+ return { type: 'string', isOptional: false, description };
733
+ case 'ZodNumber':
734
+ return { type: 'number', isOptional: false, description };
735
+ case 'ZodBoolean':
736
+ return { type: 'boolean', isOptional: false, description };
737
+ case 'ZodEnum':
738
+ return {
739
+ type: field._def.values.map((v) => `"${v}"`).join(' | '),
740
+ isOptional: false,
741
+ description,
742
+ };
743
+ case 'ZodUnion': {
744
+ const types = field._def.options.map((opt) => this._extractZodFieldType(opt).type);
745
+ return { type: `union(${types.join(' | ')})`, isOptional: false, description };
746
+ }
747
+ case 'ZodLiteral':
748
+ return { type: JSON.stringify(field._def.value), isOptional: false, description };
749
+ case 'ZodRecord': {
750
+ const keyType = this._extractZodFieldType(field._def.keyType).type;
751
+ const valueType = this._extractZodFieldType(field._def.valueType).type;
752
+ return { type: `record<${keyType}, ${valueType}>`, isOptional: false, description };
753
+ }
754
+ case 'ZodMap': {
755
+ const keyType = this._extractZodFieldType(field._def.keyType).type;
756
+ const valueType = this._extractZodFieldType(field._def.valueType).type;
757
+ return { type: `map<${keyType}, ${valueType}>`, isOptional: false, description };
758
+ }
759
+ case 'ZodSet': {
760
+ const valueType = this._extractZodFieldType(field._def.valueType).type;
761
+ return { type: `set<${valueType}>`, isOptional: false, description };
762
+ }
763
+ case 'ZodAny':
764
+ return { type: 'any', isOptional: false, description };
765
+ case 'ZodUnknown':
766
+ return { type: 'unknown', isOptional: false, description };
767
+ case 'ZodNever':
768
+ return { type: 'never', isOptional: false, description };
769
+ case 'ZodNull':
770
+ return { type: 'null', isOptional: false, description };
771
+ case 'ZodUndefined':
772
+ return { type: 'undefined', isOptional: false, description };
773
+ case 'ZodDate':
774
+ return { type: 'date', isOptional: false, description };
775
+ case 'ZodBigInt':
776
+ return { type: 'bigint', isOptional: false, description };
777
+ case 'ZodFunction':
778
+ return { type: 'function', isOptional: false, description };
779
+ case 'ZodLazy':
780
+ return { type: 'lazy', isOptional: false, description };
781
+ case 'ZodNativeEnum':
782
+ return { type: 'nativeEnum', isOptional: false, description };
783
+ case 'ZodDefault': {
784
+ const innerInfo = this._extractZodFieldType(field._def.innerType);
785
+ return { type: innerInfo.type, isOptional: false, description };
786
+ }
787
+ case 'ZodEffects':
788
+ return { type: 'effects', isOptional: false, description };
789
+ case 'ZodPipeline':
790
+ return { type: 'pipeline', isOptional: false, description };
791
+ default:
792
+ return {
793
+ type: typeName.replace('Zod', '').toLowerCase() || 'any',
794
+ isOptional: false,
795
+ description,
796
+ };
664
797
  }
665
- return desc + '\n';
666
798
  }
667
799
 
668
800
  _getParentAgent() {
@@ -765,6 +897,22 @@ class MCPExecutorPlugin extends Plugin {
765
897
  description: tool.description || '',
766
898
  inputSchema: tool.inputSchema || {},
767
899
  });
900
+
901
+ // 注册为 server_toolname 格式,供 ext_call 使用
902
+ const registeredName = `${name}_${toolName}`;
903
+ this.tools[registeredName] = {
904
+ name: registeredName,
905
+ description: `[${name}] ${tool.description || ''}`,
906
+ inputSchema: tool.inputSchema || {},
907
+ execute: async (args) => {
908
+ // 路由到 mcp_call
909
+ return await this._framework.executeTool('mcp_call', {
910
+ server: name,
911
+ tool: toolName,
912
+ args_json: JSON.stringify(args || {}),
913
+ });
914
+ },
915
+ };
768
916
  }
769
917
  }
770
918
 
@@ -775,7 +923,13 @@ class MCPExecutorPlugin extends Plugin {
775
923
  toolObjects, // 实际工具对象,供 mcp_call 直接调用
776
924
  });
777
925
 
778
- log.info(` Added server '${name}' with ${toolsInfo.length} tools`);
926
+ log.info(
927
+ ` Added server '${name}' with ${toolsInfo.length} tools (ext_call names: ${Object.keys(
928
+ this.tools
929
+ )
930
+ .filter((k) => k.startsWith(name + '_'))
931
+ .join(', ')})`
932
+ );
779
933
  }
780
934
 
781
935
  /**
@@ -796,6 +950,14 @@ class MCPExecutorPlugin extends Plugin {
796
950
  } catch (e) {
797
951
  // ignore
798
952
  }
953
+
954
+ // 清理已注册的工具
955
+ for (const toolName of Object.keys(this.tools)) {
956
+ if (toolName.startsWith(name + '_')) {
957
+ delete this.tools[toolName];
958
+ }
959
+ }
960
+
799
961
  this._clients.delete(name);
800
962
  }
801
963
  }
package/src/utils/id.js CHANGED
@@ -130,4 +130,9 @@ module.exports = {
130
130
  messageId,
131
131
  ruleId,
132
132
  resetSnowflake,
133
+ // 通用 ID 生成器(向后兼容)
134
+ generateId: () => {
135
+ const random = crypto.randomBytes(8).toString('base64url');
136
+ return `id_${Date.now()}_${random}`;
137
+ },
133
138
  };