@renxqoo/renx-code 0.0.4 → 0.0.6

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 (210) hide show
  1. package/README.md +82 -51
  2. package/bin/renx.cjs +16 -0
  3. package/package.json +2 -45
  4. package/src/agent/runtime/runtime.context-usage.test.ts +4 -5
  5. package/src/agent/runtime/runtime.error-handling.test.ts +4 -5
  6. package/src/agent/runtime/runtime.test.ts +7 -4
  7. package/src/agent/runtime/runtime.ts +3 -9
  8. package/src/agent/runtime/runtime.usage-forwarding.test.ts +4 -5
  9. package/src/agent/runtime/source-modules.test.ts +16 -35
  10. package/src/agent/runtime/source-modules.ts +17 -0
  11. package/vendor/agent-root/src/agent/ENTERPRISE_ACCEPTANCE_CHECKLIST.md +95 -0
  12. package/vendor/agent-root/src/agent/ENTERPRISE_REALTIME.html +1345 -0
  13. package/vendor/agent-root/src/agent/ENTERPRISE_REALTIME.md +1353 -0
  14. package/vendor/agent-root/src/agent/ERROR_CONTRACT.md +60 -0
  15. package/vendor/agent-root/src/agent/TEST_COVERAGE_ANALYSIS.md +278 -0
  16. package/vendor/agent-root/src/agent/__test__/error-contract.test.ts +72 -0
  17. package/vendor/agent-root/src/agent/__test__/types.test.ts +137 -0
  18. package/vendor/agent-root/src/agent/agent/__test__/abort-runtime.test.ts +83 -0
  19. package/vendor/agent-root/src/agent/agent/__test__/callback-safety.test.ts +34 -0
  20. package/vendor/agent-root/src/agent/agent/__test__/compaction.test.ts +323 -0
  21. package/vendor/agent-root/src/agent/agent/__test__/concurrency.test.ts +290 -0
  22. package/vendor/agent-root/src/agent/agent/__test__/error-normalizer.test.ts +377 -0
  23. package/vendor/agent-root/src/agent/agent/__test__/error.test.ts +212 -0
  24. package/vendor/agent-root/src/agent/agent/__test__/fault-injection.test.ts +295 -0
  25. package/vendor/agent-root/src/agent/agent/__test__/index.test.ts +3607 -0
  26. package/vendor/agent-root/src/agent/agent/__test__/logger.test.ts +35 -0
  27. package/vendor/agent-root/src/agent/agent/__test__/message-utils.test.ts +517 -0
  28. package/vendor/agent-root/src/agent/agent/__test__/telemetry.test.ts +97 -0
  29. package/vendor/agent-root/src/agent/agent/__test__/timeout-budget.test.ts +479 -0
  30. package/vendor/agent-root/src/agent/agent/__test__/tool-call-merge.test.ts +80 -0
  31. package/vendor/agent-root/src/agent/agent/__test__/tool-execution-ledger.test.ts +76 -0
  32. package/vendor/agent-root/src/agent/agent/__test__/write-buffer.test.ts +173 -0
  33. package/vendor/agent-root/src/agent/agent/__test__/write-file-session.test.ts +109 -0
  34. package/vendor/agent-root/src/agent/agent/abort-runtime.ts +71 -0
  35. package/vendor/agent-root/src/agent/agent/callback-safety.ts +33 -0
  36. package/vendor/agent-root/src/agent/agent/compaction.ts +291 -0
  37. package/vendor/agent-root/src/agent/agent/concurrency.ts +103 -0
  38. package/vendor/agent-root/src/agent/agent/error-normalizer.ts +190 -0
  39. package/vendor/agent-root/src/agent/agent/error.ts +198 -0
  40. package/vendor/agent-root/src/agent/agent/index.ts +1772 -0
  41. package/vendor/agent-root/src/agent/agent/logger.ts +65 -0
  42. package/vendor/agent-root/src/agent/agent/message-utils.ts +101 -0
  43. package/vendor/agent-root/src/agent/agent/stream-events.ts +61 -0
  44. package/vendor/agent-root/src/agent/agent/telemetry.ts +123 -0
  45. package/vendor/agent-root/src/agent/agent/timeout-budget.ts +227 -0
  46. package/vendor/agent-root/src/agent/agent/tool-call-merge.ts +111 -0
  47. package/vendor/agent-root/src/agent/agent/tool-execution-ledger.ts +164 -0
  48. package/vendor/agent-root/src/agent/agent/write-buffer.ts +188 -0
  49. package/vendor/agent-root/src/agent/agent/write-file-session.ts +238 -0
  50. package/vendor/agent-root/src/agent/app/__test__/agent-app-service.test.ts +1053 -0
  51. package/vendor/agent-root/src/agent/app/__test__/minimal-agent-application.test.ts +158 -0
  52. package/vendor/agent-root/src/agent/app/__test__/sqlite-agent-app-store.test.ts +437 -0
  53. package/vendor/agent-root/src/agent/app/agent-app-service.ts +748 -0
  54. package/vendor/agent-root/src/agent/app/contracts.ts +109 -0
  55. package/vendor/agent-root/src/agent/app/index.ts +5 -0
  56. package/vendor/agent-root/src/agent/app/minimal-agent-application.ts +151 -0
  57. package/vendor/agent-root/src/agent/app/ports.ts +72 -0
  58. package/vendor/agent-root/src/agent/app/sqlite-agent-app-store.ts +1182 -0
  59. package/vendor/agent-root/src/agent/app/sqlite-client.ts +177 -0
  60. package/vendor/agent-root/src/agent/docs/cli-app-layer/00-README.md +36 -0
  61. package/vendor/agent-root/src/agent/docs/cli-app-layer/01-scope-and-goals.md +33 -0
  62. package/vendor/agent-root/src/agent/docs/cli-app-layer/02-architecture-overview.md +40 -0
  63. package/vendor/agent-root/src/agent/docs/cli-app-layer/03-domain-model-and-contracts.md +91 -0
  64. package/vendor/agent-root/src/agent/docs/cli-app-layer/04-ports-and-interfaces.md +116 -0
  65. package/vendor/agent-root/src/agent/docs/cli-app-layer/05-run-orchestration-and-state-machine.md +52 -0
  66. package/vendor/agent-root/src/agent/docs/cli-app-layer/06-cli-commands-and-ux.md +53 -0
  67. package/vendor/agent-root/src/agent/docs/cli-app-layer/07-storage-design-local.md +52 -0
  68. package/vendor/agent-root/src/agent/docs/cli-app-layer/08-error-and-observability.md +40 -0
  69. package/vendor/agent-root/src/agent/docs/cli-app-layer/09-security-and-policy-boundary.md +19 -0
  70. package/vendor/agent-root/src/agent/docs/cli-app-layer/10-test-plan-and-acceptance.md +28 -0
  71. package/vendor/agent-root/src/agent/docs/cli-app-layer/11-implementation-phases.md +26 -0
  72. package/vendor/agent-root/src/agent/docs/cli-app-layer/12-open-questions-and-risks.md +30 -0
  73. package/vendor/agent-root/src/agent/docs/cli-app-layer/13-sqlite-schema-fields-and-rationale.md +567 -0
  74. package/vendor/agent-root/src/agent/docs/cli-app-layer/14-project-flow-mermaid.md +583 -0
  75. package/vendor/agent-root/src/agent/docs/cli-app-layer/15-openclaw-style-project-blueprint.md +972 -0
  76. package/vendor/agent-root/src/agent/error-contract.ts +154 -0
  77. package/vendor/agent-root/src/agent/prompts/system.ts +246 -0
  78. package/vendor/agent-root/src/agent/prompts/system1.ts +208 -0
  79. package/vendor/agent-root/src/agent/storage/__test__/file-history-store.test.ts +98 -0
  80. package/vendor/agent-root/src/agent/storage/file-history-store.ts +313 -0
  81. package/vendor/agent-root/src/agent/storage/file-storage-config.ts +94 -0
  82. package/vendor/agent-root/src/agent/storage/file-system.ts +31 -0
  83. package/vendor/agent-root/src/agent/storage/file-write-service.ts +21 -0
  84. package/vendor/agent-root/src/agent/tool/__test__/base-tool.test.ts +413 -0
  85. package/vendor/agent-root/src/agent/tool/__test__/bash-policy.test.ts +356 -0
  86. package/vendor/agent-root/src/agent/tool/__test__/bash.mocked-coverage.test.ts +375 -0
  87. package/vendor/agent-root/src/agent/tool/__test__/bash.test.ts +372 -0
  88. package/vendor/agent-root/src/agent/tool/__test__/error.test.ts +108 -0
  89. package/vendor/agent-root/src/agent/tool/__test__/file-edit-tool.test.ts +258 -0
  90. package/vendor/agent-root/src/agent/tool/__test__/file-history-tools.test.ts +121 -0
  91. package/vendor/agent-root/src/agent/tool/__test__/file-read-tool.test.ts +210 -0
  92. package/vendor/agent-root/src/agent/tool/__test__/glob.test.ts +139 -0
  93. package/vendor/agent-root/src/agent/tool/__test__/grep.mocked-coverage.test.ts +456 -0
  94. package/vendor/agent-root/src/agent/tool/__test__/grep.test.ts +192 -0
  95. package/vendor/agent-root/src/agent/tool/__test__/lsp.test.ts +300 -0
  96. package/vendor/agent-root/src/agent/tool/__test__/outside-workspace-confirmation.test.ts +214 -0
  97. package/vendor/agent-root/src/agent/tool/__test__/path-security.test.ts +336 -0
  98. package/vendor/agent-root/src/agent/tool/__test__/skill-loader.test.ts +494 -0
  99. package/vendor/agent-root/src/agent/tool/__test__/skill-parser.test.ts +543 -0
  100. package/vendor/agent-root/src/agent/tool/__test__/skill-tool.test.ts +172 -0
  101. package/vendor/agent-root/src/agent/tool/__test__/task-concurrency-and-version.test.ts +116 -0
  102. package/vendor/agent-root/src/agent/tool/__test__/task-create-get-list-update.test.ts +267 -0
  103. package/vendor/agent-root/src/agent/tool/__test__/task-create.test.ts +519 -0
  104. package/vendor/agent-root/src/agent/tool/__test__/task-errors.test.ts +225 -0
  105. package/vendor/agent-root/src/agent/tool/__test__/task-output-blocking.test.ts +223 -0
  106. package/vendor/agent-root/src/agent/tool/__test__/task-output.test.ts +184 -0
  107. package/vendor/agent-root/src/agent/tool/__test__/task-parent-abort.test.ts +287 -0
  108. package/vendor/agent-root/src/agent/tool/__test__/task-real-runner-adapter.test.ts +190 -0
  109. package/vendor/agent-root/src/agent/tool/__test__/task-run-lifecycle.test.ts +352 -0
  110. package/vendor/agent-root/src/agent/tool/__test__/task-store-runner-branches.test.ts +395 -0
  111. package/vendor/agent-root/src/agent/tool/__test__/task-store.test.ts +391 -0
  112. package/vendor/agent-root/src/agent/tool/__test__/task-subagent-config-integration.test.ts +176 -0
  113. package/vendor/agent-root/src/agent/tool/__test__/task-subagent-config.test.ts +68 -0
  114. package/vendor/agent-root/src/agent/tool/__test__/task-tools-core-edges.test.ts +630 -0
  115. package/vendor/agent-root/src/agent/tool/__test__/task-tools-runtime-edges.test.ts +732 -0
  116. package/vendor/agent-root/src/agent/tool/__test__/task-types.test.ts +494 -0
  117. package/vendor/agent-root/src/agent/tool/__test__/task-utils-branches.test.ts +175 -0
  118. package/vendor/agent-root/src/agent/tool/__test__/tool-manager.test.ts +505 -0
  119. package/vendor/agent-root/src/agent/tool/__test__/types.test.ts +55 -0
  120. package/vendor/agent-root/src/agent/tool/__test__/web-fetch.test.ts +244 -0
  121. package/vendor/agent-root/src/agent/tool/__test__/web-search.test.ts +290 -0
  122. package/vendor/agent-root/src/agent/tool/__test__/write-file.test.ts +368 -0
  123. package/vendor/agent-root/src/agent/tool/base-tool.ts +345 -0
  124. package/vendor/agent-root/src/agent/tool/bash-policy.ts +636 -0
  125. package/vendor/agent-root/src/agent/tool/bash.ts +688 -0
  126. package/vendor/agent-root/src/agent/tool/error.ts +131 -0
  127. package/vendor/agent-root/src/agent/tool/file-edit-tool.ts +264 -0
  128. package/vendor/agent-root/src/agent/tool/file-history-list.ts +103 -0
  129. package/vendor/agent-root/src/agent/tool/file-history-restore.ts +149 -0
  130. package/vendor/agent-root/src/agent/tool/file-read-tool.ts +211 -0
  131. package/vendor/agent-root/src/agent/tool/glob.ts +171 -0
  132. package/vendor/agent-root/src/agent/tool/grep.ts +496 -0
  133. package/vendor/agent-root/src/agent/tool/lsp.ts +481 -0
  134. package/vendor/agent-root/src/agent/tool/path-security.ts +117 -0
  135. package/vendor/agent-root/src/agent/tool/search/common.ts +153 -0
  136. package/vendor/agent-root/src/agent/tool/skill/index.ts +13 -0
  137. package/vendor/agent-root/src/agent/tool/skill/loader.ts +229 -0
  138. package/vendor/agent-root/src/agent/tool/skill/parser.ts +124 -0
  139. package/vendor/agent-root/src/agent/tool/skill/types.ts +27 -0
  140. package/vendor/agent-root/src/agent/tool/skill-tool.ts +143 -0
  141. package/vendor/agent-root/src/agent/tool/task-create.ts +186 -0
  142. package/vendor/agent-root/src/agent/tool/task-errors.ts +42 -0
  143. package/vendor/agent-root/src/agent/tool/task-get.ts +116 -0
  144. package/vendor/agent-root/src/agent/tool/task-graph.ts +78 -0
  145. package/vendor/agent-root/src/agent/tool/task-list.ts +141 -0
  146. package/vendor/agent-root/src/agent/tool/task-mock-runner-adapter.ts +232 -0
  147. package/vendor/agent-root/src/agent/tool/task-output.ts +223 -0
  148. package/vendor/agent-root/src/agent/tool/task-parent-abort.ts +115 -0
  149. package/vendor/agent-root/src/agent/tool/task-real-runner-adapter.ts +336 -0
  150. package/vendor/agent-root/src/agent/tool/task-runner-adapter.ts +55 -0
  151. package/vendor/agent-root/src/agent/tool/task-stop.ts +187 -0
  152. package/vendor/agent-root/src/agent/tool/task-store.ts +217 -0
  153. package/vendor/agent-root/src/agent/tool/task-subagent-config.ts +149 -0
  154. package/vendor/agent-root/src/agent/tool/task-types.ts +264 -0
  155. package/vendor/agent-root/src/agent/tool/task-update.ts +315 -0
  156. package/vendor/agent-root/src/agent/tool/task.ts +209 -0
  157. package/vendor/agent-root/src/agent/tool/tool-manager.ts +362 -0
  158. package/vendor/agent-root/src/agent/tool/tool-prompts.ts +242 -0
  159. package/vendor/agent-root/src/agent/tool/types.ts +116 -0
  160. package/vendor/agent-root/src/agent/tool/web-fetch.ts +227 -0
  161. package/vendor/agent-root/src/agent/tool/web-search.ts +208 -0
  162. package/vendor/agent-root/src/agent/tool/write-file.ts +497 -0
  163. package/vendor/agent-root/src/agent/types.ts +232 -0
  164. package/vendor/agent-root/src/agent/utils/__tests__/index.test.ts +18 -0
  165. package/vendor/agent-root/src/agent/utils/__tests__/message-utils.test.ts +610 -0
  166. package/vendor/agent-root/src/agent/utils/__tests__/message.test.ts +223 -0
  167. package/vendor/agent-root/src/agent/utils/__tests__/token.test.ts +42 -0
  168. package/vendor/agent-root/src/agent/utils/index.ts +16 -0
  169. package/vendor/agent-root/src/agent/utils/message.ts +171 -0
  170. package/vendor/agent-root/src/agent/utils/token.ts +28 -0
  171. package/vendor/agent-root/src/config/__tests__/load-config-to-env.test.ts +129 -0
  172. package/vendor/agent-root/src/config/__tests__/loader.test.ts +247 -0
  173. package/vendor/agent-root/src/config/__tests__/runtime.test.ts +88 -0
  174. package/vendor/agent-root/src/config/index.ts +54 -0
  175. package/vendor/agent-root/src/config/loader.ts +431 -0
  176. package/vendor/agent-root/src/config/paths.ts +30 -0
  177. package/vendor/agent-root/src/config/runtime.ts +163 -0
  178. package/vendor/agent-root/src/config/types.ts +70 -0
  179. package/vendor/agent-root/src/logger/index.ts +57 -0
  180. package/vendor/agent-root/src/logger/logger.ts +819 -0
  181. package/vendor/agent-root/src/logger/types.ts +150 -0
  182. package/vendor/agent-root/src/providers/__tests__/errors.test.ts +441 -0
  183. package/vendor/agent-root/src/providers/__tests__/index.test.ts +16 -0
  184. package/vendor/agent-root/src/providers/__tests__/openai-compatible.options.test.ts +318 -0
  185. package/vendor/agent-root/src/providers/__tests__/openai-compatible.test.ts +600 -0
  186. package/vendor/agent-root/src/providers/__tests__/registry.test.ts +449 -0
  187. package/vendor/agent-root/src/providers/__tests__/responses-adapter.test.ts +298 -0
  188. package/vendor/agent-root/src/providers/adapters/__tests__/anthropic.test.ts +354 -0
  189. package/vendor/agent-root/src/providers/adapters/__tests__/kimi.test.ts +58 -0
  190. package/vendor/agent-root/src/providers/adapters/__tests__/standard.test.ts +261 -0
  191. package/vendor/agent-root/src/providers/adapters/anthropic.ts +572 -0
  192. package/vendor/agent-root/src/providers/adapters/base.ts +131 -0
  193. package/vendor/agent-root/src/providers/adapters/kimi.ts +48 -0
  194. package/vendor/agent-root/src/providers/adapters/responses.ts +732 -0
  195. package/vendor/agent-root/src/providers/adapters/standard.ts +120 -0
  196. package/vendor/agent-root/src/providers/http/__tests__/client.timeout.test.ts +313 -0
  197. package/vendor/agent-root/src/providers/http/client.ts +289 -0
  198. package/vendor/agent-root/src/providers/http/stream-parser.ts +109 -0
  199. package/vendor/agent-root/src/providers/index.ts +76 -0
  200. package/vendor/agent-root/src/providers/kimi-headers.ts +177 -0
  201. package/vendor/agent-root/src/providers/openai-compatible.ts +387 -0
  202. package/vendor/agent-root/src/providers/registry/model-config.ts +230 -0
  203. package/vendor/agent-root/src/providers/registry/provider-factory.ts +123 -0
  204. package/vendor/agent-root/src/providers/registry.ts +135 -0
  205. package/vendor/agent-root/src/providers/types/api.ts +284 -0
  206. package/vendor/agent-root/src/providers/types/config.ts +58 -0
  207. package/vendor/agent-root/src/providers/types/errors.ts +323 -0
  208. package/vendor/agent-root/src/providers/types/index.ts +72 -0
  209. package/vendor/agent-root/src/providers/types/provider.ts +45 -0
  210. package/vendor/agent-root/src/providers/types/registry.ts +88 -0
@@ -0,0 +1,505 @@
1
+ import { afterEach, describe, expect, it, vi } from 'vitest';
2
+ import { z } from 'zod';
3
+ import { BaseTool, ToolResult } from '../base-tool';
4
+ import { DefaultToolManager } from '../tool-manager';
5
+ import {
6
+ EmptyToolNameError,
7
+ InvalidArgumentsError,
8
+ ToolDeniedError,
9
+ ToolExecutionError,
10
+ ToolNotFoundError,
11
+ ToolPolicyDeniedError,
12
+ ToolValidationError,
13
+ } from '../error';
14
+ import type { ToolExecutionContext } from '../types';
15
+
16
+ const schema = z.object({
17
+ input: z.string().min(1),
18
+ });
19
+
20
+ class EchoTool extends BaseTool<typeof schema> {
21
+ name = 'echo';
22
+ description = 'echo input';
23
+ parameters = schema;
24
+
25
+ shouldConfirm(): boolean {
26
+ return false;
27
+ }
28
+
29
+ async execute(
30
+ args: z.infer<typeof schema>,
31
+ _context?: ToolExecutionContext
32
+ ): Promise<ToolResult> {
33
+ return {
34
+ success: true,
35
+ output: args.input,
36
+ };
37
+ }
38
+ }
39
+
40
+ class ConfirmEchoTool extends EchoTool {
41
+ override name = 'confirm-echo';
42
+
43
+ override shouldConfirm(): boolean {
44
+ return true;
45
+ }
46
+ }
47
+
48
+ class ThrowingTool extends EchoTool {
49
+ override async execute(): Promise<ToolResult> {
50
+ throw new Error('run failed');
51
+ }
52
+ }
53
+
54
+ class ParallelReadTool extends EchoTool {
55
+ override name = 'parallel-echo';
56
+
57
+ override getConcurrencyMode(): 'parallel-safe' {
58
+ return 'parallel-safe';
59
+ }
60
+
61
+ override getConcurrencyLockKey(args: z.infer<typeof schema>): string | undefined {
62
+ return `resource:${args.input}`;
63
+ }
64
+ }
65
+
66
+ class ParallelNoLockTool extends EchoTool {
67
+ override name = 'parallel-no-lock';
68
+
69
+ override getConcurrencyMode(): 'parallel-safe' {
70
+ return 'parallel-safe';
71
+ }
72
+ }
73
+
74
+ const bashSchema = z.object({
75
+ command: z.string().min(1),
76
+ });
77
+
78
+ class SafeBashTool extends BaseTool<typeof bashSchema> {
79
+ name = 'bash';
80
+ description = 'bash command';
81
+ parameters = bashSchema;
82
+
83
+ async execute(
84
+ args: z.infer<typeof bashSchema>,
85
+ _context?: ToolExecutionContext
86
+ ): Promise<ToolResult> {
87
+ return {
88
+ success: true,
89
+ output: args.command,
90
+ };
91
+ }
92
+ }
93
+
94
+ function createContext(partial?: Partial<ToolExecutionContext>): ToolExecutionContext {
95
+ return {
96
+ toolCallId: 'call_1',
97
+ loopIndex: 1,
98
+ agent: {},
99
+ ...partial,
100
+ };
101
+ }
102
+
103
+ describe('DefaultToolManager', () => {
104
+ const originalConfirmationMode = process.env.AGENT_TOOL_CONFIRMATION_MODE;
105
+
106
+ afterEach(() => {
107
+ if (originalConfirmationMode === undefined) {
108
+ delete process.env.AGENT_TOOL_CONFIRMATION_MODE;
109
+ return;
110
+ }
111
+ process.env.AGENT_TOOL_CONFIRMATION_MODE = originalConfirmationMode;
112
+ });
113
+
114
+ it('returns EmptyToolNameError when tool name is empty', async () => {
115
+ const manager = new DefaultToolManager();
116
+
117
+ const result = await manager.execute(
118
+ {
119
+ id: 't1',
120
+ type: 'function',
121
+ index: 0,
122
+ function: { name: '', arguments: '{}' },
123
+ },
124
+ createContext()
125
+ );
126
+
127
+ expect(result.success).toBe(false);
128
+ expect(result.error).toBeInstanceOf(EmptyToolNameError);
129
+ expect(result.output).toBe('Tool name is empty');
130
+ });
131
+
132
+ it('returns InvalidArgumentsError when arguments are invalid json', async () => {
133
+ const manager = new DefaultToolManager();
134
+
135
+ const result = await manager.execute(
136
+ {
137
+ id: 't2',
138
+ type: 'function',
139
+ index: 0,
140
+ function: { name: 'echo', arguments: '{bad' },
141
+ },
142
+ createContext()
143
+ );
144
+
145
+ expect(result.success).toBe(false);
146
+ expect(result.error).toBeInstanceOf(InvalidArgumentsError);
147
+ expect(result.output).toContain('Invalid arguments format for tool echo');
148
+ });
149
+
150
+ it('returns ToolNotFoundError for missing handler', async () => {
151
+ const manager = new DefaultToolManager();
152
+
153
+ const result = await manager.execute(
154
+ {
155
+ id: 't3',
156
+ type: 'function',
157
+ index: 0,
158
+ function: { name: 'missing', arguments: '{}' },
159
+ },
160
+ createContext()
161
+ );
162
+
163
+ expect(result.success).toBe(false);
164
+ expect(result.error).toBeInstanceOf(ToolNotFoundError);
165
+ expect(result.output).toBe('Tool missing not found');
166
+ });
167
+
168
+ it('returns ToolValidationError for invalid parameters', async () => {
169
+ const manager = new DefaultToolManager();
170
+ manager.registerTool(new EchoTool());
171
+
172
+ const result = await manager.execute(
173
+ {
174
+ id: 't4',
175
+ type: 'function',
176
+ index: 0,
177
+ function: { name: 'echo', arguments: '{}' },
178
+ },
179
+ createContext()
180
+ );
181
+
182
+ expect(result.success).toBe(false);
183
+ expect(result.error).toBeInstanceOf(ToolValidationError);
184
+ expect(result.output).toContain('expected string');
185
+ });
186
+
187
+ it('returns ToolPolicyDeniedError when policy check rejects execution', async () => {
188
+ const manager = new DefaultToolManager();
189
+ manager.registerTool(new EchoTool());
190
+
191
+ const onPolicyCheck = vi.fn().mockResolvedValue({
192
+ allowed: false,
193
+ code: 'PATH_NOT_ALLOWED',
194
+ message: 'outside workspace',
195
+ });
196
+ const result = await manager.execute(
197
+ {
198
+ id: 't4_policy',
199
+ type: 'function',
200
+ index: 0,
201
+ function: { name: 'echo', arguments: '{"input":"abc"}' },
202
+ },
203
+ createContext({ onPolicyCheck })
204
+ );
205
+
206
+ expect(onPolicyCheck).toHaveBeenCalledOnce();
207
+ expect(result.success).toBe(false);
208
+ expect(result.error).toBeInstanceOf(ToolPolicyDeniedError);
209
+ expect(result.output).toContain('[PATH_NOT_ALLOWED]');
210
+ });
211
+
212
+ it('blocks dangerous bash command with built-in policy and includes audit details', async () => {
213
+ const manager = new DefaultToolManager();
214
+ manager.registerTool(new SafeBashTool());
215
+
216
+ const result = await manager.execute(
217
+ {
218
+ id: 't4_builtin_policy',
219
+ type: 'function',
220
+ index: 0,
221
+ function: { name: 'bash', arguments: '{"command":"rm -rf /"}' },
222
+ },
223
+ createContext()
224
+ );
225
+
226
+ expect(result.success).toBe(false);
227
+ expect(result.error).toBeInstanceOf(ToolPolicyDeniedError);
228
+ expect(result.output).toContain('[DANGEROUS_COMMAND]');
229
+ expect((result.error as ToolPolicyDeniedError).details).toMatchObject({
230
+ toolName: 'bash',
231
+ reasonCode: 'DANGEROUS_COMMAND',
232
+ audit: {
233
+ toolCallId: 't4_builtin_policy',
234
+ toolName: 'bash',
235
+ source: 'builtin',
236
+ },
237
+ });
238
+ });
239
+
240
+ it('executes when policy check allows and receives parsed arguments', async () => {
241
+ const manager = new DefaultToolManager();
242
+ const tool = new EchoTool();
243
+ const executeSpy = vi.spyOn(tool, 'execute');
244
+ manager.registerTool(tool);
245
+
246
+ const onPolicyCheck = vi.fn().mockResolvedValue({
247
+ allowed: true,
248
+ });
249
+ const result = await manager.execute(
250
+ {
251
+ id: 't4_policy_allow',
252
+ type: 'function',
253
+ index: 0,
254
+ function: { name: 'echo', arguments: '{"input":"abc"}' },
255
+ },
256
+ createContext({ onPolicyCheck })
257
+ );
258
+
259
+ expect(onPolicyCheck).toHaveBeenCalledWith({
260
+ toolCallId: 't4_policy_allow',
261
+ toolName: 'echo',
262
+ arguments: '{"input":"abc"}',
263
+ parsedArguments: { input: 'abc' },
264
+ });
265
+ expect(executeSpy).toHaveBeenCalledOnce();
266
+ expect(result.success).toBe(true);
267
+ expect(result.output).toBe('abc');
268
+ });
269
+
270
+ it('returns ToolDeniedError when user rejects confirmation', async () => {
271
+ const manager = new DefaultToolManager({ confirmationMode: 'manual' });
272
+ manager.registerTool(new ConfirmEchoTool());
273
+
274
+ const onConfirm = vi.fn().mockResolvedValue({ approved: false, message: 'deny' });
275
+ const result = await manager.execute(
276
+ {
277
+ id: 't5',
278
+ type: 'function',
279
+ index: 0,
280
+ function: { name: 'confirm-echo', arguments: '{"input":"abc"}' },
281
+ },
282
+ createContext({ onConfirm })
283
+ );
284
+
285
+ expect(onConfirm).toHaveBeenCalledOnce();
286
+ expect(result.success).toBe(false);
287
+ expect(result.error).toBeInstanceOf(ToolDeniedError);
288
+ expect(result.output).toBe('Tool confirm-echo denied: deny');
289
+ });
290
+
291
+ it('executes after confirmation approval', async () => {
292
+ const manager = new DefaultToolManager({ confirmationMode: 'manual' });
293
+ const tool = new ConfirmEchoTool();
294
+ const execSpy = vi.spyOn(tool, 'execute');
295
+ manager.registerTool(tool);
296
+
297
+ const onConfirm = vi.fn().mockResolvedValue({ approved: true });
298
+ const result = await manager.execute(
299
+ {
300
+ id: 't6',
301
+ type: 'function',
302
+ index: 0,
303
+ function: { name: 'confirm-echo', arguments: '{"input":"abc"}' },
304
+ },
305
+ createContext({ onConfirm })
306
+ );
307
+
308
+ expect(onConfirm).toHaveBeenCalledOnce();
309
+ expect(execSpy).toHaveBeenCalledOnce();
310
+ expect(result.success).toBe(true);
311
+ expect(result.output).toBe('abc');
312
+ });
313
+
314
+ it('executes directly when confirm callback is not provided', async () => {
315
+ const manager = new DefaultToolManager();
316
+ const tool = new ConfirmEchoTool();
317
+ const execSpy = vi.spyOn(tool, 'execute');
318
+ manager.registerTool(tool);
319
+
320
+ const result = await manager.execute(
321
+ {
322
+ id: 't7',
323
+ type: 'function',
324
+ index: 0,
325
+ function: { name: 'confirm-echo', arguments: '{"input":"no-confirm"}' },
326
+ },
327
+ createContext()
328
+ );
329
+
330
+ expect(execSpy).toHaveBeenCalledOnce();
331
+ expect(result.success).toBe(true);
332
+ expect(result.output).toBe('no-confirm');
333
+ });
334
+
335
+ it('auto-approves confirmations from env without invoking callback', async () => {
336
+ process.env.AGENT_TOOL_CONFIRMATION_MODE = 'auto-approve';
337
+ const manager = new DefaultToolManager();
338
+ const tool = new ConfirmEchoTool();
339
+ const execSpy = vi.spyOn(tool, 'execute');
340
+ manager.registerTool(tool);
341
+
342
+ const onConfirm = vi.fn();
343
+ const result = await manager.execute(
344
+ {
345
+ id: 't7_auto_approve',
346
+ type: 'function',
347
+ index: 0,
348
+ function: { name: 'confirm-echo', arguments: '{"input":"approved-by-env"}' },
349
+ },
350
+ createContext({ onConfirm })
351
+ );
352
+
353
+ expect(onConfirm).not.toHaveBeenCalled();
354
+ expect(execSpy).toHaveBeenCalledOnce();
355
+ expect(execSpy.mock.calls[0]?.[1]?.confirmationApproved).toBe(true);
356
+ expect(result.success).toBe(true);
357
+ expect(result.output).toBe('approved-by-env');
358
+ });
359
+
360
+ it('auto-denies confirmations from env before invoking callback', async () => {
361
+ process.env.AGENT_TOOL_CONFIRMATION_MODE = 'auto-deny';
362
+ const manager = new DefaultToolManager();
363
+ manager.registerTool(new ConfirmEchoTool());
364
+
365
+ const onConfirm = vi.fn();
366
+ const result = await manager.execute(
367
+ {
368
+ id: 't7_auto_deny',
369
+ type: 'function',
370
+ index: 0,
371
+ function: { name: 'confirm-echo', arguments: '{"input":"denied-by-env"}' },
372
+ },
373
+ createContext({ onConfirm })
374
+ );
375
+
376
+ expect(onConfirm).not.toHaveBeenCalled();
377
+ expect(result.success).toBe(false);
378
+ expect(result.error).toBeInstanceOf(ToolDeniedError);
379
+ expect(result.output).toBe(
380
+ 'Tool confirm-echo denied: Denied by AGENT_TOOL_CONFIRMATION_MODE=auto-deny'
381
+ );
382
+ });
383
+
384
+ it('throws for invalid confirmation mode env values', () => {
385
+ process.env.AGENT_TOOL_CONFIRMATION_MODE = 'sometimes';
386
+
387
+ expect(() => new DefaultToolManager()).toThrow(
388
+ 'Invalid AGENT_TOOL_CONFIRMATION_MODE: "sometimes" (expected "manual", "auto-approve", or "auto-deny")'
389
+ );
390
+ });
391
+
392
+ it('wraps handler execution error with ToolExecutionError and emits stderr chunk', async () => {
393
+ const manager = new DefaultToolManager();
394
+ manager.registerTool(new ThrowingTool());
395
+
396
+ const onChunk = vi.fn();
397
+ const result = await manager.execute(
398
+ {
399
+ id: 't8',
400
+ type: 'function',
401
+ index: 0,
402
+ function: { name: 'echo', arguments: '{"input":"x"}' },
403
+ },
404
+ createContext({ onChunk })
405
+ );
406
+
407
+ expect(onChunk).toHaveBeenCalledWith({ type: 'stderr', data: 'run failed' });
408
+ expect(result.success).toBe(false);
409
+ expect(result.error).toBeInstanceOf(ToolExecutionError);
410
+ expect(result.output).toBe('run failed');
411
+ });
412
+
413
+ it('registerTool and getTools returns all tools', () => {
414
+ const manager = new DefaultToolManager();
415
+ manager.registerTool(new EchoTool());
416
+ manager.registerTool(new ConfirmEchoTool());
417
+
418
+ const tools = manager.getTools();
419
+ expect(tools).toHaveLength(2);
420
+ expect(tools.map((t) => t.name)).toEqual(['echo', 'confirm-echo']);
421
+ });
422
+
423
+ it('toToolsSchema maps registered handlers to LLM tool schemas', () => {
424
+ const manager = new DefaultToolManager();
425
+ manager.registerTool(new EchoTool());
426
+
427
+ const schemas = manager.toToolsSchema();
428
+ expect(schemas).toHaveLength(1);
429
+ expect(schemas[0]).toMatchObject({
430
+ type: 'function',
431
+ function: { name: 'echo' },
432
+ });
433
+ });
434
+
435
+ it('getConcurrencyPolicy returns exclusive for unknown tool', () => {
436
+ const manager = new DefaultToolManager();
437
+ const policy = manager.getConcurrencyPolicy({
438
+ id: 'c1',
439
+ type: 'function',
440
+ index: 0,
441
+ function: { name: 'missing', arguments: '{}' },
442
+ });
443
+
444
+ expect(policy).toEqual({ mode: 'exclusive' });
445
+ });
446
+
447
+ it('getConcurrencyPolicy reads mode and lockKey from tool handler', () => {
448
+ const manager = new DefaultToolManager();
449
+ manager.registerTool(new ParallelReadTool());
450
+
451
+ const policy = manager.getConcurrencyPolicy({
452
+ id: 'c2',
453
+ type: 'function',
454
+ index: 0,
455
+ function: { name: 'parallel-echo', arguments: '{"input":"abc"}' },
456
+ });
457
+
458
+ expect(policy).toEqual({
459
+ mode: 'parallel-safe',
460
+ lockKey: 'resource:abc',
461
+ });
462
+ });
463
+
464
+ it('getConcurrencyPolicy returns mode-only when handler has no lock key', () => {
465
+ const manager = new DefaultToolManager();
466
+ manager.registerTool(new ParallelNoLockTool());
467
+
468
+ const policy = manager.getConcurrencyPolicy({
469
+ id: 'c5',
470
+ type: 'function',
471
+ index: 0,
472
+ function: { name: 'parallel-no-lock', arguments: '{"input":"abc"}' },
473
+ });
474
+
475
+ expect(policy).toEqual({ mode: 'parallel-safe' });
476
+ });
477
+
478
+ it('getConcurrencyPolicy falls back to exclusive for invalid json args', () => {
479
+ const manager = new DefaultToolManager();
480
+ manager.registerTool(new ParallelReadTool());
481
+
482
+ const policy = manager.getConcurrencyPolicy({
483
+ id: 'c3',
484
+ type: 'function',
485
+ index: 0,
486
+ function: { name: 'parallel-echo', arguments: '{bad' },
487
+ });
488
+
489
+ expect(policy).toEqual({ mode: 'exclusive' });
490
+ });
491
+
492
+ it('getConcurrencyPolicy falls back to exclusive for validation failure', () => {
493
+ const manager = new DefaultToolManager();
494
+ manager.registerTool(new ParallelReadTool());
495
+
496
+ const policy = manager.getConcurrencyPolicy({
497
+ id: 'c4',
498
+ type: 'function',
499
+ index: 0,
500
+ function: { name: 'parallel-echo', arguments: '{}' },
501
+ });
502
+
503
+ expect(policy).toEqual({ mode: 'exclusive' });
504
+ });
505
+ });
@@ -0,0 +1,55 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { AGENT_TOOL_TYPES_MODULE } from '../types';
3
+ import type {
4
+ Tool,
5
+ ToolCall,
6
+ ToolConfirmInfo,
7
+ ToolDecision,
8
+ ToolExecutionContext,
9
+ ToolPolicyDecision,
10
+ ToolStreamEventInput,
11
+ } from '../types';
12
+
13
+ describe('tool/types runtime contract', () => {
14
+ it('accepts representative typed objects', () => {
15
+ const tool: Tool = {
16
+ name: 'bash',
17
+ description: 'run shell command',
18
+ parameters: { type: 'object' },
19
+ };
20
+
21
+ const call: ToolCall = {
22
+ id: 'call_1',
23
+ type: 'function',
24
+ index: 0,
25
+ function: {
26
+ name: 'bash',
27
+ arguments: '{"command":"echo ok"}',
28
+ },
29
+ };
30
+
31
+ const info: ToolConfirmInfo = {
32
+ toolCallId: call.id,
33
+ toolName: tool.name,
34
+ arguments: call.function.arguments,
35
+ };
36
+
37
+ const decision: ToolDecision = { approved: true };
38
+ const policyDecision: ToolPolicyDecision = { allowed: true };
39
+ const chunk: ToolStreamEventInput = { type: 'stdout', content: 'ok' };
40
+ const context: ToolExecutionContext = {
41
+ toolCallId: call.id,
42
+ loopIndex: 1,
43
+ agent: {},
44
+ onChunk: () => undefined,
45
+ onConfirm: async () => decision,
46
+ onPolicyCheck: async () => policyDecision,
47
+ };
48
+
49
+ expect(tool.name).toBe('bash');
50
+ expect(info.toolName).toBe('bash');
51
+ expect(chunk.type).toBe('stdout');
52
+ expect(context.loopIndex).toBe(1);
53
+ expect(AGENT_TOOL_TYPES_MODULE).toBe('renx-tool-types');
54
+ });
55
+ });