@vibe-lang/runtime 0.2.5

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 (250) hide show
  1. package/package.json +46 -0
  2. package/src/ast/index.ts +375 -0
  3. package/src/ast.ts +2 -0
  4. package/src/debug/advanced-features.ts +482 -0
  5. package/src/debug/bun-inspector.ts +424 -0
  6. package/src/debug/handoff-manager.ts +283 -0
  7. package/src/debug/index.ts +150 -0
  8. package/src/debug/runner.ts +365 -0
  9. package/src/debug/server.ts +565 -0
  10. package/src/debug/stack-merger.ts +267 -0
  11. package/src/debug/state.ts +581 -0
  12. package/src/debug/test/advanced-features.test.ts +300 -0
  13. package/src/debug/test/e2e.test.ts +218 -0
  14. package/src/debug/test/handoff-manager.test.ts +256 -0
  15. package/src/debug/test/runner.test.ts +256 -0
  16. package/src/debug/test/stack-merger.test.ts +163 -0
  17. package/src/debug/test/state.test.ts +400 -0
  18. package/src/debug/test/ts-debug-integration.test.ts +374 -0
  19. package/src/debug/test/ts-import-tracker.test.ts +125 -0
  20. package/src/debug/test/ts-source-map.test.ts +169 -0
  21. package/src/debug/ts-import-tracker.ts +151 -0
  22. package/src/debug/ts-source-map.ts +171 -0
  23. package/src/errors/index.ts +124 -0
  24. package/src/index.ts +358 -0
  25. package/src/lexer/index.ts +348 -0
  26. package/src/lexer.ts +2 -0
  27. package/src/parser/index.ts +792 -0
  28. package/src/parser/parse.ts +45 -0
  29. package/src/parser/test/async.test.ts +248 -0
  30. package/src/parser/test/destructuring.test.ts +167 -0
  31. package/src/parser/test/do-expression.test.ts +486 -0
  32. package/src/parser/test/errors/do-expression.test.ts +95 -0
  33. package/src/parser/test/errors/error-locations.test.ts +230 -0
  34. package/src/parser/test/errors/invalid-expressions.test.ts +144 -0
  35. package/src/parser/test/errors/missing-tokens.test.ts +126 -0
  36. package/src/parser/test/errors/model-declaration.test.ts +185 -0
  37. package/src/parser/test/errors/nested-blocks.test.ts +226 -0
  38. package/src/parser/test/errors/unclosed-delimiters.test.ts +122 -0
  39. package/src/parser/test/errors/unexpected-tokens.test.ts +120 -0
  40. package/src/parser/test/import-export.test.ts +143 -0
  41. package/src/parser/test/literals.test.ts +404 -0
  42. package/src/parser/test/model-declaration.test.ts +161 -0
  43. package/src/parser/test/nested-blocks.test.ts +402 -0
  44. package/src/parser/test/parser.test.ts +743 -0
  45. package/src/parser/test/private.test.ts +136 -0
  46. package/src/parser/test/template-literal.test.ts +127 -0
  47. package/src/parser/test/tool-declaration.test.ts +302 -0
  48. package/src/parser/test/ts-block.test.ts +252 -0
  49. package/src/parser/test/type-annotations.test.ts +254 -0
  50. package/src/parser/visitor/helpers.ts +330 -0
  51. package/src/parser/visitor.ts +794 -0
  52. package/src/parser.ts +2 -0
  53. package/src/runtime/ai/cache-chunking.test.ts +69 -0
  54. package/src/runtime/ai/cache-chunking.ts +73 -0
  55. package/src/runtime/ai/client.ts +109 -0
  56. package/src/runtime/ai/context.ts +168 -0
  57. package/src/runtime/ai/formatters.ts +316 -0
  58. package/src/runtime/ai/index.ts +38 -0
  59. package/src/runtime/ai/language-ref.ts +38 -0
  60. package/src/runtime/ai/providers/anthropic.ts +253 -0
  61. package/src/runtime/ai/providers/google.ts +201 -0
  62. package/src/runtime/ai/providers/openai.ts +156 -0
  63. package/src/runtime/ai/retry.ts +100 -0
  64. package/src/runtime/ai/return-tools.ts +301 -0
  65. package/src/runtime/ai/test/client.test.ts +83 -0
  66. package/src/runtime/ai/test/formatters.test.ts +485 -0
  67. package/src/runtime/ai/test/retry.test.ts +137 -0
  68. package/src/runtime/ai/test/return-tools.test.ts +450 -0
  69. package/src/runtime/ai/test/tool-loop.test.ts +319 -0
  70. package/src/runtime/ai/test/tool-schema.test.ts +241 -0
  71. package/src/runtime/ai/tool-loop.ts +203 -0
  72. package/src/runtime/ai/tool-schema.ts +151 -0
  73. package/src/runtime/ai/types.ts +113 -0
  74. package/src/runtime/ai-logger.ts +255 -0
  75. package/src/runtime/ai-provider.ts +347 -0
  76. package/src/runtime/async/dependencies.ts +276 -0
  77. package/src/runtime/async/executor.ts +293 -0
  78. package/src/runtime/async/index.ts +43 -0
  79. package/src/runtime/async/scheduling.ts +163 -0
  80. package/src/runtime/async/test/dependencies.test.ts +284 -0
  81. package/src/runtime/async/test/executor.test.ts +388 -0
  82. package/src/runtime/context.ts +357 -0
  83. package/src/runtime/exec/ai.ts +139 -0
  84. package/src/runtime/exec/expressions.ts +475 -0
  85. package/src/runtime/exec/frames.ts +26 -0
  86. package/src/runtime/exec/functions.ts +305 -0
  87. package/src/runtime/exec/interpolation.ts +312 -0
  88. package/src/runtime/exec/statements.ts +604 -0
  89. package/src/runtime/exec/tools.ts +129 -0
  90. package/src/runtime/exec/typescript.ts +215 -0
  91. package/src/runtime/exec/variables.ts +279 -0
  92. package/src/runtime/index.ts +975 -0
  93. package/src/runtime/modules.ts +452 -0
  94. package/src/runtime/serialize.ts +103 -0
  95. package/src/runtime/state.ts +489 -0
  96. package/src/runtime/stdlib/core.ts +45 -0
  97. package/src/runtime/stdlib/directory.test.ts +156 -0
  98. package/src/runtime/stdlib/edit.test.ts +154 -0
  99. package/src/runtime/stdlib/fastEdit.test.ts +201 -0
  100. package/src/runtime/stdlib/glob.test.ts +106 -0
  101. package/src/runtime/stdlib/grep.test.ts +144 -0
  102. package/src/runtime/stdlib/index.ts +16 -0
  103. package/src/runtime/stdlib/readFile.test.ts +123 -0
  104. package/src/runtime/stdlib/tools/index.ts +707 -0
  105. package/src/runtime/stdlib/writeFile.test.ts +157 -0
  106. package/src/runtime/step.ts +969 -0
  107. package/src/runtime/test/ai-context.test.ts +1086 -0
  108. package/src/runtime/test/ai-result-object.test.ts +419 -0
  109. package/src/runtime/test/ai-tool-flow.test.ts +859 -0
  110. package/src/runtime/test/async-execution-order.test.ts +618 -0
  111. package/src/runtime/test/async-execution.test.ts +344 -0
  112. package/src/runtime/test/async-nested.test.ts +660 -0
  113. package/src/runtime/test/async-parallel-timing.test.ts +546 -0
  114. package/src/runtime/test/basic1.test.ts +154 -0
  115. package/src/runtime/test/binary-operators.test.ts +431 -0
  116. package/src/runtime/test/break-statement.test.ts +257 -0
  117. package/src/runtime/test/context-modes.test.ts +650 -0
  118. package/src/runtime/test/context.test.ts +466 -0
  119. package/src/runtime/test/core-functions.test.ts +228 -0
  120. package/src/runtime/test/e2e.test.ts +88 -0
  121. package/src/runtime/test/error-locations/error-locations.test.ts +80 -0
  122. package/src/runtime/test/error-locations/main-error.vibe +4 -0
  123. package/src/runtime/test/error-locations/main-import-error.vibe +3 -0
  124. package/src/runtime/test/error-locations/utils/helper.vibe +5 -0
  125. package/src/runtime/test/for-in.test.ts +312 -0
  126. package/src/runtime/test/helpers.ts +69 -0
  127. package/src/runtime/test/imports.test.ts +334 -0
  128. package/src/runtime/test/json-expressions.test.ts +232 -0
  129. package/src/runtime/test/literals.test.ts +372 -0
  130. package/src/runtime/test/logical-indexing.test.ts +478 -0
  131. package/src/runtime/test/member-methods.test.ts +324 -0
  132. package/src/runtime/test/model-config.test.ts +338 -0
  133. package/src/runtime/test/null-handling.test.ts +342 -0
  134. package/src/runtime/test/private-visibility.test.ts +332 -0
  135. package/src/runtime/test/runtime-state.test.ts +514 -0
  136. package/src/runtime/test/scoping.test.ts +370 -0
  137. package/src/runtime/test/string-interpolation.test.ts +354 -0
  138. package/src/runtime/test/template-literal.test.ts +181 -0
  139. package/src/runtime/test/tool-execution.test.ts +467 -0
  140. package/src/runtime/test/tool-schema-generation.test.ts +477 -0
  141. package/src/runtime/test/tostring.test.ts +210 -0
  142. package/src/runtime/test/ts-block.test.ts +594 -0
  143. package/src/runtime/test/ts-error-location.test.ts +231 -0
  144. package/src/runtime/test/types.test.ts +732 -0
  145. package/src/runtime/test/verbose-logger.test.ts +710 -0
  146. package/src/runtime/test/vibe-expression.test.ts +54 -0
  147. package/src/runtime/test/vibe-value-errors.test.ts +541 -0
  148. package/src/runtime/test/while.test.ts +232 -0
  149. package/src/runtime/tools/builtin.ts +30 -0
  150. package/src/runtime/tools/directory-tools.ts +70 -0
  151. package/src/runtime/tools/file-tools.ts +228 -0
  152. package/src/runtime/tools/index.ts +5 -0
  153. package/src/runtime/tools/registry.ts +48 -0
  154. package/src/runtime/tools/search-tools.ts +134 -0
  155. package/src/runtime/tools/security.ts +36 -0
  156. package/src/runtime/tools/system-tools.ts +312 -0
  157. package/src/runtime/tools/test/fixtures/base-types.ts +40 -0
  158. package/src/runtime/tools/test/fixtures/test-types.ts +132 -0
  159. package/src/runtime/tools/test/registry.test.ts +713 -0
  160. package/src/runtime/tools/test/security.test.ts +86 -0
  161. package/src/runtime/tools/test/system-tools.test.ts +679 -0
  162. package/src/runtime/tools/test/ts-schema.test.ts +357 -0
  163. package/src/runtime/tools/ts-schema.ts +341 -0
  164. package/src/runtime/tools/types.ts +89 -0
  165. package/src/runtime/tools/utility-tools.ts +198 -0
  166. package/src/runtime/ts-eval.ts +126 -0
  167. package/src/runtime/types.ts +797 -0
  168. package/src/runtime/validation.ts +160 -0
  169. package/src/runtime/verbose-logger.ts +459 -0
  170. package/src/runtime.ts +2 -0
  171. package/src/semantic/analyzer-context.ts +62 -0
  172. package/src/semantic/analyzer-validators.ts +575 -0
  173. package/src/semantic/analyzer-visitors.ts +534 -0
  174. package/src/semantic/analyzer.ts +83 -0
  175. package/src/semantic/index.ts +11 -0
  176. package/src/semantic/symbol-table.ts +58 -0
  177. package/src/semantic/test/async-validation.test.ts +301 -0
  178. package/src/semantic/test/compress-validation.test.ts +179 -0
  179. package/src/semantic/test/const-reassignment.test.ts +111 -0
  180. package/src/semantic/test/control-flow.test.ts +346 -0
  181. package/src/semantic/test/destructuring.test.ts +185 -0
  182. package/src/semantic/test/duplicate-declarations.test.ts +168 -0
  183. package/src/semantic/test/export-validation.test.ts +111 -0
  184. package/src/semantic/test/fixtures/math.ts +31 -0
  185. package/src/semantic/test/imports.test.ts +148 -0
  186. package/src/semantic/test/json-type.test.ts +68 -0
  187. package/src/semantic/test/literals.test.ts +127 -0
  188. package/src/semantic/test/model-validation.test.ts +179 -0
  189. package/src/semantic/test/prompt-validation.test.ts +343 -0
  190. package/src/semantic/test/scoping.test.ts +312 -0
  191. package/src/semantic/test/tool-validation.test.ts +306 -0
  192. package/src/semantic/test/ts-type-checking.test.ts +563 -0
  193. package/src/semantic/test/type-constraints.test.ts +111 -0
  194. package/src/semantic/test/type-inference.test.ts +87 -0
  195. package/src/semantic/test/type-validation.test.ts +552 -0
  196. package/src/semantic/test/undefined-variables.test.ts +163 -0
  197. package/src/semantic/ts-block-checker.ts +204 -0
  198. package/src/semantic/ts-signatures.ts +194 -0
  199. package/src/semantic/ts-types.ts +170 -0
  200. package/src/semantic/types.ts +58 -0
  201. package/tests/fixtures/conditional-logic.vibe +14 -0
  202. package/tests/fixtures/function-call.vibe +16 -0
  203. package/tests/fixtures/imports/cycle-detection/a.vibe +6 -0
  204. package/tests/fixtures/imports/cycle-detection/b.vibe +5 -0
  205. package/tests/fixtures/imports/cycle-detection/main.vibe +3 -0
  206. package/tests/fixtures/imports/module-isolation/main-b.vibe +8 -0
  207. package/tests/fixtures/imports/module-isolation/main.vibe +9 -0
  208. package/tests/fixtures/imports/module-isolation/moduleA.vibe +6 -0
  209. package/tests/fixtures/imports/module-isolation/moduleB.vibe +6 -0
  210. package/tests/fixtures/imports/nested-import/helper.vibe +6 -0
  211. package/tests/fixtures/imports/nested-import/main.vibe +3 -0
  212. package/tests/fixtures/imports/nested-import/utils.ts +3 -0
  213. package/tests/fixtures/imports/nested-isolation/file2.vibe +15 -0
  214. package/tests/fixtures/imports/nested-isolation/file3.vibe +10 -0
  215. package/tests/fixtures/imports/nested-isolation/main.vibe +21 -0
  216. package/tests/fixtures/imports/pure-cycle/a.vibe +5 -0
  217. package/tests/fixtures/imports/pure-cycle/b.vibe +5 -0
  218. package/tests/fixtures/imports/pure-cycle/main.vibe +3 -0
  219. package/tests/fixtures/imports/ts-boolean/checks.ts +14 -0
  220. package/tests/fixtures/imports/ts-boolean/main.vibe +10 -0
  221. package/tests/fixtures/imports/ts-boolean/type-mismatch.vibe +5 -0
  222. package/tests/fixtures/imports/ts-boolean/use-constant.vibe +18 -0
  223. package/tests/fixtures/imports/ts-error-handling/helpers.ts +42 -0
  224. package/tests/fixtures/imports/ts-error-handling/main.vibe +5 -0
  225. package/tests/fixtures/imports/ts-import/main.vibe +4 -0
  226. package/tests/fixtures/imports/ts-import/math.ts +9 -0
  227. package/tests/fixtures/imports/ts-variables/call-non-function.vibe +5 -0
  228. package/tests/fixtures/imports/ts-variables/data.ts +10 -0
  229. package/tests/fixtures/imports/ts-variables/import-json.vibe +5 -0
  230. package/tests/fixtures/imports/ts-variables/import-type-mismatch.vibe +5 -0
  231. package/tests/fixtures/imports/ts-variables/import-variable.vibe +5 -0
  232. package/tests/fixtures/imports/vibe-import/greet.vibe +5 -0
  233. package/tests/fixtures/imports/vibe-import/main.vibe +3 -0
  234. package/tests/fixtures/multiple-ai-calls.vibe +10 -0
  235. package/tests/fixtures/simple-greeting.vibe +6 -0
  236. package/tests/fixtures/template-literals.vibe +11 -0
  237. package/tests/integration/basic-ai/basic-ai.integration.test.ts +166 -0
  238. package/tests/integration/basic-ai/basic-ai.vibe +12 -0
  239. package/tests/integration/bug-fix/bug-fix.integration.test.ts +201 -0
  240. package/tests/integration/bug-fix/buggy-code.ts +22 -0
  241. package/tests/integration/bug-fix/fix-bug.vibe +21 -0
  242. package/tests/integration/compress/compress.integration.test.ts +206 -0
  243. package/tests/integration/destructuring/destructuring.integration.test.ts +92 -0
  244. package/tests/integration/hello-world-translator/hello-world-translator.integration.test.ts +61 -0
  245. package/tests/integration/line-annotator/context-modes.integration.test.ts +261 -0
  246. package/tests/integration/line-annotator/line-annotator.integration.test.ts +148 -0
  247. package/tests/integration/multi-feature/cumulative-sum.integration.test.ts +75 -0
  248. package/tests/integration/multi-feature/number-analyzer.integration.test.ts +191 -0
  249. package/tests/integration/multi-feature/number-analyzer.vibe +59 -0
  250. package/tests/integration/tool-calls/tool-calls.integration.test.ts +93 -0
@@ -0,0 +1,306 @@
1
+ import { describe, expect, test } from 'bun:test';
2
+ import { parse } from '../../parser/parse';
3
+ import { analyze } from '../index';
4
+
5
+ describe('Semantic Analysis - Tool Declaration', () => {
6
+ // ============================================================================
7
+ // @param decorator validation
8
+ // ============================================================================
9
+
10
+ describe('@param decorator validation', () => {
11
+ test('valid @param referencing existing parameter', () => {
12
+ const ast = parse(`
13
+ tool greet(name: text): text
14
+ @description "Greet someone"
15
+ @param name "The person's name"
16
+ {
17
+ ts(name) { return "Hello, " + name }
18
+ }
19
+ `);
20
+ const errors = analyze(ast);
21
+ expect(errors).toHaveLength(0);
22
+ });
23
+
24
+ test('valid @param for multiple parameters', () => {
25
+ const ast = parse(`
26
+ tool calculate(x: number, y: number, op: text): number
27
+ @description "Calculate"
28
+ @param x "First operand"
29
+ @param y "Second operand"
30
+ @param op "Operation"
31
+ {
32
+ ts(x, y, op) { return x + y }
33
+ }
34
+ `);
35
+ const errors = analyze(ast);
36
+ expect(errors).toHaveLength(0);
37
+ });
38
+
39
+ test('error when @param references non-existent parameter', () => {
40
+ const ast = parse(`
41
+ tool greet(name: text): text
42
+ @description "Greet someone"
43
+ @param nonexistent "This param does not exist"
44
+ {
45
+ ts(name) { return "Hello, " + name }
46
+ }
47
+ `);
48
+ const errors = analyze(ast);
49
+ expect(errors).toHaveLength(1);
50
+ expect(errors[0].message).toContain("@param 'nonexistent' does not match any parameter");
51
+ expect(errors[0].message).toContain("Valid parameters: name");
52
+ });
53
+
54
+ test('error when @param references non-existent parameter among multiple', () => {
55
+ const ast = parse(`
56
+ tool sendEmail(to: text, subject: text): boolean
57
+ @description "Send email"
58
+ @param to "Recipient"
59
+ @param body "This param does not exist"
60
+ {
61
+ ts(to, subject) { return true }
62
+ }
63
+ `);
64
+ const errors = analyze(ast);
65
+ expect(errors).toHaveLength(1);
66
+ expect(errors[0].message).toContain("@param 'body' does not match any parameter");
67
+ expect(errors[0].message).toContain("Valid parameters: to, subject");
68
+ });
69
+
70
+ test('error when @param used on tool with no parameters', () => {
71
+ const ast = parse(`
72
+ tool getCurrentTime(): text
73
+ @description "Get current time"
74
+ @param time "There are no params"
75
+ {
76
+ ts() { return new Date().toISOString() }
77
+ }
78
+ `);
79
+ const errors = analyze(ast);
80
+ expect(errors).toHaveLength(1);
81
+ expect(errors[0].message).toContain("@param 'time' does not match any parameter");
82
+ expect(errors[0].message).toContain("Valid parameters: (none)");
83
+ });
84
+
85
+ test('multiple @param errors reported', () => {
86
+ const ast = parse(`
87
+ tool greet(name: text): text
88
+ @description "Greet"
89
+ @param foo "Does not exist"
90
+ @param bar "Also does not exist"
91
+ {
92
+ ts(name) { return "Hello" }
93
+ }
94
+ `);
95
+ const errors = analyze(ast);
96
+ expect(errors).toHaveLength(2);
97
+ expect(errors[0].message).toContain("@param 'foo'");
98
+ expect(errors[1].message).toContain("@param 'bar'");
99
+ });
100
+
101
+ test('partial valid @params with one invalid', () => {
102
+ const ast = parse(`
103
+ tool search(query: text, limit: number): json
104
+ @description "Search"
105
+ @param query "Search query"
106
+ @param typo "This is a typo"
107
+ @param limit "Max results"
108
+ {
109
+ ts(query, limit) { return [] }
110
+ }
111
+ `);
112
+ const errors = analyze(ast);
113
+ expect(errors).toHaveLength(1);
114
+ expect(errors[0].message).toContain("@param 'typo'");
115
+ });
116
+ });
117
+
118
+ // ============================================================================
119
+ // Tool type validation
120
+ // ============================================================================
121
+
122
+ describe('Tool type validation', () => {
123
+ test('valid Vibe types in parameters', () => {
124
+ const ast = parse(`
125
+ tool test(a: text, b: number, c: boolean, d: json): text
126
+ @description "Test"
127
+ {
128
+ ts(a, b, c, d) { return a }
129
+ }
130
+ `);
131
+ const errors = analyze(ast);
132
+ expect(errors).toHaveLength(0);
133
+ });
134
+
135
+ test('valid array types in parameters', () => {
136
+ const ast = parse(`
137
+ tool test(items: text[], numbers: number[]): json[]
138
+ @description "Test"
139
+ {
140
+ ts(items, numbers) { return [] }
141
+ }
142
+ `);
143
+ const errors = analyze(ast);
144
+ expect(errors).toHaveLength(0);
145
+ });
146
+
147
+ test('error for unknown type in parameter', () => {
148
+ const ast = parse(`
149
+ tool test(data: UnknownType): text
150
+ @description "Test"
151
+ {
152
+ ts(data) { return "" }
153
+ }
154
+ `);
155
+ const errors = analyze(ast);
156
+ expect(errors).toHaveLength(1);
157
+ expect(errors[0].message).toContain("Unknown type 'UnknownType'");
158
+ });
159
+
160
+ test('error for unknown return type', () => {
161
+ const ast = parse(`
162
+ tool test(name: text): UnknownReturn
163
+ @description "Test"
164
+ {
165
+ ts(name) { return {} }
166
+ }
167
+ `);
168
+ const errors = analyze(ast);
169
+ expect(errors).toHaveLength(1);
170
+ expect(errors[0].message).toContain("Unknown return type 'UnknownReturn'");
171
+ });
172
+
173
+ test('imported type is valid when imported', () => {
174
+ const ast = parse(`
175
+ import { CustomerInfo } from "./types.ts"
176
+
177
+ tool processCustomer(info: CustomerInfo): json
178
+ @description "Process customer"
179
+ {
180
+ ts(info) { return {} }
181
+ }
182
+ `);
183
+ const errors = analyze(ast);
184
+ expect(errors).toHaveLength(0);
185
+ });
186
+ });
187
+
188
+ // ============================================================================
189
+ // Tool scope validation
190
+ // ============================================================================
191
+
192
+ describe('Tool scope validation', () => {
193
+ test('tool at global scope is valid', () => {
194
+ const ast = parse(`
195
+ tool greet(name: text): text
196
+ @description "Greet"
197
+ {
198
+ ts(name) { return "Hello" }
199
+ }
200
+ `);
201
+ const errors = analyze(ast);
202
+ expect(errors).toHaveLength(0);
203
+ });
204
+
205
+ // Note: Parser currently doesn't allow tools inside blocks,
206
+ // so this test documents that behavior would be caught
207
+ // if it were syntactically allowed
208
+ });
209
+
210
+ // ============================================================================
211
+ // Tool call validation - tools cannot be called directly
212
+ // ============================================================================
213
+
214
+ describe('Tool call validation', () => {
215
+ test('error when calling user-defined tool directly', () => {
216
+ const ast = parse(`
217
+ tool greet(name: text): text
218
+ @description "Greet"
219
+ {
220
+ ts(name) { return "Hello, " + name }
221
+ }
222
+
223
+ let result = greet("World")
224
+ `);
225
+ const errors = analyze(ast);
226
+ expect(errors).toHaveLength(1);
227
+ expect(errors[0].message).toContain("Cannot call tool 'greet' directly");
228
+ expect(errors[0].message).toContain("Tools can only be used by AI models");
229
+ });
230
+
231
+ test('error when calling imported tool directly', () => {
232
+ const ast = parse(`
233
+ import { now } from "system/tools"
234
+ let timestamp = now()
235
+ `);
236
+ const errors = analyze(ast);
237
+ expect(errors).toHaveLength(1);
238
+ expect(errors[0].message).toContain("Cannot call tool 'now' directly");
239
+ });
240
+
241
+ test('error when calling multiple tools directly', () => {
242
+ const ast = parse(`
243
+ import { readFile, writeFile } from "system/tools"
244
+ let content = readFile("test.txt")
245
+ let _ = writeFile("out.txt", "data")
246
+ `);
247
+ const errors = analyze(ast);
248
+ expect(errors).toHaveLength(2);
249
+ expect(errors[0].message).toContain("Cannot call tool 'readFile' directly");
250
+ expect(errors[1].message).toContain("Cannot call tool 'writeFile' directly");
251
+ });
252
+
253
+ test('no error when tool is used in model tools array', () => {
254
+ const ast = parse(`
255
+ tool greet(name: text): text
256
+ @description "Greet"
257
+ {
258
+ ts(name) { return "Hello, " + name }
259
+ }
260
+
261
+ model m = {
262
+ name: "gpt-4",
263
+ apiKey: "key",
264
+ url: "https://api.openai.com",
265
+ tools: [greet]
266
+ }
267
+ `);
268
+ const errors = analyze(ast);
269
+ expect(errors).toHaveLength(0);
270
+ });
271
+
272
+ test('no error when allTools is imported and used in model', () => {
273
+ const ast = parse(`
274
+ import { allTools } from "system/tools"
275
+
276
+ model m = {
277
+ name: "gpt-4",
278
+ apiKey: "key",
279
+ url: "https://api.openai.com",
280
+ tools: allTools
281
+ }
282
+ `);
283
+ const errors = analyze(ast);
284
+ expect(errors).toHaveLength(0);
285
+ });
286
+
287
+ test('tool declaration is valid but calling it is not', () => {
288
+ const ast = parse(`
289
+ tool double(n: number): number
290
+ @description "Double a number"
291
+ {
292
+ ts(n) { return n * 2 }
293
+ }
294
+
295
+ // Just referencing the tool is fine (e.g., for model tools array)
296
+ let toolRef = double
297
+
298
+ // But calling it is not allowed
299
+ let result = double(21)
300
+ `);
301
+ const errors = analyze(ast);
302
+ expect(errors).toHaveLength(1);
303
+ expect(errors[0].message).toContain("Cannot call tool 'double' directly");
304
+ });
305
+ });
306
+ });