@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.
- package/package.json +46 -0
- package/src/ast/index.ts +375 -0
- package/src/ast.ts +2 -0
- package/src/debug/advanced-features.ts +482 -0
- package/src/debug/bun-inspector.ts +424 -0
- package/src/debug/handoff-manager.ts +283 -0
- package/src/debug/index.ts +150 -0
- package/src/debug/runner.ts +365 -0
- package/src/debug/server.ts +565 -0
- package/src/debug/stack-merger.ts +267 -0
- package/src/debug/state.ts +581 -0
- package/src/debug/test/advanced-features.test.ts +300 -0
- package/src/debug/test/e2e.test.ts +218 -0
- package/src/debug/test/handoff-manager.test.ts +256 -0
- package/src/debug/test/runner.test.ts +256 -0
- package/src/debug/test/stack-merger.test.ts +163 -0
- package/src/debug/test/state.test.ts +400 -0
- package/src/debug/test/ts-debug-integration.test.ts +374 -0
- package/src/debug/test/ts-import-tracker.test.ts +125 -0
- package/src/debug/test/ts-source-map.test.ts +169 -0
- package/src/debug/ts-import-tracker.ts +151 -0
- package/src/debug/ts-source-map.ts +171 -0
- package/src/errors/index.ts +124 -0
- package/src/index.ts +358 -0
- package/src/lexer/index.ts +348 -0
- package/src/lexer.ts +2 -0
- package/src/parser/index.ts +792 -0
- package/src/parser/parse.ts +45 -0
- package/src/parser/test/async.test.ts +248 -0
- package/src/parser/test/destructuring.test.ts +167 -0
- package/src/parser/test/do-expression.test.ts +486 -0
- package/src/parser/test/errors/do-expression.test.ts +95 -0
- package/src/parser/test/errors/error-locations.test.ts +230 -0
- package/src/parser/test/errors/invalid-expressions.test.ts +144 -0
- package/src/parser/test/errors/missing-tokens.test.ts +126 -0
- package/src/parser/test/errors/model-declaration.test.ts +185 -0
- package/src/parser/test/errors/nested-blocks.test.ts +226 -0
- package/src/parser/test/errors/unclosed-delimiters.test.ts +122 -0
- package/src/parser/test/errors/unexpected-tokens.test.ts +120 -0
- package/src/parser/test/import-export.test.ts +143 -0
- package/src/parser/test/literals.test.ts +404 -0
- package/src/parser/test/model-declaration.test.ts +161 -0
- package/src/parser/test/nested-blocks.test.ts +402 -0
- package/src/parser/test/parser.test.ts +743 -0
- package/src/parser/test/private.test.ts +136 -0
- package/src/parser/test/template-literal.test.ts +127 -0
- package/src/parser/test/tool-declaration.test.ts +302 -0
- package/src/parser/test/ts-block.test.ts +252 -0
- package/src/parser/test/type-annotations.test.ts +254 -0
- package/src/parser/visitor/helpers.ts +330 -0
- package/src/parser/visitor.ts +794 -0
- package/src/parser.ts +2 -0
- package/src/runtime/ai/cache-chunking.test.ts +69 -0
- package/src/runtime/ai/cache-chunking.ts +73 -0
- package/src/runtime/ai/client.ts +109 -0
- package/src/runtime/ai/context.ts +168 -0
- package/src/runtime/ai/formatters.ts +316 -0
- package/src/runtime/ai/index.ts +38 -0
- package/src/runtime/ai/language-ref.ts +38 -0
- package/src/runtime/ai/providers/anthropic.ts +253 -0
- package/src/runtime/ai/providers/google.ts +201 -0
- package/src/runtime/ai/providers/openai.ts +156 -0
- package/src/runtime/ai/retry.ts +100 -0
- package/src/runtime/ai/return-tools.ts +301 -0
- package/src/runtime/ai/test/client.test.ts +83 -0
- package/src/runtime/ai/test/formatters.test.ts +485 -0
- package/src/runtime/ai/test/retry.test.ts +137 -0
- package/src/runtime/ai/test/return-tools.test.ts +450 -0
- package/src/runtime/ai/test/tool-loop.test.ts +319 -0
- package/src/runtime/ai/test/tool-schema.test.ts +241 -0
- package/src/runtime/ai/tool-loop.ts +203 -0
- package/src/runtime/ai/tool-schema.ts +151 -0
- package/src/runtime/ai/types.ts +113 -0
- package/src/runtime/ai-logger.ts +255 -0
- package/src/runtime/ai-provider.ts +347 -0
- package/src/runtime/async/dependencies.ts +276 -0
- package/src/runtime/async/executor.ts +293 -0
- package/src/runtime/async/index.ts +43 -0
- package/src/runtime/async/scheduling.ts +163 -0
- package/src/runtime/async/test/dependencies.test.ts +284 -0
- package/src/runtime/async/test/executor.test.ts +388 -0
- package/src/runtime/context.ts +357 -0
- package/src/runtime/exec/ai.ts +139 -0
- package/src/runtime/exec/expressions.ts +475 -0
- package/src/runtime/exec/frames.ts +26 -0
- package/src/runtime/exec/functions.ts +305 -0
- package/src/runtime/exec/interpolation.ts +312 -0
- package/src/runtime/exec/statements.ts +604 -0
- package/src/runtime/exec/tools.ts +129 -0
- package/src/runtime/exec/typescript.ts +215 -0
- package/src/runtime/exec/variables.ts +279 -0
- package/src/runtime/index.ts +975 -0
- package/src/runtime/modules.ts +452 -0
- package/src/runtime/serialize.ts +103 -0
- package/src/runtime/state.ts +489 -0
- package/src/runtime/stdlib/core.ts +45 -0
- package/src/runtime/stdlib/directory.test.ts +156 -0
- package/src/runtime/stdlib/edit.test.ts +154 -0
- package/src/runtime/stdlib/fastEdit.test.ts +201 -0
- package/src/runtime/stdlib/glob.test.ts +106 -0
- package/src/runtime/stdlib/grep.test.ts +144 -0
- package/src/runtime/stdlib/index.ts +16 -0
- package/src/runtime/stdlib/readFile.test.ts +123 -0
- package/src/runtime/stdlib/tools/index.ts +707 -0
- package/src/runtime/stdlib/writeFile.test.ts +157 -0
- package/src/runtime/step.ts +969 -0
- package/src/runtime/test/ai-context.test.ts +1086 -0
- package/src/runtime/test/ai-result-object.test.ts +419 -0
- package/src/runtime/test/ai-tool-flow.test.ts +859 -0
- package/src/runtime/test/async-execution-order.test.ts +618 -0
- package/src/runtime/test/async-execution.test.ts +344 -0
- package/src/runtime/test/async-nested.test.ts +660 -0
- package/src/runtime/test/async-parallel-timing.test.ts +546 -0
- package/src/runtime/test/basic1.test.ts +154 -0
- package/src/runtime/test/binary-operators.test.ts +431 -0
- package/src/runtime/test/break-statement.test.ts +257 -0
- package/src/runtime/test/context-modes.test.ts +650 -0
- package/src/runtime/test/context.test.ts +466 -0
- package/src/runtime/test/core-functions.test.ts +228 -0
- package/src/runtime/test/e2e.test.ts +88 -0
- package/src/runtime/test/error-locations/error-locations.test.ts +80 -0
- package/src/runtime/test/error-locations/main-error.vibe +4 -0
- package/src/runtime/test/error-locations/main-import-error.vibe +3 -0
- package/src/runtime/test/error-locations/utils/helper.vibe +5 -0
- package/src/runtime/test/for-in.test.ts +312 -0
- package/src/runtime/test/helpers.ts +69 -0
- package/src/runtime/test/imports.test.ts +334 -0
- package/src/runtime/test/json-expressions.test.ts +232 -0
- package/src/runtime/test/literals.test.ts +372 -0
- package/src/runtime/test/logical-indexing.test.ts +478 -0
- package/src/runtime/test/member-methods.test.ts +324 -0
- package/src/runtime/test/model-config.test.ts +338 -0
- package/src/runtime/test/null-handling.test.ts +342 -0
- package/src/runtime/test/private-visibility.test.ts +332 -0
- package/src/runtime/test/runtime-state.test.ts +514 -0
- package/src/runtime/test/scoping.test.ts +370 -0
- package/src/runtime/test/string-interpolation.test.ts +354 -0
- package/src/runtime/test/template-literal.test.ts +181 -0
- package/src/runtime/test/tool-execution.test.ts +467 -0
- package/src/runtime/test/tool-schema-generation.test.ts +477 -0
- package/src/runtime/test/tostring.test.ts +210 -0
- package/src/runtime/test/ts-block.test.ts +594 -0
- package/src/runtime/test/ts-error-location.test.ts +231 -0
- package/src/runtime/test/types.test.ts +732 -0
- package/src/runtime/test/verbose-logger.test.ts +710 -0
- package/src/runtime/test/vibe-expression.test.ts +54 -0
- package/src/runtime/test/vibe-value-errors.test.ts +541 -0
- package/src/runtime/test/while.test.ts +232 -0
- package/src/runtime/tools/builtin.ts +30 -0
- package/src/runtime/tools/directory-tools.ts +70 -0
- package/src/runtime/tools/file-tools.ts +228 -0
- package/src/runtime/tools/index.ts +5 -0
- package/src/runtime/tools/registry.ts +48 -0
- package/src/runtime/tools/search-tools.ts +134 -0
- package/src/runtime/tools/security.ts +36 -0
- package/src/runtime/tools/system-tools.ts +312 -0
- package/src/runtime/tools/test/fixtures/base-types.ts +40 -0
- package/src/runtime/tools/test/fixtures/test-types.ts +132 -0
- package/src/runtime/tools/test/registry.test.ts +713 -0
- package/src/runtime/tools/test/security.test.ts +86 -0
- package/src/runtime/tools/test/system-tools.test.ts +679 -0
- package/src/runtime/tools/test/ts-schema.test.ts +357 -0
- package/src/runtime/tools/ts-schema.ts +341 -0
- package/src/runtime/tools/types.ts +89 -0
- package/src/runtime/tools/utility-tools.ts +198 -0
- package/src/runtime/ts-eval.ts +126 -0
- package/src/runtime/types.ts +797 -0
- package/src/runtime/validation.ts +160 -0
- package/src/runtime/verbose-logger.ts +459 -0
- package/src/runtime.ts +2 -0
- package/src/semantic/analyzer-context.ts +62 -0
- package/src/semantic/analyzer-validators.ts +575 -0
- package/src/semantic/analyzer-visitors.ts +534 -0
- package/src/semantic/analyzer.ts +83 -0
- package/src/semantic/index.ts +11 -0
- package/src/semantic/symbol-table.ts +58 -0
- package/src/semantic/test/async-validation.test.ts +301 -0
- package/src/semantic/test/compress-validation.test.ts +179 -0
- package/src/semantic/test/const-reassignment.test.ts +111 -0
- package/src/semantic/test/control-flow.test.ts +346 -0
- package/src/semantic/test/destructuring.test.ts +185 -0
- package/src/semantic/test/duplicate-declarations.test.ts +168 -0
- package/src/semantic/test/export-validation.test.ts +111 -0
- package/src/semantic/test/fixtures/math.ts +31 -0
- package/src/semantic/test/imports.test.ts +148 -0
- package/src/semantic/test/json-type.test.ts +68 -0
- package/src/semantic/test/literals.test.ts +127 -0
- package/src/semantic/test/model-validation.test.ts +179 -0
- package/src/semantic/test/prompt-validation.test.ts +343 -0
- package/src/semantic/test/scoping.test.ts +312 -0
- package/src/semantic/test/tool-validation.test.ts +306 -0
- package/src/semantic/test/ts-type-checking.test.ts +563 -0
- package/src/semantic/test/type-constraints.test.ts +111 -0
- package/src/semantic/test/type-inference.test.ts +87 -0
- package/src/semantic/test/type-validation.test.ts +552 -0
- package/src/semantic/test/undefined-variables.test.ts +163 -0
- package/src/semantic/ts-block-checker.ts +204 -0
- package/src/semantic/ts-signatures.ts +194 -0
- package/src/semantic/ts-types.ts +170 -0
- package/src/semantic/types.ts +58 -0
- package/tests/fixtures/conditional-logic.vibe +14 -0
- package/tests/fixtures/function-call.vibe +16 -0
- package/tests/fixtures/imports/cycle-detection/a.vibe +6 -0
- package/tests/fixtures/imports/cycle-detection/b.vibe +5 -0
- package/tests/fixtures/imports/cycle-detection/main.vibe +3 -0
- package/tests/fixtures/imports/module-isolation/main-b.vibe +8 -0
- package/tests/fixtures/imports/module-isolation/main.vibe +9 -0
- package/tests/fixtures/imports/module-isolation/moduleA.vibe +6 -0
- package/tests/fixtures/imports/module-isolation/moduleB.vibe +6 -0
- package/tests/fixtures/imports/nested-import/helper.vibe +6 -0
- package/tests/fixtures/imports/nested-import/main.vibe +3 -0
- package/tests/fixtures/imports/nested-import/utils.ts +3 -0
- package/tests/fixtures/imports/nested-isolation/file2.vibe +15 -0
- package/tests/fixtures/imports/nested-isolation/file3.vibe +10 -0
- package/tests/fixtures/imports/nested-isolation/main.vibe +21 -0
- package/tests/fixtures/imports/pure-cycle/a.vibe +5 -0
- package/tests/fixtures/imports/pure-cycle/b.vibe +5 -0
- package/tests/fixtures/imports/pure-cycle/main.vibe +3 -0
- package/tests/fixtures/imports/ts-boolean/checks.ts +14 -0
- package/tests/fixtures/imports/ts-boolean/main.vibe +10 -0
- package/tests/fixtures/imports/ts-boolean/type-mismatch.vibe +5 -0
- package/tests/fixtures/imports/ts-boolean/use-constant.vibe +18 -0
- package/tests/fixtures/imports/ts-error-handling/helpers.ts +42 -0
- package/tests/fixtures/imports/ts-error-handling/main.vibe +5 -0
- package/tests/fixtures/imports/ts-import/main.vibe +4 -0
- package/tests/fixtures/imports/ts-import/math.ts +9 -0
- package/tests/fixtures/imports/ts-variables/call-non-function.vibe +5 -0
- package/tests/fixtures/imports/ts-variables/data.ts +10 -0
- package/tests/fixtures/imports/ts-variables/import-json.vibe +5 -0
- package/tests/fixtures/imports/ts-variables/import-type-mismatch.vibe +5 -0
- package/tests/fixtures/imports/ts-variables/import-variable.vibe +5 -0
- package/tests/fixtures/imports/vibe-import/greet.vibe +5 -0
- package/tests/fixtures/imports/vibe-import/main.vibe +3 -0
- package/tests/fixtures/multiple-ai-calls.vibe +10 -0
- package/tests/fixtures/simple-greeting.vibe +6 -0
- package/tests/fixtures/template-literals.vibe +11 -0
- package/tests/integration/basic-ai/basic-ai.integration.test.ts +166 -0
- package/tests/integration/basic-ai/basic-ai.vibe +12 -0
- package/tests/integration/bug-fix/bug-fix.integration.test.ts +201 -0
- package/tests/integration/bug-fix/buggy-code.ts +22 -0
- package/tests/integration/bug-fix/fix-bug.vibe +21 -0
- package/tests/integration/compress/compress.integration.test.ts +206 -0
- package/tests/integration/destructuring/destructuring.integration.test.ts +92 -0
- package/tests/integration/hello-world-translator/hello-world-translator.integration.test.ts +61 -0
- package/tests/integration/line-annotator/context-modes.integration.test.ts +261 -0
- package/tests/integration/line-annotator/line-annotator.integration.test.ts +148 -0
- package/tests/integration/multi-feature/cumulative-sum.integration.test.ts +75 -0
- package/tests/integration/multi-feature/number-analyzer.integration.test.ts +191 -0
- package/tests/integration/multi-feature/number-analyzer.vibe +59 -0
- package/tests/integration/tool-calls/tool-calls.integration.test.ts +93 -0
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
import { describe, expect, test } from 'bun:test';
|
|
2
|
+
import { parse } from '../../parser/parse';
|
|
3
|
+
import { createInitialState, resumeWithAIResponse, resumeWithAsyncResults } from '../state';
|
|
4
|
+
import { runUntilPause, step } from '../step';
|
|
5
|
+
import type { RuntimeState, VibeValue } from '../types';
|
|
6
|
+
import { createVibeValue } from '../types';
|
|
7
|
+
import { completeAsyncOperation } from '../async';
|
|
8
|
+
|
|
9
|
+
// Helper function to process scheduled async operations
|
|
10
|
+
function processScheduledAsync(s: RuntimeState, response: unknown): RuntimeState {
|
|
11
|
+
if (!s.pendingAsyncStarts || s.pendingAsyncStarts.length === 0) {
|
|
12
|
+
return s;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const starts = s.pendingAsyncStarts;
|
|
16
|
+
s = { ...s, pendingAsyncStarts: [] };
|
|
17
|
+
|
|
18
|
+
// Complete each operation with the mock response
|
|
19
|
+
const frame = s.callStack[s.callStack.length - 1];
|
|
20
|
+
const newLocals = { ...frame.locals };
|
|
21
|
+
|
|
22
|
+
for (const start of starts) {
|
|
23
|
+
const operation = s.asyncOperations.get(start.operationId);
|
|
24
|
+
if (operation) {
|
|
25
|
+
// Get existing variable to preserve its properties (isConst, isPrivate, etc.)
|
|
26
|
+
const existingVar = operation.variableName ? newLocals[operation.variableName] : null;
|
|
27
|
+
const result = createVibeValue(response, {
|
|
28
|
+
source: 'ai',
|
|
29
|
+
isConst: existingVar?.isConst,
|
|
30
|
+
isPrivate: existingVar?.isPrivate,
|
|
31
|
+
typeAnnotation: existingVar?.typeAnnotation,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
operation.status = 'completed';
|
|
35
|
+
operation.result = result;
|
|
36
|
+
operation.endTime = Date.now();
|
|
37
|
+
s.pendingAsyncIds.delete(start.operationId);
|
|
38
|
+
|
|
39
|
+
// Update the variable with the result (preserving declaration properties)
|
|
40
|
+
if (operation.variableName) {
|
|
41
|
+
newLocals[operation.variableName] = result;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Update the frame with new locals
|
|
47
|
+
return {
|
|
48
|
+
...s,
|
|
49
|
+
callStack: [
|
|
50
|
+
...s.callStack.slice(0, -1),
|
|
51
|
+
{ ...frame, locals: newLocals },
|
|
52
|
+
],
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Helper to run with mock AI responses (handles both sync and async AI calls)
|
|
57
|
+
function runWithMockAI(state: RuntimeState, response: unknown): RuntimeState {
|
|
58
|
+
let s = runUntilPause(state);
|
|
59
|
+
|
|
60
|
+
// Process any scheduled async ops immediately (even if completed)
|
|
61
|
+
s = processScheduledAsync(s, response);
|
|
62
|
+
|
|
63
|
+
// Loop to handle all types of pauses
|
|
64
|
+
while (s.status !== 'completed' && s.status !== 'error') {
|
|
65
|
+
// Handle awaiting_async (variable access needs pending result)
|
|
66
|
+
if (s.status === 'awaiting_async' && s.awaitingAsyncIds.length > 0) {
|
|
67
|
+
const results = new Map<string, VibeValue>();
|
|
68
|
+
for (const opId of s.awaitingAsyncIds) {
|
|
69
|
+
const op = s.asyncOperations.get(opId);
|
|
70
|
+
if (op?.result) {
|
|
71
|
+
results.set(opId, op.result);
|
|
72
|
+
} else {
|
|
73
|
+
// If operation not complete yet, complete it with mock response
|
|
74
|
+
const result = createVibeValue(response, { source: 'ai' });
|
|
75
|
+
results.set(opId, result);
|
|
76
|
+
if (op) {
|
|
77
|
+
op.status = 'completed';
|
|
78
|
+
op.result = result;
|
|
79
|
+
s.pendingAsyncIds.delete(opId);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
s = resumeWithAsyncResults(s, results);
|
|
84
|
+
s = runUntilPause(s);
|
|
85
|
+
s = processScheduledAsync(s, response);
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Handle sync AI calls
|
|
90
|
+
if (s.status === 'awaiting_ai' && s.pendingAI) {
|
|
91
|
+
s = resumeWithAIResponse(s, response);
|
|
92
|
+
s = runUntilPause(s);
|
|
93
|
+
s = processScheduledAsync(s, response);
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Handle scheduled async operations
|
|
98
|
+
if (s.pendingAsyncStarts && s.pendingAsyncStarts.length > 0) {
|
|
99
|
+
s = processScheduledAsync(s, response);
|
|
100
|
+
s = runUntilPause(s);
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// No more work to do
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return s;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
describe('Async Execution', () => {
|
|
112
|
+
describe('async let declarations', () => {
|
|
113
|
+
test('async let with do expression executes', () => {
|
|
114
|
+
const ast = parse(`
|
|
115
|
+
model m = { name: "test", apiKey: "key", url: "http://test" }
|
|
116
|
+
async let x = do "prompt" m default
|
|
117
|
+
`);
|
|
118
|
+
let state = createInitialState(ast);
|
|
119
|
+
state = runWithMockAI(state, 'async result');
|
|
120
|
+
|
|
121
|
+
expect(state.status).toBe('completed');
|
|
122
|
+
expect(state.callStack[0].locals['x'].value).toBe('async result');
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
test('async let with type annotation executes', () => {
|
|
126
|
+
const ast = parse(`
|
|
127
|
+
model m = { name: "test", apiKey: "key", url: "http://test" }
|
|
128
|
+
async let x: text = do "prompt" m default
|
|
129
|
+
`);
|
|
130
|
+
let state = createInitialState(ast);
|
|
131
|
+
state = runWithMockAI(state, 'typed result');
|
|
132
|
+
|
|
133
|
+
expect(state.status).toBe('completed');
|
|
134
|
+
expect(state.callStack[0].locals['x'].value).toBe('typed result');
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
test('async let with private modifier executes', () => {
|
|
138
|
+
const ast = parse(`
|
|
139
|
+
model m = { name: "test", apiKey: "key", url: "http://test" }
|
|
140
|
+
async let private secret = do "get secret" m default
|
|
141
|
+
`);
|
|
142
|
+
let state = createInitialState(ast);
|
|
143
|
+
state = runWithMockAI(state, 'secret value');
|
|
144
|
+
|
|
145
|
+
expect(state.status).toBe('completed');
|
|
146
|
+
expect(state.callStack[0].locals['secret'].value).toBe('secret value');
|
|
147
|
+
expect(state.callStack[0].locals['secret'].isPrivate).toBe(true);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
test('async let with ts block schedules async operation', () => {
|
|
151
|
+
const ast = parse(`
|
|
152
|
+
async let x = ts() { return 42; }
|
|
153
|
+
`);
|
|
154
|
+
let state = createInitialState(ast);
|
|
155
|
+
state = runUntilPause(state);
|
|
156
|
+
|
|
157
|
+
// Async TS blocks now schedule for parallel execution
|
|
158
|
+
// The program may complete but have pending async operations
|
|
159
|
+
expect(state.pendingAsyncIds.size).toBeGreaterThan(0);
|
|
160
|
+
// The variable should have a pending marker
|
|
161
|
+
expect(state.callStack[0].locals['x'].asyncOperationId).toBeDefined();
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
describe('async const declarations', () => {
|
|
166
|
+
test('async const with do expression executes', () => {
|
|
167
|
+
const ast = parse(`
|
|
168
|
+
model m = { name: "test", apiKey: "key", url: "http://test" }
|
|
169
|
+
async const x = do "prompt" m default
|
|
170
|
+
`);
|
|
171
|
+
let state = createInitialState(ast);
|
|
172
|
+
state = runWithMockAI(state, 'const result');
|
|
173
|
+
|
|
174
|
+
expect(state.status).toBe('completed');
|
|
175
|
+
expect(state.callStack[0].locals['x'].value).toBe('const result');
|
|
176
|
+
expect(state.callStack[0].locals['x'].isConst).toBe(true);
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
test('async const with type annotation executes', () => {
|
|
180
|
+
const ast = parse(`
|
|
181
|
+
model m = { name: "test", apiKey: "key", url: "http://test" }
|
|
182
|
+
async const x: number = do "give number" m default
|
|
183
|
+
`);
|
|
184
|
+
let state = createInitialState(ast);
|
|
185
|
+
state = runWithMockAI(state, 42);
|
|
186
|
+
|
|
187
|
+
expect(state.status).toBe('completed');
|
|
188
|
+
expect(state.callStack[0].locals['x'].value).toBe(42);
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
describe('async destructuring declarations', () => {
|
|
193
|
+
test('async let destructuring executes', () => {
|
|
194
|
+
const ast = parse(`
|
|
195
|
+
model m = { name: "test", apiKey: "key", url: "http://test" }
|
|
196
|
+
async let {name: text, age: number} = do "get person" m default
|
|
197
|
+
`);
|
|
198
|
+
let state = createInitialState(ast);
|
|
199
|
+
state = runWithMockAI(state, { name: 'Alice', age: 30 });
|
|
200
|
+
|
|
201
|
+
expect(state.status).toBe('completed');
|
|
202
|
+
expect(state.callStack[0].locals['name'].value).toBe('Alice');
|
|
203
|
+
expect(state.callStack[0].locals['age'].value).toBe(30);
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
test('async const destructuring executes', () => {
|
|
207
|
+
const ast = parse(`
|
|
208
|
+
model m = { name: "test", apiKey: "key", url: "http://test" }
|
|
209
|
+
async const {x: number, y: number} = do "get coords" m default
|
|
210
|
+
`);
|
|
211
|
+
let state = createInitialState(ast);
|
|
212
|
+
state = runWithMockAI(state, { x: 10, y: 20 });
|
|
213
|
+
|
|
214
|
+
expect(state.status).toBe('completed');
|
|
215
|
+
expect(state.callStack[0].locals['x'].value).toBe(10);
|
|
216
|
+
expect(state.callStack[0].locals['y'].value).toBe(20);
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
describe('async standalone statements (fire-and-forget)', () => {
|
|
221
|
+
test('async do statement executes', () => {
|
|
222
|
+
const ast = parse(`
|
|
223
|
+
model m = { name: "test", apiKey: "key", url: "http://test" }
|
|
224
|
+
async do "log something" m default
|
|
225
|
+
`);
|
|
226
|
+
let state = createInitialState(ast);
|
|
227
|
+
state = runWithMockAI(state, 'logged');
|
|
228
|
+
|
|
229
|
+
expect(state.status).toBe('completed');
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
test('async vibe statement executes', () => {
|
|
233
|
+
const ast = parse(`
|
|
234
|
+
model m = { name: "test", apiKey: "key", url: "http://test" }
|
|
235
|
+
async vibe "process data" m default
|
|
236
|
+
`);
|
|
237
|
+
let state = createInitialState(ast);
|
|
238
|
+
state = runWithMockAI(state, 'processed');
|
|
239
|
+
|
|
240
|
+
expect(state.status).toBe('completed');
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
test('async ts block statement schedules async operation', () => {
|
|
244
|
+
const ast = parse(`
|
|
245
|
+
async ts() { console.log("fire and forget"); }
|
|
246
|
+
`);
|
|
247
|
+
let state = createInitialState(ast);
|
|
248
|
+
state = runUntilPause(state);
|
|
249
|
+
|
|
250
|
+
// Fire-and-forget async should schedule operation for parallel execution
|
|
251
|
+
// Once implemented, this will have pending async ops
|
|
252
|
+
// For now, it still blocks (TODO: implement fire-and-forget)
|
|
253
|
+
expect(state.pendingAsyncIds.size).toBeGreaterThanOrEqual(0);
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
describe('multiple async declarations', () => {
|
|
258
|
+
test('multiple async lets schedule in parallel', () => {
|
|
259
|
+
const ast = parse(`
|
|
260
|
+
model m = { name: "test", apiKey: "key", url: "http://test" }
|
|
261
|
+
async let a = do "1" m default
|
|
262
|
+
async let b = do "2" m default
|
|
263
|
+
async let c = do "3" m default
|
|
264
|
+
`);
|
|
265
|
+
let state = createInitialState(ast);
|
|
266
|
+
|
|
267
|
+
// Run until pause - all three async lets should schedule without blocking
|
|
268
|
+
state = runUntilPause(state);
|
|
269
|
+
|
|
270
|
+
// Should complete (not block on awaiting_ai) with 3 pending async operations
|
|
271
|
+
expect(state.status).toBe('completed');
|
|
272
|
+
expect(state.pendingAsyncStarts.length).toBe(3);
|
|
273
|
+
expect(state.asyncOperations.size).toBe(3);
|
|
274
|
+
expect(state.pendingAsyncIds.size).toBe(3);
|
|
275
|
+
|
|
276
|
+
// Variables should have pending markers
|
|
277
|
+
expect(state.callStack[0].locals['a'].asyncOperationId).toBeDefined();
|
|
278
|
+
expect(state.callStack[0].locals['b'].asyncOperationId).toBeDefined();
|
|
279
|
+
expect(state.callStack[0].locals['c'].asyncOperationId).toBeDefined();
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
test('multiple async lets get results when processed', () => {
|
|
283
|
+
const ast = parse(`
|
|
284
|
+
model m = { name: "test", apiKey: "key", url: "http://test" }
|
|
285
|
+
async let a = do "1" m default
|
|
286
|
+
async let b = do "2" m default
|
|
287
|
+
async let c = do "3" m default
|
|
288
|
+
`);
|
|
289
|
+
let state = createInitialState(ast);
|
|
290
|
+
|
|
291
|
+
// Use the helper which processes scheduled async operations
|
|
292
|
+
state = runWithMockAI(state, 'parallel_result');
|
|
293
|
+
|
|
294
|
+
expect(state.status).toBe('completed');
|
|
295
|
+
expect(state.callStack[0].locals['a'].value).toBe('parallel_result');
|
|
296
|
+
expect(state.callStack[0].locals['b'].value).toBe('parallel_result');
|
|
297
|
+
expect(state.callStack[0].locals['c'].value).toBe('parallel_result');
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
test('mixed async and sync declarations execute correctly', () => {
|
|
301
|
+
const ast = parse(`
|
|
302
|
+
model m = { name: "test", apiKey: "key", url: "http://test" }
|
|
303
|
+
let sync1 = "hello"
|
|
304
|
+
async let async1 = do "prompt" m default
|
|
305
|
+
const sync2 = 42
|
|
306
|
+
`);
|
|
307
|
+
let state = createInitialState(ast);
|
|
308
|
+
state = runWithMockAI(state, 'async value');
|
|
309
|
+
|
|
310
|
+
expect(state.status).toBe('completed');
|
|
311
|
+
expect(state.callStack[0].locals['sync1'].value).toBe('hello');
|
|
312
|
+
expect(state.callStack[0].locals['async1'].value).toBe('async value');
|
|
313
|
+
expect(state.callStack[0].locals['sync2'].value).toBe(42);
|
|
314
|
+
});
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
describe('async state tracking', () => {
|
|
318
|
+
test('maxParallel is set from options', () => {
|
|
319
|
+
const ast = parse(`let x = 1`);
|
|
320
|
+
const state = createInitialState(ast, { maxParallel: 8 });
|
|
321
|
+
expect(state.maxParallel).toBe(8);
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
test('default maxParallel is 4', () => {
|
|
325
|
+
const ast = parse(`let x = 1`);
|
|
326
|
+
const state = createInitialState(ast);
|
|
327
|
+
expect(state.maxParallel).toBe(4);
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
test('asyncOperations map is initialized', () => {
|
|
331
|
+
const ast = parse(`let x = 1`);
|
|
332
|
+
const state = createInitialState(ast);
|
|
333
|
+
expect(state.asyncOperations).toBeInstanceOf(Map);
|
|
334
|
+
expect(state.asyncOperations.size).toBe(0);
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
test('pendingAsyncIds set is initialized', () => {
|
|
338
|
+
const ast = parse(`let x = 1`);
|
|
339
|
+
const state = createInitialState(ast);
|
|
340
|
+
expect(state.pendingAsyncIds).toBeInstanceOf(Set);
|
|
341
|
+
expect(state.pendingAsyncIds.size).toBe(0);
|
|
342
|
+
});
|
|
343
|
+
});
|
|
344
|
+
});
|