@zhin.js/agent 0.0.0 → 0.0.1

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 (139) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +226 -0
  3. package/lib/agent.d.ts +9 -7
  4. package/lib/agent.d.ts.map +1 -1
  5. package/lib/agent.js +63 -29
  6. package/lib/agent.js.map +1 -1
  7. package/lib/bootstrap.js +1 -1
  8. package/lib/bootstrap.js.map +1 -1
  9. package/lib/builtin-tools.d.ts.map +1 -1
  10. package/lib/builtin-tools.js +34 -31
  11. package/lib/builtin-tools.js.map +1 -1
  12. package/lib/compaction.js +1 -1
  13. package/lib/compaction.js.map +1 -1
  14. package/lib/context-manager.js +1 -1
  15. package/lib/context-manager.js.map +1 -1
  16. package/lib/conversation-memory.d.ts +11 -0
  17. package/lib/conversation-memory.d.ts.map +1 -1
  18. package/lib/conversation-memory.js +39 -1
  19. package/lib/conversation-memory.js.map +1 -1
  20. package/lib/cron-engine.d.ts.map +1 -1
  21. package/lib/cron-engine.js +5 -3
  22. package/lib/cron-engine.js.map +1 -1
  23. package/lib/follow-up.js +1 -1
  24. package/lib/follow-up.js.map +1 -1
  25. package/lib/hooks.js +1 -1
  26. package/lib/hooks.js.map +1 -1
  27. package/lib/index.d.ts +2 -0
  28. package/lib/index.d.ts.map +1 -1
  29. package/lib/index.js +1 -0
  30. package/lib/index.js.map +1 -1
  31. package/lib/init/create-zhin-agent.d.ts +3 -0
  32. package/lib/init/create-zhin-agent.d.ts.map +1 -0
  33. package/lib/init/create-zhin-agent.js +127 -0
  34. package/lib/init/create-zhin-agent.js.map +1 -0
  35. package/lib/init/register-ai-service.d.ts +7 -0
  36. package/lib/init/register-ai-service.d.ts.map +1 -0
  37. package/lib/init/register-ai-service.js +42 -0
  38. package/lib/init/register-ai-service.js.map +1 -0
  39. package/lib/init/register-ai-trigger.d.ts +7 -0
  40. package/lib/init/register-ai-trigger.d.ts.map +1 -0
  41. package/lib/init/register-ai-trigger.js +163 -0
  42. package/lib/init/register-ai-trigger.js.map +1 -0
  43. package/lib/init/register-builtin-tools.d.ts +3 -0
  44. package/lib/init/register-builtin-tools.d.ts.map +1 -0
  45. package/lib/init/register-builtin-tools.js +179 -0
  46. package/lib/init/register-builtin-tools.js.map +1 -0
  47. package/lib/init/register-db-models.d.ts +2 -0
  48. package/lib/init/register-db-models.d.ts.map +1 -0
  49. package/lib/init/register-db-models.js +28 -0
  50. package/lib/init/register-db-models.js.map +1 -0
  51. package/lib/init/register-db-upgrade.d.ts +10 -0
  52. package/lib/init/register-db-upgrade.d.ts.map +1 -0
  53. package/lib/init/register-db-upgrade.js +67 -0
  54. package/lib/init/register-db-upgrade.js.map +1 -0
  55. package/lib/init/register-management-tools.d.ts +6 -0
  56. package/lib/init/register-management-tools.d.ts.map +1 -0
  57. package/lib/init/register-management-tools.js +68 -0
  58. package/lib/init/register-management-tools.js.map +1 -0
  59. package/lib/init/register-message-recorder.d.ts +3 -0
  60. package/lib/init/register-message-recorder.d.ts.map +1 -0
  61. package/lib/init/register-message-recorder.js +27 -0
  62. package/lib/init/register-message-recorder.js.map +1 -0
  63. package/lib/init/register-tool-service.d.ts +2 -0
  64. package/lib/init/register-tool-service.d.ts.map +1 -0
  65. package/lib/init/register-tool-service.js +9 -0
  66. package/lib/init/register-tool-service.js.map +1 -0
  67. package/lib/init/shared-refs.d.ts +14 -0
  68. package/lib/init/shared-refs.d.ts.map +1 -0
  69. package/lib/init/shared-refs.js +7 -0
  70. package/lib/init/shared-refs.js.map +1 -0
  71. package/lib/init/types.d.ts +15 -0
  72. package/lib/init/types.d.ts.map +1 -0
  73. package/lib/init/types.js +7 -0
  74. package/lib/init/types.js.map +1 -0
  75. package/lib/init.d.ts +14 -17
  76. package/lib/init.d.ts.map +1 -1
  77. package/lib/init.js +34 -670
  78. package/lib/init.js.map +1 -1
  79. package/lib/rate-limiter.js +1 -1
  80. package/lib/rate-limiter.js.map +1 -1
  81. package/lib/service.js +2 -2
  82. package/lib/service.js.map +1 -1
  83. package/lib/session.d.ts +7 -0
  84. package/lib/session.d.ts.map +1 -1
  85. package/lib/session.js +26 -4
  86. package/lib/session.js.map +1 -1
  87. package/lib/storage.d.ts +68 -0
  88. package/lib/storage.d.ts.map +1 -0
  89. package/lib/storage.js +105 -0
  90. package/lib/storage.js.map +1 -0
  91. package/lib/subagent.js +1 -1
  92. package/lib/subagent.js.map +1 -1
  93. package/lib/tools.d.ts.map +1 -1
  94. package/lib/tools.js +8 -9
  95. package/lib/tools.js.map +1 -1
  96. package/lib/user-profile.js +1 -1
  97. package/lib/user-profile.js.map +1 -1
  98. package/lib/zhin-agent/builtin-tools.js.map +1 -1
  99. package/lib/zhin-agent/config.d.ts +1 -1
  100. package/lib/zhin-agent/config.d.ts.map +1 -1
  101. package/lib/zhin-agent/config.js.map +1 -1
  102. package/lib/zhin-agent/index.js +1 -1
  103. package/lib/zhin-agent/index.js.map +1 -1
  104. package/lib/zhin-agent/tool-collector.js +3 -3
  105. package/lib/zhin-agent/tool-collector.js.map +1 -1
  106. package/package.json +4 -3
  107. package/src/agent.ts +53 -30
  108. package/src/bootstrap.ts +1 -1
  109. package/src/builtin-tools.ts +44 -40
  110. package/src/compaction.ts +1 -1
  111. package/src/context-manager.ts +1 -1
  112. package/src/conversation-memory.ts +43 -1
  113. package/src/cron-engine.ts +5 -3
  114. package/src/follow-up.ts +1 -1
  115. package/src/hooks.ts +1 -1
  116. package/src/index.ts +10 -0
  117. package/src/init/create-zhin-agent.ts +133 -0
  118. package/src/init/register-ai-service.ts +53 -0
  119. package/src/init/register-ai-trigger.ts +179 -0
  120. package/src/init/register-builtin-tools.ts +177 -0
  121. package/src/init/register-db-models.ts +31 -0
  122. package/src/init/register-db-upgrade.ts +77 -0
  123. package/src/init/register-management-tools.ts +71 -0
  124. package/src/init/register-message-recorder.ts +31 -0
  125. package/src/init/register-tool-service.ts +9 -0
  126. package/src/init/shared-refs.ts +20 -0
  127. package/src/init/types.ts +18 -0
  128. package/src/init.ts +35 -735
  129. package/src/rate-limiter.ts +1 -1
  130. package/src/service.ts +4 -4
  131. package/src/session.ts +26 -4
  132. package/src/storage.ts +135 -0
  133. package/src/subagent.ts +1 -1
  134. package/src/tools.ts +7 -10
  135. package/src/user-profile.ts +1 -1
  136. package/src/zhin-agent/builtin-tools.ts +2 -2
  137. package/src/zhin-agent/config.ts +3 -3
  138. package/src/zhin-agent/index.ts +1 -1
  139. package/src/zhin-agent/tool-collector.ts +8 -8
@@ -8,7 +8,7 @@
8
8
  * 2. 优雅降级 — 超限时返回友好提示而非静默丢弃
9
9
  */
10
10
 
11
- import { Logger } from '@zhin.js/logger';
11
+ import { Logger } from '@zhin.js/core';
12
12
 
13
13
  const logger = new Logger(null, 'RateLimiter');
14
14
 
package/src/service.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  * 统一管理多个模型提供商,提供会话和 Agent 能力
4
4
  */
5
5
 
6
- import { Logger } from '@zhin.js/logger';
6
+ import { Logger } from '@zhin.js/core';
7
7
  import type { Plugin, Tool, ToolContext, AITriggerConfig } from '@zhin.js/core';
8
8
  import type {
9
9
  AIProvider,
@@ -224,12 +224,12 @@ ${preExecutedData ? `\n已自动获取的数据:${preExecutedData}\n` : ''}
224
224
  const agentTool: AgentTool = {
225
225
  name: tool.name,
226
226
  description: tool.description,
227
- parameters: tool.parameters as any,
228
- execute: tool.execute,
227
+ parameters: tool.parameters,
228
+ execute: async (args) => tool.execute(args),
229
229
  };
230
230
  if (tool.tags?.length) agentTool.tags = tool.tags;
231
231
  if (tool.permissionLevel) agentTool.permissionLevel = AIService.PERM_MAP[tool.permissionLevel] ?? 0;
232
- if ((tool as any).keywords?.length) agentTool.keywords = (tool as any).keywords;
232
+ if (tool.keywords?.length) agentTool.keywords = tool.keywords;
233
233
  return agentTool;
234
234
  }
235
235
 
package/src/session.ts CHANGED
@@ -9,7 +9,7 @@
9
9
  * - 更长的上下文记忆能力
10
10
  */
11
11
 
12
- import { Logger } from '@zhin.js/logger';
12
+ import { Logger } from '@zhin.js/core';
13
13
  import type { ChatMessage, SessionConfig, Session } from '@zhin.js/core';
14
14
 
15
15
  const logger = new Logger(null, 'AI-Session');
@@ -192,14 +192,17 @@ export class DatabaseSessionManager implements ISessionManager {
192
192
  private saveTimer?: ReturnType<typeof setTimeout>;
193
193
  private model: any; // 数据库模型
194
194
 
195
+ /** 内存缓存上限,超出时淘汰最久未访问的条目 */
196
+ private static readonly MAX_CACHE_SIZE = 2000;
197
+
195
198
  constructor(
196
199
  model: any,
197
200
  config: { maxHistory?: number; expireMs?: number } = {}
198
201
  ) {
199
202
  this.model = model;
200
203
  this.config = {
201
- maxHistory: config.maxHistory ?? 200, // 数据库支持更长的历史
202
- expireMs: config.expireMs ?? 7 * 24 * 60 * 60 * 1000, // 7 天过期
204
+ maxHistory: config.maxHistory ?? 200,
205
+ expireMs: config.expireMs ?? 7 * 24 * 60 * 60 * 1000,
203
206
  };
204
207
 
205
208
  // 定期清理过期会话(每小时)
@@ -286,7 +289,6 @@ export class DatabaseSessionManager implements ISessionManager {
286
289
  session = await this.loadSession(sessionId) ?? undefined;
287
290
 
288
291
  if (!session) {
289
- // 创建新会话
290
292
  session = {
291
293
  id: sessionId,
292
294
  config: config || { provider: 'openai' },
@@ -296,6 +298,11 @@ export class DatabaseSessionManager implements ISessionManager {
296
298
  };
297
299
  }
298
300
 
301
+ this.evictCacheIfNeeded();
302
+ this.cache.set(sessionId, session);
303
+ } else {
304
+ // LRU: 重新插入以更新 Map 的迭代顺序
305
+ this.cache.delete(sessionId);
299
306
  this.cache.set(sessionId, session);
300
307
  }
301
308
 
@@ -305,6 +312,21 @@ export class DatabaseSessionManager implements ISessionManager {
305
312
  return session;
306
313
  }
307
314
 
315
+ /**
316
+ * 当缓存超过上限时,淘汰最久未访问的条目。
317
+ * 利用 Map 的插入顺序(最旧的在前)。
318
+ */
319
+ private evictCacheIfNeeded(): void {
320
+ while (this.cache.size >= DatabaseSessionManager.MAX_CACHE_SIZE) {
321
+ const oldest = this.cache.keys().next().value;
322
+ if (oldest !== undefined) {
323
+ this.cache.delete(oldest);
324
+ } else {
325
+ break;
326
+ }
327
+ }
328
+ }
329
+
308
330
  async has(sessionId: string): Promise<boolean> {
309
331
  if (this.cache.has(sessionId)) {
310
332
  return true;
package/src/storage.ts ADDED
@@ -0,0 +1,135 @@
1
+ /**
2
+ * StorageBackend — Unified storage abstraction layer
3
+ *
4
+ * Provides a common interface for AI sub-systems (session, context, memory,
5
+ * user profile, follow-up) to switch between in-memory and database backends
6
+ * without changing business logic.
7
+ *
8
+ * Usage:
9
+ * const backend = new MemoryStorageBackend<MyRecord>();
10
+ * // ... later, when DB is ready:
11
+ * const dbBackend = new DatabaseStorageBackend<MyRecord>(model, { keyField: 'session_id' });
12
+ * service.upgradeBackend(dbBackend);
13
+ */
14
+
15
+ export interface StorageBackend<T extends Record<string, any>> {
16
+ get(key: string): Promise<T | null>;
17
+ set(key: string, value: T): Promise<void>;
18
+ delete(key: string): Promise<boolean>;
19
+ list(filter?: Partial<T>): Promise<T[]>;
20
+ clear(): Promise<void>;
21
+ readonly type: 'memory' | 'database';
22
+ }
23
+
24
+ /**
25
+ * In-memory storage backend.
26
+ */
27
+ export class MemoryStorageBackend<T extends Record<string, any>> implements StorageBackend<T> {
28
+ readonly type = 'memory' as const;
29
+ private data = new Map<string, T>();
30
+
31
+ async get(key: string): Promise<T | null> {
32
+ return this.data.get(key) ?? null;
33
+ }
34
+
35
+ async set(key: string, value: T): Promise<void> {
36
+ this.data.set(key, value);
37
+ }
38
+
39
+ async delete(key: string): Promise<boolean> {
40
+ return this.data.delete(key);
41
+ }
42
+
43
+ async list(filter?: Partial<T>): Promise<T[]> {
44
+ const all = Array.from(this.data.values());
45
+ if (!filter) return all;
46
+ return all.filter(item => {
47
+ for (const [k, v] of Object.entries(filter)) {
48
+ if (item[k] !== v) return false;
49
+ }
50
+ return true;
51
+ });
52
+ }
53
+
54
+ async clear(): Promise<void> {
55
+ this.data.clear();
56
+ }
57
+ }
58
+
59
+ /**
60
+ * Database model interface aligned with @zhin.js/database's RelatedModel API.
61
+ */
62
+ export interface DbModel {
63
+ select(...fields: string[]): any;
64
+ create(data: Record<string, any>): Promise<any>;
65
+ update(data: Partial<any>): any;
66
+ delete(condition: Record<string, any>): any;
67
+ }
68
+
69
+ /**
70
+ * Database-backed storage backend.
71
+ */
72
+ export class DatabaseStorageBackend<T extends Record<string, any>> implements StorageBackend<T> {
73
+ readonly type = 'database' as const;
74
+
75
+ constructor(
76
+ private model: DbModel,
77
+ private options: {
78
+ /** The field name used as lookup key (e.g. 'session_id', 'user_id') */
79
+ keyField: string;
80
+ },
81
+ ) {}
82
+
83
+ async get(key: string): Promise<T | null> {
84
+ const rows: T[] = await this.model
85
+ .select()
86
+ .where({ [this.options.keyField]: key });
87
+ return rows[0] ?? null;
88
+ }
89
+
90
+ async set(key: string, value: T): Promise<void> {
91
+ const existing = await this.get(key);
92
+ if (existing) {
93
+ await this.model
94
+ .update(value)
95
+ .where({ [this.options.keyField]: key });
96
+ } else {
97
+ await this.model.create({ ...value, [this.options.keyField]: key });
98
+ }
99
+ }
100
+
101
+ async delete(key: string): Promise<boolean> {
102
+ try {
103
+ await this.model.delete({ [this.options.keyField]: key });
104
+ return true;
105
+ } catch {
106
+ return false;
107
+ }
108
+ }
109
+
110
+ async list(filter?: Partial<T>): Promise<T[]> {
111
+ if (filter) {
112
+ return this.model.select().where(filter);
113
+ }
114
+ return this.model.select();
115
+ }
116
+
117
+ async clear(): Promise<void> {
118
+ const all = await this.list();
119
+ for (const item of all) {
120
+ const key = (item as Record<string, unknown>)[this.options.keyField] as string | undefined;
121
+ if (key) await this.delete(key);
122
+ }
123
+ }
124
+ }
125
+
126
+ /**
127
+ * Helper to create a swappable backend ref.
128
+ * Call `swap(newBackend)` to atomically upgrade from memory to database.
129
+ */
130
+ export function createSwappableBackend<T extends Record<string, any>>(
131
+ initial: StorageBackend<T>,
132
+ ): { backend: StorageBackend<T>; swap: (next: StorageBackend<T>) => void } {
133
+ const ref = { backend: initial, swap: (next: StorageBackend<T>) => { ref.backend = next; } };
134
+ return ref;
135
+ }
package/src/subagent.ts CHANGED
@@ -9,7 +9,7 @@
9
9
  */
10
10
 
11
11
  import { randomUUID } from 'crypto';
12
- import { Logger } from '@zhin.js/logger';
12
+ import { Logger } from '@zhin.js/core';
13
13
  import type { AIProvider, AgentTool } from '@zhin.js/core';
14
14
  import { createAgent } from './agent.js';
15
15
  import type { ZhinAgentConfig } from './zhin-agent/config.js';
package/src/tools.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  * 内置工具集合 - 使用 ZhinTool 类定义
4
4
  */
5
5
 
6
- import { ZhinTool, type Tool } from '@zhin.js/core';
6
+ import { ZhinTool, type Tool, evaluate, execute } from '@zhin.js/core';
7
7
 
8
8
  /**
9
9
  * 计算器工具
@@ -16,7 +16,6 @@ export const calculatorTool = new ZhinTool('calculator')
16
16
  .param('expression', { type: 'string', description: '数学表达式,例如 "2 + 3 * 4" 或 "sqrt(16)"' }, true)
17
17
  .execute(async ({ expression }) => {
18
18
  try {
19
- // 安全的数学表达式求值
20
19
  const sanitized = (expression as string)
21
20
  .replace(/[^0-9+\-*/().^eEsincosqrtabspowlogxMathPI\s]/g, '')
22
21
  .replace(/\bsqrt\b/g, 'Math.sqrt')
@@ -30,7 +29,8 @@ export const calculatorTool = new ZhinTool('calculator')
30
29
  .replace(/\bE\b(?![0-9])/g, 'Math.E')
31
30
  .replace(/\^/g, '**');
32
31
 
33
- const result = new Function(`return ${sanitized}`)();
32
+ const result = evaluate(sanitized, { Math });
33
+ if (result === undefined) return { error: '无法计算表达式', expression };
34
34
  return { result, expression };
35
35
  } catch (error) {
36
36
  return { error: '无法计算表达式', expression };
@@ -104,13 +104,10 @@ export const codeRunnerTool = new ZhinTool('run_code')
104
104
  .param('code', { type: 'string', description: 'JavaScript 代码' }, true)
105
105
  .execute(async ({ code }) => {
106
106
  try {
107
- // 简单的沙箱执行(生产环境应使用 vm2 或 isolated-vm)
108
- const result = new Function(`
109
- 'use strict';
110
- const console = { log: (...args) => args.join(' ') };
111
- return (function() { ${code} })();
112
- `)();
113
-
107
+ const sandbox = {
108
+ console: { log: (...args: unknown[]) => args.map(String).join(' ') },
109
+ };
110
+ const result = execute(code as string, sandbox);
114
111
  return {
115
112
  success: true,
116
113
  result: result !== undefined ? String(result) : 'undefined',
@@ -12,7 +12,7 @@
12
12
  * └──────────────────────────────────────────────────────────┘
13
13
  */
14
14
 
15
- import { Logger } from '@zhin.js/logger';
15
+ import { Logger } from '@zhin.js/core';
16
16
 
17
17
  const logger = new Logger(null, 'UserProfile');
18
18
 
@@ -147,7 +147,7 @@ export function createScheduleFollowUpTool(
147
147
  const botId = context.botId || '';
148
148
  const senderId = context.senderId || '';
149
149
  const sceneId = context.sceneId || '';
150
- const sceneType = (context.message as any)?.$channel?.type || 'private';
150
+ const sceneType = context.message?.$channel?.type || 'private';
151
151
 
152
152
  return {
153
153
  name: 'schedule_followup',
@@ -208,7 +208,7 @@ export function createSpawnTaskTool(
208
208
  const botId = context.botId || '';
209
209
  const senderId = context.senderId || '';
210
210
  const sceneId = context.sceneId || '';
211
- const sceneType = (context.message as any)?.$channel?.type || 'private';
211
+ const sceneType = context.message?.$channel?.type || 'private';
212
212
 
213
213
  return {
214
214
  name: 'spawn_task',
@@ -25,7 +25,7 @@ export function inferModelSize(modelName: string): ModelSizeHint {
25
25
  * Priority: explicit config > model name inference.
26
26
  */
27
27
  export function resolveModelSize(config: Required<ZhinAgentConfig>, modelName: string): ModelSizeHint {
28
- if (config.modelSizeHint && config.modelSizeHint !== ('' as any)) return config.modelSizeHint;
28
+ if (config.modelSizeHint && (config.modelSizeHint as string) !== '') return config.modelSizeHint as ModelSizeHint;
29
29
  return inferModelSize(modelName);
30
30
  }
31
31
 
@@ -80,7 +80,7 @@ export interface ZhinAgentConfig {
80
80
  maxSubagentIterations?: number;
81
81
  subagentTools?: string[];
82
82
  /** 模型大小提示,影响技能指令截断长度。留空则根据模型名自动推断 */
83
- modelSizeHint?: 'small' | 'medium' | 'large';
83
+ modelSizeHint?: '' | 'small' | 'medium' | 'large';
84
84
  /** 技能指令最大字符数(覆盖 modelSizeHint 推断值) */
85
85
  skillInstructionMaxChars?: number;
86
86
  }
@@ -108,6 +108,6 @@ export const DEFAULT_CONFIG: Required<ZhinAgentConfig> = {
108
108
  execAsk: false,
109
109
  maxSubagentIterations: 15,
110
110
  subagentTools: [],
111
- modelSizeHint: '' as any,
111
+ modelSizeHint: '',
112
112
  skillInstructionMaxChars: 0,
113
113
  };
@@ -16,7 +16,7 @@
16
16
  * 12. 多模态输入:图片/音频直接传给视觉模型
17
17
  */
18
18
 
19
- import { Logger } from '@zhin.js/logger';
19
+ import { Logger } from '@zhin.js/core';
20
20
  import type { Tool, ToolContext, SkillFeature, AIProvider, AgentTool, ChatMessage, ContentPart } from '@zhin.js/core';
21
21
  import { createAgent } from '../agent.js';
22
22
  import { SessionManager, createMemorySessionManager } from '../session.js';
@@ -2,7 +2,7 @@
2
2
  * ZhinAgent 工具收集 — 两级过滤 (Skill → Tool) + 技能支持工具注入
3
3
  */
4
4
 
5
- import { Logger } from '@zhin.js/logger';
5
+ import { Logger } from '@zhin.js/core';
6
6
  import type { Tool, ToolContext, SkillFeature } from '@zhin.js/core';
7
7
  import type { AgentTool } from '@zhin.js/core';
8
8
  import { Agent } from '../agent.js';
@@ -22,7 +22,7 @@ export function toAgentTool(tool: Tool, context?: ToolContext): AgentTool {
22
22
  contextKey: string;
23
23
  paramType: string;
24
24
  }> = [];
25
- let cleanParameters: any = tool.parameters;
25
+ let cleanParameters: AgentTool['parameters'] = tool.parameters;
26
26
 
27
27
  if (context && tool.parameters?.properties) {
28
28
  const props = tool.parameters.properties as Record<string, any>;
@@ -30,7 +30,7 @@ export function toAgentTool(tool: Tool, context?: ToolContext): AgentTool {
30
30
  const filteredRequired: string[] = [];
31
31
 
32
32
  for (const [key, schema] of Object.entries(props)) {
33
- if (schema.contextKey && (context as any)[schema.contextKey] != null) {
33
+ if (schema.contextKey && (context as Record<string, unknown>)[schema.contextKey] != null) {
34
34
  contextInjections.push({
35
35
  paramName: key,
36
36
  contextKey: schema.contextKey,
@@ -56,12 +56,12 @@ export function toAgentTool(tool: Tool, context?: ToolContext): AgentTool {
56
56
  const at: AgentTool = {
57
57
  name: tool.name,
58
58
  description: tool.description,
59
- parameters: cleanParameters as any,
59
+ parameters: cleanParameters,
60
60
  execute: context
61
- ? (args: Record<string, any>) => {
61
+ ? async (args: Record<string, any>) => {
62
62
  const enrichedArgs = { ...args };
63
63
  for (const { paramName, contextKey, paramType } of contextInjections) {
64
- let value = (context as any)[contextKey];
64
+ let value = (context as Record<string, unknown>)[contextKey];
65
65
  if (paramType === 'number' && typeof value === 'string') {
66
66
  value = Number(value);
67
67
  } else if (paramType === 'string' && typeof value !== 'string') {
@@ -71,13 +71,13 @@ export function toAgentTool(tool: Tool, context?: ToolContext): AgentTool {
71
71
  }
72
72
  return originalExecute(enrichedArgs, context);
73
73
  }
74
- : originalExecute,
74
+ : async (args: Record<string, any>) => originalExecute(args),
75
75
  };
76
76
  if (tool.tags?.length) at.tags = tool.tags;
77
77
  if (tool.keywords?.length) at.keywords = tool.keywords;
78
78
  if (tool.permissionLevel) at.permissionLevel = PERM_MAP[tool.permissionLevel] ?? 0;
79
79
  if (tool.preExecutable) at.preExecutable = true;
80
- if ((tool as any).kind) at.kind = (tool as any).kind;
80
+ if (tool.kind) at.kind = tool.kind;
81
81
  return at;
82
82
  }
83
83