tjs-lang 0.8.0 → 0.8.2

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 (86) hide show
  1. package/CLAUDE.md +15 -5
  2. package/CONTEXT.md +4 -0
  3. package/demo/docs.json +12 -690
  4. package/demo/examples.test.ts +6 -2
  5. package/demo/src/playground-shared.ts +48 -16
  6. package/demo/src/playground-test-results.test.ts +112 -0
  7. package/demo/src/tjs-playground.ts +11 -5
  8. package/dist/eslint.config.d.ts +2 -0
  9. package/dist/index.js +146 -141
  10. package/dist/index.js.map +4 -4
  11. package/dist/src/lang/core.d.ts +1 -1
  12. package/dist/src/lang/dialect.d.ts +35 -0
  13. package/dist/src/lang/emitters/ast.d.ts +1 -1
  14. package/dist/src/lang/emitters/js-tests.d.ts +7 -0
  15. package/dist/src/lang/emitters/js-wasm.d.ts +5 -1
  16. package/dist/src/lang/emitters/js.d.ts +21 -0
  17. package/dist/src/lang/index.d.ts +3 -1
  18. package/dist/src/lang/module-loader.d.ts +125 -0
  19. package/dist/src/lang/parser-transforms.d.ts +79 -0
  20. package/dist/src/lang/parser-types.d.ts +50 -0
  21. package/dist/src/lang/parser.d.ts +18 -0
  22. package/dist/src/lang/transpiler.d.ts +1 -0
  23. package/dist/src/lang/types.d.ts +18 -0
  24. package/dist/src/lang/wasm.d.ts +67 -1
  25. package/dist/src/vm/runtime.d.ts +18 -0
  26. package/dist/src/vm/vm.d.ts +15 -1
  27. package/dist/tjs-batteries.js +2 -2
  28. package/dist/tjs-batteries.js.map +2 -2
  29. package/dist/tjs-eval.js +43 -41
  30. package/dist/tjs-eval.js.map +3 -3
  31. package/dist/tjs-from-ts.js +2 -2
  32. package/dist/tjs-from-ts.js.map +2 -2
  33. package/dist/tjs-lang.js +107 -104
  34. package/dist/tjs-lang.js.map +4 -4
  35. package/dist/tjs-vm.js +53 -51
  36. package/dist/tjs-vm.js.map +3 -3
  37. package/docs/README.md +2 -0
  38. package/docs/lm-studio-setup.md +143 -0
  39. package/docs/universal-endpoint.md +122 -0
  40. package/llms.txt +9 -2
  41. package/package.json +24 -4
  42. package/src/batteries/audit.ts +6 -5
  43. package/src/batteries/llm.ts +8 -3
  44. package/src/builder.ts +0 -3
  45. package/src/cli/commands/check.ts +3 -2
  46. package/src/cli/commands/emit.ts +4 -2
  47. package/src/cli/commands/run.ts +6 -2
  48. package/src/cli/commands/test.ts +1 -1
  49. package/src/cli/commands/types.ts +2 -2
  50. package/src/lang/codegen.test.ts +4 -1
  51. package/src/lang/core.ts +6 -4
  52. package/src/lang/dialect.test.ts +63 -0
  53. package/src/lang/dialect.ts +50 -0
  54. package/src/lang/docs.test.ts +0 -1
  55. package/src/lang/emitters/ast.ts +145 -2
  56. package/src/lang/emitters/from-ts.ts +1 -1
  57. package/src/lang/emitters/js-tests.ts +46 -37
  58. package/src/lang/emitters/js.ts +19 -3
  59. package/src/lang/features.test.ts +6 -5
  60. package/src/lang/index.ts +18 -5
  61. package/src/lang/linter.ts +1 -1
  62. package/src/lang/module-loader.test.ts +9 -5
  63. package/src/lang/module-loader.ts +4 -5
  64. package/src/lang/parser-params.ts +1 -1
  65. package/src/lang/parser-transforms.ts +12 -18
  66. package/src/lang/parser-types.ts +17 -0
  67. package/src/lang/parser.test.ts +12 -6
  68. package/src/lang/parser.ts +113 -3
  69. package/src/lang/perf.test.ts +10 -4
  70. package/src/lang/runtime.ts +0 -1
  71. package/src/lang/subset-invariant.test.ts +90 -0
  72. package/src/lang/transpiler.ts +8 -0
  73. package/src/lang/types.ts +18 -0
  74. package/src/lang/wasm.test.ts +22 -16
  75. package/src/linalg/linalg.test.ts +16 -4
  76. package/src/linalg/vector-search.bench.test.ts +31 -10
  77. package/src/types/Type.ts +6 -6
  78. package/src/use-cases/asymmetric-client-server.test.ts +0 -2
  79. package/src/use-cases/batteries.test.ts +4 -0
  80. package/src/use-cases/client-server.test.ts +1 -1
  81. package/src/use-cases/local-helpers.test.ts +219 -0
  82. package/src/use-cases/timeout-overrides.test.ts +169 -0
  83. package/src/use-cases/unbundled-imports.test.ts +0 -1
  84. package/src/vm/atoms/batteries.ts +17 -3
  85. package/src/vm/runtime.ts +92 -7
  86. package/src/vm/vm.ts +50 -10
package/src/vm/vm.ts CHANGED
@@ -4,6 +4,7 @@ import {
4
4
  type RunResult,
5
5
  type RuntimeContext,
6
6
  type CostOverride,
7
+ type TimeoutOverride,
7
8
  coreAtoms,
8
9
  AgentError,
9
10
  isProcedureToken,
@@ -13,16 +14,49 @@ import { TypedBuilder, type BaseNode, type BuilderType } from '../builder'
13
14
  import { validate } from 'tosijs-schema'
14
15
  import { transpile } from '../lang/core'
15
16
 
16
- /** Default timeout multiplier: milliseconds per fuel unit */
17
- const FUEL_TO_MS = 10 // 1000 fuel = 10 seconds
17
+ /**
18
+ * Floor for the run-level default timeout. The actual default is derived from
19
+ * the registered atoms (slowest atom × 2 — see `defaultRunTimeout`), but never
20
+ * drops below this for a VM whose atoms are all fast.
21
+ */
22
+ const MIN_DEFAULT_RUN_TIMEOUT_MS = 60_000
18
23
 
19
24
  export class AgentVM<M extends Record<string, Atom<any, any>>> {
20
25
  readonly atoms: typeof coreAtoms & M
21
26
 
27
+ private _defaultRunTimeout?: number
28
+
22
29
  constructor(customAtoms: M = {} as M) {
23
30
  this.atoms = { ...coreAtoms, ...customAtoms }
24
31
  }
25
32
 
33
+ /**
34
+ * Default run-level wall-clock timeout when `run()` is given no explicit
35
+ * `timeoutMs`. Derived as `max(per-atom timeoutMs) × 2` over the registered
36
+ * atoms (with headroom for an agent that chains a couple of slow calls), so
37
+ * the run-level backstop can never be shorter than the slowest single atom's
38
+ * own budget — otherwise that per-atom budget would be dead config (e.g.
39
+ * `llmVision`/`llmPredictBattery` are 120s; a fixed 60s run default would kill
40
+ * them mid-call). Atoms with `timeoutMs: 0` (no timeout, e.g. `seq`) are
41
+ * excluded; the result is floored at {@link MIN_DEFAULT_RUN_TIMEOUT_MS}.
42
+ * Self-adjusting: registering a slower custom atom raises the default.
43
+ */
44
+ get defaultRunTimeout(): number {
45
+ if (this._defaultRunTimeout === undefined) {
46
+ let slowest = 0
47
+ for (const atom of Object.values(this.atoms)) {
48
+ // undefined timeoutMs means the per-atom default (1000ms); 0 means none.
49
+ const t = (atom as any).timeoutMs ?? 1000
50
+ if (t > 0 && t > slowest) slowest = t
51
+ }
52
+ this._defaultRunTimeout = Math.max(
53
+ MIN_DEFAULT_RUN_TIMEOUT_MS,
54
+ slowest * 2
55
+ )
56
+ }
57
+ return this._defaultRunTimeout
58
+ }
59
+
26
60
  get builder(): BuilderType<typeof coreAtoms & M> {
27
61
  return new TypedBuilder(this.atoms) as any
28
62
  }
@@ -77,9 +111,10 @@ export class AgentVM<M extends Record<string, Atom<any, any>>> {
77
111
  fuel?: number
78
112
  capabilities?: Capabilities
79
113
  trace?: boolean
80
- timeoutMs?: number // Override automatic timeout (fuel * FUEL_TO_MS)
114
+ timeoutMs?: number // Wall-clock cap on the whole run (default: slowest atom × 2, min 60s — see defaultRunTimeout)
81
115
  signal?: AbortSignal // External abort signal (e.g., from caller)
82
116
  costOverrides?: Record<string, CostOverride> // Per-atom fuel cost overrides
117
+ timeoutOverrides?: Record<string, TimeoutOverride> // Per-atom timeout overrides (ms, 0 disables)
83
118
  context?: Record<string, any> // Request-scoped metadata (auth, permissions, etc.)
84
119
  } = {}
85
120
  ): Promise<RunResult> {
@@ -94,7 +129,9 @@ export class AgentVM<M extends Record<string, Atom<any, any>>> {
94
129
  try {
95
130
  ast = transpile(astOrToken).ast as BaseNode
96
131
  } catch (e: any) {
97
- throw new Error(`AJS transpilation failed: ${e.message}`)
132
+ throw new Error(`AJS transpilation failed: ${e.message}`, {
133
+ cause: e,
134
+ })
98
135
  }
99
136
  }
100
137
  } else {
@@ -103,9 +140,10 @@ export class AgentVM<M extends Record<string, Atom<any, any>>> {
103
140
 
104
141
  const startFuel = options.fuel ?? 1000
105
142
 
106
- // Calculate timeout from fuel budget (generous: 10ms per fuel unit)
107
- // Can be overridden with explicit timeoutMs option
108
- const timeoutMs = options.timeoutMs ?? startFuel * FUEL_TO_MS
143
+ // Run-level wall-clock timeout. Agents are typically IO-bound; the default
144
+ // is derived from the registered atoms (slowest × 2) so it always covers the
145
+ // slowest atom's own budget. See `defaultRunTimeout`.
146
+ const timeoutMs = options.timeoutMs ?? this.defaultRunTimeout
109
147
 
110
148
  // Default Capabilities
111
149
  const capabilities = options.capabilities ?? {}
@@ -158,8 +196,10 @@ export class AgentVM<M extends Record<string, Atom<any, any>>> {
158
196
  output: undefined,
159
197
  signal: controller.signal,
160
198
  costOverrides: options.costOverrides,
199
+ timeoutOverrides: options.timeoutOverrides,
161
200
  context: options.context,
162
201
  warnings, // Shared warnings array
202
+ helpers: (ast as any).helpers, // Local helper bodies, called by name via callLocal
163
203
  }
164
204
 
165
205
  if (options.trace) {
@@ -195,7 +235,7 @@ export class AgentVM<M extends Record<string, Atom<any, any>>> {
195
235
  controller.signal.addEventListener('abort', () => {
196
236
  reject(
197
237
  new Error(
198
- `Execution timeout after ${timeoutMs}ms (fuel: ${startFuel}). Consider increasing fuel or optimizing your agent.`
238
+ `Execution timeout after ${timeoutMs}ms. Pass a higher \`timeoutMs\` to vm.run() or set per-atom \`timeoutOverrides\` for slow IO atoms.`
199
239
  )
200
240
  )
201
241
  })
@@ -203,7 +243,7 @@ export class AgentVM<M extends Record<string, Atom<any, any>>> {
203
243
  if (controller.signal.aborted) {
204
244
  reject(
205
245
  new Error(
206
- `Execution timeout after ${timeoutMs}ms (fuel: ${startFuel}). Consider increasing fuel or optimizing your agent.`
246
+ `Execution timeout after ${timeoutMs}ms. Pass a higher \`timeoutMs\` to vm.run() or set per-atom \`timeoutOverrides\` for slow IO atoms.`
207
247
  )
208
248
  )
209
249
  }
@@ -217,7 +257,7 @@ export class AgentVM<M extends Record<string, Atom<any, any>>> {
217
257
  controller.signal.aborted
218
258
  ) {
219
259
  ctx.error = new AgentError(
220
- `Execution timeout after ${timeoutMs}ms (fuel: ${startFuel}). Consider increasing fuel or optimizing your agent.`,
260
+ `Execution timeout after ${timeoutMs}ms. Pass a higher \`timeoutMs\` to vm.run() or set per-atom \`timeoutOverrides\` for slow IO atoms.`,
221
261
  'vm.run'
222
262
  )
223
263
  } else {