@zhin.js/agent 0.0.15 → 0.0.17

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 (45) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/lib/builtin-tools.d.ts +93 -0
  3. package/lib/builtin-tools.d.ts.map +1 -1
  4. package/lib/builtin-tools.js +358 -3
  5. package/lib/builtin-tools.js.map +1 -1
  6. package/lib/init/register-builtin-tools.d.ts.map +1 -1
  7. package/lib/init/register-builtin-tools.js +138 -2
  8. package/lib/init/register-builtin-tools.js.map +1 -1
  9. package/lib/init/register-db-models.js +3 -3
  10. package/lib/init/register-db-models.js.map +1 -1
  11. package/lib/init/register-db-upgrade.js +2 -2
  12. package/lib/init/register-db-upgrade.js.map +1 -1
  13. package/lib/init/register-management-tools.js +1 -1
  14. package/lib/init/register-management-tools.js.map +1 -1
  15. package/lib/service.d.ts +4 -8
  16. package/lib/service.d.ts.map +1 -1
  17. package/lib/service.js +23 -112
  18. package/lib/service.js.map +1 -1
  19. package/lib/subagent.js +1 -1
  20. package/lib/subagent.js.map +1 -1
  21. package/lib/zhin-agent/builtin-tools.d.ts +1 -1
  22. package/lib/zhin-agent/builtin-tools.d.ts.map +1 -1
  23. package/lib/zhin-agent/config.d.ts +8 -1
  24. package/lib/zhin-agent/config.d.ts.map +1 -1
  25. package/lib/zhin-agent/config.js +8 -1
  26. package/lib/zhin-agent/config.js.map +1 -1
  27. package/lib/zhin-agent/index.d.ts +3 -3
  28. package/lib/zhin-agent/index.d.ts.map +1 -1
  29. package/lib/zhin-agent/index.js +52 -29
  30. package/lib/zhin-agent/index.js.map +1 -1
  31. package/lib/zhin-agent/tool-collector.js +1 -1
  32. package/package.json +3 -3
  33. package/src/builtin-tools.ts +443 -3
  34. package/src/init/register-ai-trigger.ts +1 -1
  35. package/src/init/register-builtin-tools.ts +135 -2
  36. package/src/init/register-db-models.ts +3 -3
  37. package/src/init/register-db-upgrade.ts +2 -2
  38. package/src/init/register-management-tools.ts +1 -1
  39. package/src/init/register-message-recorder.ts +1 -1
  40. package/src/service.ts +28 -132
  41. package/src/subagent.ts +1 -1
  42. package/src/zhin-agent/builtin-tools.ts +1 -1
  43. package/src/zhin-agent/config.ts +10 -2
  44. package/src/zhin-agent/index.ts +51 -29
  45. package/src/zhin-agent/tool-collector.ts +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhin.js/agent",
3
- "version": "0.0.15",
3
+ "version": "0.0.17",
4
4
  "description": "Zhin AI Agent — session, ZhinAgent, init; composes @zhin.js/core providers and tools",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -14,8 +14,8 @@
14
14
  },
15
15
  "dependencies": {
16
16
  "js-yaml": "^4.1.0",
17
- "@zhin.js/ai": "1.0.13",
18
- "@zhin.js/core": "1.0.52"
17
+ "@zhin.js/ai": "1.0.15",
18
+ "@zhin.js/core": "1.0.54"
19
19
  },
20
20
  "devDependencies": {
21
21
  "@types/js-yaml": "^4.0.9",
@@ -62,7 +62,13 @@ export function collectPluginSkillSearchRoots(root: Plugin | null | undefined):
62
62
  };
63
63
  const fromPlugin = (p: Plugin) => {
64
64
  if (!p?.filePath) return;
65
- push(path.join(path.dirname(p.filePath), 'skills'));
65
+ const dir = path.dirname(p.filePath);
66
+ push(path.join(dir, 'skills'));
67
+ // Also check package root when filePath is under src/ or lib/
68
+ const dirName = path.basename(dir);
69
+ if (dirName === 'src' || dirName === 'lib') {
70
+ push(path.join(path.dirname(dir), 'skills'));
71
+ }
66
72
  };
67
73
  fromPlugin(root);
68
74
  for (const child of root.children || []) {
@@ -120,6 +126,11 @@ export interface BuiltinToolsOptions {
120
126
  * 返回额外技能根目录(每个根下为 `<skillName>/SKILL.md`),通常为已加载插件的 `.../skills`
121
127
  */
122
128
  pluginSkillRootsResolver?: () => string[];
129
+ /**
130
+ * 按名称查找 SkillFeature 中已注册技能的 filePath
131
+ * 返回 SKILL.md 的绝对路径,或 undefined 表示未找到
132
+ */
133
+ skillFileLookup?: (name: string) => string | undefined;
123
134
  }
124
135
 
125
136
  /**
@@ -129,6 +140,7 @@ export function createBuiltinTools(options?: BuiltinToolsOptions): ZhinTool[] {
129
140
  const DATA_DIR = getDataDir();
130
141
  const skillMaxChars = options?.skillInstructionMaxChars ?? 4000;
131
142
  const skillDirList = () => mergeSkillDirsWithResolver(options?.pluginSkillRootsResolver);
143
+ const skillFileLookup = options?.skillFileLookup;
132
144
 
133
145
  const tools: ZhinTool[] = [];
134
146
 
@@ -535,12 +547,19 @@ export function createBuiltinTools(options?: BuiltinToolsOptions): ZhinTool[] {
535
547
  .param('name', { type: 'string', description: '技能名称' }, true)
536
548
  .execute(async (args) => {
537
549
  try {
538
- // discoverWorkspaceSkills / getSkillSearchDirectories 顺序一致
550
+ // 优先查找 SkillFeature 中已注册技能的 filePath
551
+ const registeredPath = skillFileLookup?.(args.name);
552
+ if (registeredPath && fs.existsSync(registeredPath)) {
553
+ const fullContent = await fs.promises.readFile(registeredPath, 'utf-8');
554
+ const depWarning = await checkSkillDeps(fullContent);
555
+ const instructions = extractSkillInstructions(args.name, fullContent, skillMaxChars);
556
+ return depWarning ? `${depWarning}\n\n${instructions}` : instructions;
557
+ }
558
+ // 回退到目录扫描(与 discoverWorkspaceSkills 顺序一致)
539
559
  for (const dir of skillDirList()) {
540
560
  const skillPath = path.join(dir, args.name, 'SKILL.md');
541
561
  if (fs.existsSync(skillPath)) {
542
562
  const fullContent = await fs.promises.readFile(skillPath, 'utf-8');
543
- // 5.3 可执行环境检查:若 SKILL 声明了 deps,再次检查;缺失则在返回内容中提示
544
563
  const depWarning = await checkSkillDeps(fullContent);
545
564
  const instructions = extractSkillInstructions(args.name, fullContent, skillMaxChars);
546
565
  return depWarning ? `${depWarning}\n\n${instructions}` : instructions;
@@ -912,3 +931,424 @@ export function buildSkillsSummaryXML(skills: SkillMeta[]): string {
912
931
  lines.push('</skills>');
913
932
  return lines.join('\n');
914
933
  }
934
+
935
+ // ============================================================================
936
+ // Agent 预设发现(*.agent.md 文件)
937
+ // ============================================================================
938
+
939
+ /**
940
+ * Agent 预设元数据(从 *.agent.md frontmatter 解析)
941
+ */
942
+ export interface AgentMeta {
943
+ name: string;
944
+ description: string;
945
+ keywords?: string[];
946
+ tags?: string[];
947
+ /** frontmatter 中声明的工具名列表 */
948
+ toolNames?: string[];
949
+ /** *.agent.md 文件的绝对路径 */
950
+ filePath: string;
951
+ /** 首选模型名 */
952
+ model?: string;
953
+ /** 首选 Provider 名 */
954
+ provider?: string;
955
+ /** 最大工具调用迭代次数 */
956
+ maxIterations?: number;
957
+ }
958
+
959
+ /**
960
+ * 扫描 agents/ 目录,发现 *.agent.md 文件
961
+ * 加载顺序与 skills 一致:Workspace > ~/.zhin > data > 插件包
962
+ * 同名先发现者优先
963
+ */
964
+ export async function discoverWorkspaceAgents(root?: Plugin | null): Promise<AgentMeta[]> {
965
+ const agents: AgentMeta[] = [];
966
+ const seenNames = new Set<string>();
967
+
968
+ // 构建扫描目录:标准目录的 agents/ + 插件包的 agents/
969
+ const agentDirs: string[] = [
970
+ path.join(process.cwd(), 'agents'),
971
+ path.join(os.homedir(), '.zhin', 'agents'),
972
+ path.join(getDataDir(), 'agents'),
973
+ ];
974
+ if (root) {
975
+ const addPluginDir = (p: Plugin) => {
976
+ if (!p?.filePath) return;
977
+ const dir = path.dirname(p.filePath);
978
+ const d = path.join(dir, 'agents');
979
+ if (!agentDirs.includes(d)) agentDirs.push(d);
980
+ // Also check package root when filePath is under src/ or lib/
981
+ const dirName = path.basename(dir);
982
+ if (dirName === 'src' || dirName === 'lib') {
983
+ const d2 = path.join(path.dirname(dir), 'agents');
984
+ if (!agentDirs.includes(d2)) agentDirs.push(d2);
985
+ }
986
+ };
987
+ addPluginDir(root);
988
+ for (const child of root.children || []) {
989
+ addPluginDir(child);
990
+ }
991
+ }
992
+
993
+ for (const agentsDir of agentDirs) {
994
+ if (!fs.existsSync(agentsDir)) continue;
995
+
996
+ let entries: fs.Dirent[];
997
+ try {
998
+ entries = await fs.promises.readdir(agentsDir, { withFileTypes: true });
999
+ } catch {
1000
+ continue;
1001
+ }
1002
+
1003
+ for (const entry of entries) {
1004
+ // 支持两种结构:
1005
+ // 1. agents/<name>.agent.md(扁平文件)
1006
+ // 2. agents/<name>/<name>.agent.md(目录结构)
1007
+ let agentMdPath: string | undefined;
1008
+ if (entry.isFile() && entry.name.endsWith('.agent.md')) {
1009
+ agentMdPath = path.join(agentsDir, entry.name);
1010
+ } else if (entry.isDirectory()) {
1011
+ const nested = path.join(agentsDir, entry.name, `${entry.name}.agent.md`);
1012
+ if (fs.existsSync(nested)) {
1013
+ agentMdPath = nested;
1014
+ }
1015
+ }
1016
+ if (!agentMdPath) continue;
1017
+
1018
+ try {
1019
+ const content = await fs.promises.readFile(agentMdPath, 'utf-8');
1020
+ const match = content.match(/^---\s*\n([\s\S]*?)\n---\s*(?:\n|$)/);
1021
+ if (!match) {
1022
+ logger.debug(`Agent文件 ${agentMdPath} 没有有效的frontmatter格式`);
1023
+ continue;
1024
+ }
1025
+
1026
+ let jsYaml: any;
1027
+ try {
1028
+ jsYaml = await import('js-yaml');
1029
+ if (jsYaml.default) jsYaml = jsYaml.default;
1030
+ } catch (e) {
1031
+ logger.warn(`Unable to import js-yaml module: ${e}`);
1032
+ continue;
1033
+ }
1034
+
1035
+ const metadata = jsYaml.load(match[1]);
1036
+ if (!metadata || !metadata.name || !metadata.description) {
1037
+ logger.debug(`Agent文件 ${agentMdPath} 缺少必需的 name/description 字段`);
1038
+ continue;
1039
+ }
1040
+
1041
+ if (seenNames.has(metadata.name)) {
1042
+ logger.debug(`Agent '${metadata.name}' 已由先序目录加载,跳过: ${agentMdPath}`);
1043
+ continue;
1044
+ }
1045
+ seenNames.add(metadata.name);
1046
+
1047
+ agents.push({
1048
+ name: metadata.name,
1049
+ description: metadata.description,
1050
+ keywords: metadata.keywords || [],
1051
+ tags: metadata.tags || [],
1052
+ toolNames: Array.isArray(metadata.tools) ? metadata.tools : [],
1053
+ filePath: agentMdPath,
1054
+ model: metadata.model,
1055
+ provider: metadata.provider,
1056
+ maxIterations: typeof metadata.maxIterations === 'number' ? metadata.maxIterations : undefined,
1057
+ });
1058
+ logger.debug(`Agent发现成功: ${metadata.name}`);
1059
+ } catch (e) {
1060
+ logger.warn(`Failed to parse agent.md in ${agentMdPath}:`, e);
1061
+ }
1062
+ }
1063
+ }
1064
+
1065
+ if (agents.length > 0) {
1066
+ logger.info(`发现 ${agents.length} 个工作区 Agent 预设: ${agents.map(a => a.name).join(', ')}`);
1067
+ }
1068
+
1069
+ return agents;
1070
+ }
1071
+
1072
+ // ============================================================================
1073
+ // Tool 发现(*.tool.md 文件)
1074
+ // ============================================================================
1075
+
1076
+ /**
1077
+ * 简写参数定义(*.tool.md frontmatter 中使用)
1078
+ */
1079
+ export interface ToolParamShorthand {
1080
+ type: string;
1081
+ description?: string;
1082
+ required?: boolean;
1083
+ enum?: string[];
1084
+ default?: any;
1085
+ }
1086
+
1087
+ /**
1088
+ * Tool 元数据(从 *.tool.md frontmatter 解析)
1089
+ */
1090
+ export interface ToolMeta {
1091
+ name: string;
1092
+ description: string;
1093
+ /** 简写参数定义(frontmatter 格式) */
1094
+ parameters?: Record<string, ToolParamShorthand>;
1095
+ /** 命令配置 */
1096
+ command?: {
1097
+ pattern?: string;
1098
+ alias?: string[];
1099
+ examples?: string[];
1100
+ };
1101
+ /** 支持的平台列表 */
1102
+ platforms?: string[];
1103
+ /** 支持的场景列表 */
1104
+ scopes?: string[];
1105
+ /** 权限级别 */
1106
+ permissionLevel?: string;
1107
+ /** 标签 */
1108
+ tags?: string[];
1109
+ /** 触发关键词 */
1110
+ keywords?: string[];
1111
+ /** 工具分类 */
1112
+ kind?: string;
1113
+ /** 是否隐藏 */
1114
+ hidden?: boolean;
1115
+ /** handler 文件路径(相对于 .tool.md) */
1116
+ handler?: string;
1117
+ /** *.tool.md 文件的绝对路径 */
1118
+ filePath: string;
1119
+ /** body 内容(无 handler 时作为 prompt 模板) */
1120
+ templateBody?: string;
1121
+ }
1122
+
1123
+ /**
1124
+ * 从根插件树收集:根插件与直接子插件包目录下的 `tools/`
1125
+ */
1126
+ export function collectPluginToolSearchRoots(root: Plugin | null | undefined): string[] {
1127
+ if (!root) return [];
1128
+ const dirs: string[] = [];
1129
+ const push = (d: string) => {
1130
+ if (d && !dirs.includes(d)) dirs.push(d);
1131
+ };
1132
+ const fromPlugin = (p: Plugin) => {
1133
+ if (!p?.filePath) return;
1134
+ const dir = path.dirname(p.filePath);
1135
+ push(path.join(dir, 'tools'));
1136
+ // Also check package root when filePath is under src/ or lib/
1137
+ const dirName = path.basename(dir);
1138
+ if (dirName === 'src' || dirName === 'lib') {
1139
+ push(path.join(path.dirname(dir), 'tools'));
1140
+ }
1141
+ };
1142
+ fromPlugin(root);
1143
+ for (const child of root.children || []) {
1144
+ fromPlugin(child);
1145
+ }
1146
+ return dirs;
1147
+ }
1148
+
1149
+ /**
1150
+ * 获取所有 tool 搜索目录(标准目录 + 插件包 tools/)
1151
+ */
1152
+ export function getToolSearchDirectories(root?: Plugin | null): string[] {
1153
+ const list = [
1154
+ path.join(process.cwd(), 'tools'),
1155
+ path.join(os.homedir(), '.zhin', 'tools'),
1156
+ path.join(getDataDir(), 'tools'),
1157
+ ];
1158
+ for (const d of collectPluginToolSearchRoots(root ?? undefined)) {
1159
+ if (!list.includes(d)) list.push(d);
1160
+ }
1161
+ return list;
1162
+ }
1163
+
1164
+ /**
1165
+ * 将简写参数定义转换为 ToolParametersSchema
1166
+ */
1167
+ function shorthandToSchema(params: Record<string, ToolParamShorthand>): import('@zhin.js/core').ToolParametersSchema {
1168
+ const properties: Record<string, any> = {};
1169
+ const required: string[] = [];
1170
+ for (const [key, param] of Object.entries(params)) {
1171
+ properties[key] = {
1172
+ type: param.type || 'string',
1173
+ description: param.description || key,
1174
+ };
1175
+ if (param.enum) properties[key].enum = param.enum;
1176
+ if (param.default !== undefined) properties[key].default = param.default;
1177
+ if (param.required) required.push(key);
1178
+ }
1179
+ return { type: 'object', properties, required: required.length > 0 ? required : undefined };
1180
+ }
1181
+
1182
+ /**
1183
+ * 加载 handler 文件(动态 import)
1184
+ * @returns execute 函数, 或 undefined(加载失败)
1185
+ */
1186
+ async function loadToolHandler(handlerPath: string, toolMdPath: string): Promise<((args: any, context?: any) => any) | undefined> {
1187
+ const resolved = path.resolve(path.dirname(toolMdPath), handlerPath);
1188
+ if (!fs.existsSync(resolved)) {
1189
+ logger.warn(`Tool handler 文件不存在: ${resolved}`);
1190
+ return undefined;
1191
+ }
1192
+ try {
1193
+ const fileUrl = `file://${resolved}?t=${Date.now()}`;
1194
+ const mod = await import(fileUrl);
1195
+ const fn = mod.default || mod;
1196
+ if (typeof fn !== 'function') {
1197
+ logger.warn(`Tool handler 未导出函数: ${resolved}`);
1198
+ return undefined;
1199
+ }
1200
+ return fn;
1201
+ } catch (e) {
1202
+ logger.warn(`Tool handler 加载失败 (${resolved}): ${errMsg(e)}`);
1203
+ return undefined;
1204
+ }
1205
+ }
1206
+
1207
+ /**
1208
+ * 从 body 构建 prompt 模板执行函数
1209
+ */
1210
+ function buildTemplateExecute(body: string): (args: Record<string, any>) => string {
1211
+ return (args: Record<string, any>) => body.replace(/\{\{(\w+)\}\}/g, (_, k) => {
1212
+ const val = args[k];
1213
+ return val !== undefined && val !== null ? String(val) : '';
1214
+ });
1215
+ }
1216
+
1217
+ /**
1218
+ * 扫描 tools/ 目录,发现 *.tool.md 文件
1219
+ * 加载顺序与 skills/agents 一致:Workspace > ~/.zhin > data > 插件包
1220
+ * 同名先发现者优先
1221
+ */
1222
+ export async function discoverWorkspaceTools(root?: Plugin | null): Promise<ToolMeta[]> {
1223
+ const tools: ToolMeta[] = [];
1224
+ const seenNames = new Set<string>();
1225
+ const toolDirs = getToolSearchDirectories(root);
1226
+
1227
+ for (const toolsDir of toolDirs) {
1228
+ if (!fs.existsSync(toolsDir)) continue;
1229
+
1230
+ let entries: fs.Dirent[];
1231
+ try {
1232
+ entries = await fs.promises.readdir(toolsDir, { withFileTypes: true });
1233
+ } catch {
1234
+ continue;
1235
+ }
1236
+
1237
+ for (const entry of entries) {
1238
+ // 支持两种结构:
1239
+ // 1. tools/<name>.tool.md(扁平文件)
1240
+ // 2. tools/<name>/<name>.tool.md(目录结构,允许放 handler.ts)
1241
+ let toolMdPath: string | undefined;
1242
+ if (entry.isFile() && entry.name.endsWith('.tool.md')) {
1243
+ toolMdPath = path.join(toolsDir, entry.name);
1244
+ } else if (entry.isDirectory()) {
1245
+ const nested = path.join(toolsDir, entry.name, `${entry.name}.tool.md`);
1246
+ if (fs.existsSync(nested)) {
1247
+ toolMdPath = nested;
1248
+ }
1249
+ }
1250
+ if (!toolMdPath) continue;
1251
+
1252
+ try {
1253
+ const content = await fs.promises.readFile(toolMdPath, 'utf-8');
1254
+ const match = content.match(/^---\s*\n([\s\S]*?)\n---\s*(?:\n|$)/);
1255
+ if (!match) {
1256
+ logger.debug(`Tool文件 ${toolMdPath} 没有有效的frontmatter格式`);
1257
+ continue;
1258
+ }
1259
+
1260
+ let jsYaml: any;
1261
+ try {
1262
+ jsYaml = await import('js-yaml');
1263
+ if (jsYaml.default) jsYaml = jsYaml.default;
1264
+ } catch (e) {
1265
+ logger.warn(`Unable to import js-yaml module: ${e}`);
1266
+ continue;
1267
+ }
1268
+
1269
+ const metadata = jsYaml.load(match[1]);
1270
+ if (!metadata || !metadata.name || !metadata.description) {
1271
+ logger.debug(`Tool文件 ${toolMdPath} 缺少必需的 name/description 字段`);
1272
+ continue;
1273
+ }
1274
+
1275
+ if (seenNames.has(metadata.name)) {
1276
+ logger.debug(`Tool '${metadata.name}' 已由先序目录加载,跳过: ${toolMdPath}`);
1277
+ continue;
1278
+ }
1279
+ seenNames.add(metadata.name);
1280
+
1281
+ // 提取 body(frontmatter 之后的内容)
1282
+ const body = content.replace(/^---\s*\n[\s\S]*?\n---\s*(?:\n|$)/, '').trim();
1283
+
1284
+ tools.push({
1285
+ name: metadata.name,
1286
+ description: metadata.description,
1287
+ parameters: metadata.parameters || undefined,
1288
+ command: metadata.command || undefined,
1289
+ platforms: metadata.platforms,
1290
+ scopes: metadata.scopes,
1291
+ permissionLevel: metadata.permissionLevel,
1292
+ tags: metadata.tags || [],
1293
+ keywords: metadata.keywords || [],
1294
+ kind: metadata.kind,
1295
+ hidden: metadata.hidden,
1296
+ handler: metadata.handler,
1297
+ filePath: toolMdPath,
1298
+ templateBody: !metadata.handler && body ? body : undefined,
1299
+ });
1300
+ logger.debug(`Tool发现成功: ${metadata.name}`);
1301
+ } catch (e) {
1302
+ logger.warn(`Failed to parse tool.md in ${toolMdPath}:`, e);
1303
+ }
1304
+ }
1305
+ }
1306
+
1307
+ if (tools.length > 0) {
1308
+ logger.info(`发现 ${tools.length} 个工作区 Tool: ${tools.map(t => t.name).join(', ')}`);
1309
+ }
1310
+
1311
+ return tools;
1312
+ }
1313
+
1314
+ /**
1315
+ * 将 ToolMeta 转换为 Tool 对象(包含 execute 函数)
1316
+ */
1317
+ export async function buildToolFromMeta(meta: ToolMeta): Promise<import('@zhin.js/core').Tool | null> {
1318
+ // 构建 execute 函数
1319
+ let execute: ((args: any, context?: any) => any) | undefined;
1320
+
1321
+ if (meta.handler) {
1322
+ execute = await loadToolHandler(meta.handler, meta.filePath);
1323
+ if (!execute) return null;
1324
+ } else if (meta.templateBody) {
1325
+ execute = buildTemplateExecute(meta.templateBody);
1326
+ } else {
1327
+ logger.warn(`Tool '${meta.name}' 既没有 handler 也没有模板 body,跳过`);
1328
+ return null;
1329
+ }
1330
+
1331
+ // 构建参数 schema
1332
+ const parameters = meta.parameters
1333
+ ? shorthandToSchema(meta.parameters)
1334
+ : { type: 'object' as const, properties: {} };
1335
+
1336
+ return {
1337
+ name: meta.name,
1338
+ description: meta.description,
1339
+ parameters,
1340
+ execute,
1341
+ tags: meta.tags,
1342
+ keywords: meta.keywords,
1343
+ platforms: meta.platforms,
1344
+ scopes: meta.scopes as any,
1345
+ permissionLevel: meta.permissionLevel as any,
1346
+ hidden: meta.hidden,
1347
+ kind: meta.kind,
1348
+ command: meta.command ? {
1349
+ pattern: meta.command.pattern,
1350
+ alias: meta.command.alias,
1351
+ examples: meta.command.examples,
1352
+ } : undefined,
1353
+ };
1354
+ }
@@ -5,7 +5,7 @@ import './types.js';
5
5
  import { getPlugin, Message, shouldTriggerAI, inferSenderPermissions, parseRichMediaContent, mergeAITriggerConfig } from '@zhin.js/core';
6
6
  import type { Tool, ToolContext } from '@zhin.js/core';
7
7
  import type { ContentPart } from '@zhin.js/core';
8
- import type { OutputElement } from '../output.js';
8
+ import type { OutputElement } from '@zhin.js/ai';
9
9
  import type { AIServiceRefs } from './shared-refs.js';
10
10
 
11
11
  /**