@misterscan/sesi 1.2.3 → 1.3.0
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/README.md +101 -35
- package/bin/sesi.js +163 -38
- package/dist/builtins.d.ts.map +1 -1
- package/dist/builtins.js +196 -4
- package/dist/builtins.js.map +1 -1
- package/dist/index.d.ts +7 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +30 -5
- package/dist/index.js.map +1 -1
- package/dist/interpreter.d.ts +11 -2
- package/dist/interpreter.d.ts.map +1 -1
- package/dist/interpreter.js +181 -88
- package/dist/interpreter.js.map +1 -1
- package/dist/lexer.d.ts.map +1 -1
- package/dist/lexer.js +8 -4
- package/dist/lexer.js.map +1 -1
- package/dist/parser.d.ts +1 -0
- package/dist/parser.d.ts.map +1 -1
- package/dist/parser.js +18 -8
- package/dist/parser.js.map +1 -1
- package/dist/types.d.ts +13 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +33 -1
- package/dist/types.js.map +1 -1
- package/docs/ARCHITECTURE.md +22 -9
- package/docs/BUILTINS.md +111 -13
- package/docs/COMPARISON.md +7 -9
- package/docs/{DISTRIBUTED_SYSTEMS.md → CONCURRENCY.md} +11 -11
- package/docs/IMAGE_GENERATION.md +13 -14
- package/docs/IMPLEMENTATION_SUMMARY.md +141 -84
- package/docs/QUICKSTART.md +81 -28
- package/docs/README.md +140 -34
- package/docs/{SYSTEMS_REASONING.md → REASONING.md} +100 -110
- package/docs/ROADMAP.md +42 -43
- package/docs/SKILLS.md +56 -28
- package/docs/SPECIFICATION.md +25 -18
- package/docs/sesi_ai_chronicles.md +96 -209
- package/examples/07_prompts.sesi +1 -1
- package/examples/08_model_call.sesi +1 -1
- package/examples/09_structured_output.sesi +1 -1
- package/examples/10_code_generation.sesi +1 -1
- package/examples/13_data_pipeline.sesi +1 -1
- package/examples/14_folder_explainer.sesi +2 -2
- package/examples/15_image_generation.sesi +1 -1
- package/examples/16_modules.sesi +27 -27
- package/examples/20_model_aliases.sesi +22 -0
- package/examples/21_custom_tools.sesi +27 -0
- package/examples/22_reasoning_plus_custom_tools.sesi +19 -0
- package/main/orchestrator.sesi +2 -2
- package/main/sesi_db_chatbot.sesi +6 -2
- package/main/tests/test_grounding.sesi +2 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<img src="./sesi-logo.svg" alt="Sesi Logo" width="250" />
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
|
-
<h1 align="center">Sesi: A
|
|
5
|
+
<h1 align="center">Sesi: A Concise, Legible Programming Language</h1>
|
|
6
6
|
|
|
7
7
|
<p align="center">
|
|
8
8
|
<em>Pronounced "say-see" — What you say, you'll see.</em>
|
|
@@ -10,13 +10,13 @@
|
|
|
10
10
|
|
|
11
11
|
<p align="center">
|
|
12
12
|
<img alt="License" src="https://img.shields.io/badge/license-MIT-blue.svg">
|
|
13
|
-
<img alt="TypeScript" src="https://img.shields.io/badge/TypeScript-
|
|
13
|
+
<img alt="TypeScript" src="https://img.shields.io/badge/TypeScript-Interpreter-blue?logo=typescript">
|
|
14
14
|
<img alt="Powered by Gemini" src="https://img.shields.io/badge/Powered%20By-Google%20Gemini-orange">
|
|
15
15
|
<img alt="Framework" src="https://img.shields.io/badge/Node.js-Engine-success?logo=node.js">
|
|
16
16
|
</p>
|
|
17
17
|
|
|
18
18
|
<p align="center">
|
|
19
|
-
<strong>Sesi</strong> is a
|
|
19
|
+
<strong>Sesi</strong> is a clean, minimal, and highly legible programming language. Built from the ground up to be concise and buildable, Sesi removes unnecessary boilerplate. Because the language itself is so simple, integrating external tools like shell commands or Reasoning models becomes effortless. It is a language built for clarity.
|
|
20
20
|
</p>
|
|
21
21
|
|
|
22
22
|
<p align="center">
|
|
@@ -79,6 +79,26 @@ sesi examples/08_model_call.sesi
|
|
|
79
79
|
sesi examples.sesi
|
|
80
80
|
```
|
|
81
81
|
|
|
82
|
+
Useful CLI shortcuts:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
# Evaluate a quick snippet
|
|
86
|
+
sesi -e "print 'hello'"
|
|
87
|
+
|
|
88
|
+
# Ask the built-in co-pilot a question
|
|
89
|
+
sesi -help "how do I use memory?"
|
|
90
|
+
|
|
91
|
+
# Ask for help about a specific file
|
|
92
|
+
sesi main/playground.sesi -h "why is this failing"
|
|
93
|
+
|
|
94
|
+
# Encrypt or decrypt a script file
|
|
95
|
+
sesi -encrypt my_script.sesi -p "my-password"
|
|
96
|
+
sesi -decrypt my_script.sesi -p "my-password"
|
|
97
|
+
|
|
98
|
+
# Run with sandbox restrictions disabled
|
|
99
|
+
sesi main/start.sesi --local
|
|
100
|
+
```
|
|
101
|
+
|
|
82
102
|
# Local Execution (Development)
|
|
83
103
|
|
|
84
104
|
If you choose not install `sesi` globally, use the helper npm scripts:
|
|
@@ -143,7 +163,7 @@ When embedding Sesi inside a host application, you can statically configure safe
|
|
|
143
163
|
```typescript
|
|
144
164
|
const interpreter = new Interpreter(scriptDir, {
|
|
145
165
|
safeMode: true, // Enable full sandbox limits (on by default)
|
|
146
|
-
|
|
166
|
+
allowLocalFs: false, // Block directory escapes (on by default)
|
|
147
167
|
allowedPaths: ['/var/tmp/sandbox'] // Custom strict whitelist directories
|
|
148
168
|
});
|
|
149
169
|
```
|
|
@@ -155,11 +175,11 @@ const interpreter = new Interpreter(scriptDir, {
|
|
|
155
175
|
- [Language Specification](./docs/SPECIFICATION.md)
|
|
156
176
|
- [Language Comparison Showcase](./docs/COMPARISON.md)
|
|
157
177
|
- [Built-in Functions](./docs/BUILTINS.md)
|
|
158
|
-
- [Reasoning
|
|
159
|
-
- [
|
|
178
|
+
- [Reasoning](./docs/REASONING.md)
|
|
179
|
+
- [Concurrency Systems](./docs/CONCURRENCY.md)
|
|
160
180
|
- [Runtime Architecture](./docs/ARCHITECTURE.md)
|
|
161
181
|
|
|
162
|
-
##
|
|
182
|
+
## Agent Context
|
|
163
183
|
|
|
164
184
|
The root-level `SKILLS.md` file is a workspace context file for AI agents. It records repo-specific constraints such as valid Sesi syntax expectations, execution conventions, and the intended meaning of directories like `main/` and `main/tests/`.
|
|
165
185
|
|
|
@@ -167,37 +187,83 @@ The root-level `SKILLS.md` file is a workspace context file for AI agents. It re
|
|
|
167
187
|
|
|
168
188
|
```
|
|
169
189
|
Sesi/
|
|
170
|
-
├── SKILLS.md
|
|
171
|
-
├── index.html
|
|
172
|
-
├── eslint.config.mjs
|
|
173
|
-
├──
|
|
174
|
-
├── example.js
|
|
175
|
-
├──
|
|
176
|
-
├──
|
|
177
|
-
├──
|
|
178
|
-
├──
|
|
179
|
-
├──
|
|
180
|
-
├──
|
|
181
|
-
│
|
|
182
|
-
|
|
183
|
-
│ ├──
|
|
184
|
-
│ ├──
|
|
185
|
-
│ ├──
|
|
186
|
-
│ ├──
|
|
187
|
-
│
|
|
190
|
+
├── SKILLS.md # Workspace context and repo guardrails
|
|
191
|
+
├── index.html # Sesi-generated systems landing page
|
|
192
|
+
├── eslint.config.mjs # ESLint configuration
|
|
193
|
+
├── example.js # Helper script to run basic examples
|
|
194
|
+
├── example-ai.js # Helper script to run reasoning examples
|
|
195
|
+
├── examples.sesi # Central execution suite for examples
|
|
196
|
+
├── README.md # Project overview
|
|
197
|
+
├── QUICKSTART.md # Getting started guide
|
|
198
|
+
├── package.json # Dependencies & scripts
|
|
199
|
+
├── tsconfig.json # TypeScript configuration
|
|
200
|
+
├── dist/ # Compiled TypeScript output
|
|
201
|
+
│
|
|
202
|
+
├── src/ # Source code
|
|
203
|
+
│ ├── types.ts # Type definitions & AST nodes (400+ lines)
|
|
204
|
+
│ ├── lexer.ts # Tokenization (350+ lines)
|
|
205
|
+
│ ├── parser.ts # Recursive descent parser (700+ lines)
|
|
206
|
+
│ ├── interpreter.ts # Tree-walking interpreter (600+ lines)
|
|
207
|
+
│ ├── builtins.ts # Built-in functions (250+ lines)
|
|
208
|
+
│ ├── ai-runtime.ts # Integrated reasoning integration (120+ lines)
|
|
209
|
+
│ └── index.ts # Entry point (30+ lines)
|
|
210
|
+
│
|
|
188
211
|
├── bin/
|
|
189
|
-
│ └── sesi.js
|
|
190
|
-
|
|
191
|
-
├── main/
|
|
192
|
-
│ ├── playground.sesi
|
|
193
|
-
│ ├── start.sesi
|
|
194
|
-
│
|
|
195
|
-
│
|
|
196
|
-
├──
|
|
197
|
-
|
|
212
|
+
│ └── sesi.js # CLI executable
|
|
213
|
+
│
|
|
214
|
+
├── main/ # Playgrounds & debugging
|
|
215
|
+
│ ├── playground.sesi # Main playground script
|
|
216
|
+
│ ├── start.sesi # Beginner script
|
|
217
|
+
│ └── tests/ # Additional syntax validation scripts
|
|
218
|
+
│
|
|
219
|
+
├── docs/
|
|
220
|
+
│ ├── SPECIFICATION.md # Complete language spec (600+ lines)
|
|
221
|
+
│ ├── ARCHITECTURE.md # Runtime & system design (400+ lines)
|
|
222
|
+
│ ├── BUILTINS.md # Built-in functions reference (450+ lines)
|
|
223
|
+
│ ├── COMPARISON.md # Language comparison showcase
|
|
224
|
+
│ ├── CONCURRENCY.md # Concurrency & coordination guide (>100 lines)
|
|
225
|
+
│ ├── IMAGE_GENERATION.md # Image generation guide (>100 lines)
|
|
226
|
+
│ ├── REASONING.md # Reasoning and simple logic guide (>500 lines)
|
|
227
|
+
│ ├── ROADMAP.md # V2-V4+ development plan (400+ lines)
|
|
228
|
+
│ └── sesi_ai_chronicles.md # AI project history & notes
|
|
229
|
+
│
|
|
230
|
+
├── examples/
|
|
231
|
+
│ ├── 01_hello.sesi # Hello World
|
|
232
|
+
│ ├── 02_variables.sesi # Variables & operations
|
|
233
|
+
│ ├── 03_functions.sesi # Functions with parameters
|
|
234
|
+
│ ├── 04_conditionals.sesi # If/else control flow
|
|
235
|
+
│ ├── 05_loops.sesi # While, for, for-in loops
|
|
236
|
+
│ ├── 06_arrays_objects.sesi # Collections
|
|
237
|
+
│ ├── 07_prompts.sesi # Reasoning blocks
|
|
238
|
+
│ ├── 08_model_call.sesi # Basic reasoning calls
|
|
239
|
+
│ ├── 09_structured_output.sesi # Type-safe reasoning responses
|
|
240
|
+
│ ├── 10_code_generation.sesi # Systems logic generation
|
|
241
|
+
│ ├── 11_memory_conversation.sesi # Multi-turn stateful reasoning
|
|
242
|
+
│ ├── 12_classification.sesi # Systems classification loop
|
|
243
|
+
│ ├── 13_data_pipeline.sesi # Complete systems pipeline
|
|
244
|
+
│ ├── 14_folder_explainer.sesi # Directory parsing & reasoning
|
|
245
|
+
│ ├── 15_image_generation.sesi # Image generation API test
|
|
246
|
+
│ ├── 16_modules.sesi # Modules & std library namespaces
|
|
247
|
+
│ ├── 17_http_client.sesi # Network GET/POST client
|
|
248
|
+
│ ├── 18_parallel_requests.sesi # Parallel requests concurrency
|
|
249
|
+
│ ├── 19_search_web.sesi # Web search integration
|
|
250
|
+
│ ├── 20_model_aliases.sesi # Custom model naming aliases
|
|
251
|
+
│ ├── 21_custom_tools.sesi # Custom runtime tool definitions
|
|
252
|
+
│ └── 22_reasoning_plus_custom_tools.sesi # Reasoning composed with custom tools
|
|
253
|
+
│
|
|
254
|
+
└── tests/ # Engine test suite
|
|
255
|
+
├── basic.test.ts # Core parsing & evaluation tests
|
|
256
|
+
├── cache.test.ts # Execution caching tests
|
|
257
|
+
├── http.test.ts # Web request builtins testing
|
|
258
|
+
├── module.test.ts # Imports & module loading tests
|
|
259
|
+
├── parallel.test.ts # Concurrent execution tests
|
|
260
|
+
├── security.test.ts # Sandbox & guardrail tests
|
|
261
|
+
├── test-gemini.ts # Base model integration test
|
|
262
|
+
├── test-gemini2.ts # Extended model integration test
|
|
263
|
+
└── workflow.test.ts # Complex sequence workflows tests
|
|
198
264
|
```
|
|
199
265
|
|
|
200
|
-
## Version 1.
|
|
266
|
+
## Version 1.3 Features (In Progress)
|
|
201
267
|
|
|
202
268
|
### Core Language ✅
|
|
203
269
|
|
package/bin/sesi.js
CHANGED
|
@@ -1,57 +1,182 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
require('@dotenvx/dotenvx').config();
|
|
3
|
-
const { runSesiFile } = require('../dist/index.js');
|
|
3
|
+
const { runSesiFile, runSesi } = require('../dist/index.js');
|
|
4
4
|
const fs = require('fs');
|
|
5
5
|
const path = require('path');
|
|
6
6
|
|
|
7
7
|
const args = process.argv.slice(2);
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
Sesi Programming Language v1.2.2
|
|
9
|
+
const argsHeader = `
|
|
10
|
+
Sesi Programming Language v1.3.0
|
|
12
11
|
|
|
13
12
|
Usage:
|
|
14
|
-
sesi <file>
|
|
15
|
-
sesi -
|
|
16
|
-
sesi
|
|
17
|
-
sesi -h <query>
|
|
13
|
+
sesi <file> [options] Run a Sesi program
|
|
14
|
+
sesi -e "code" Evaluate Sesi code directly
|
|
15
|
+
sesi -help <query> Ask for help from our Sesi Co-Pilot
|
|
18
16
|
|
|
19
17
|
Options:
|
|
20
|
-
--
|
|
18
|
+
--local Disable safe mode (careful!)
|
|
19
|
+
--allowed-paths <p> Comma-separated list of allowed directories
|
|
20
|
+
-encrypt <file> Encrypt a file
|
|
21
|
+
-decrypt <file> Decrypt a file
|
|
22
|
+
-p, --password <pass> Password for encryption/decryption
|
|
23
|
+
--version Show version
|
|
24
|
+
--help, -h Show this help
|
|
21
25
|
|
|
22
26
|
Examples:
|
|
23
27
|
sesi main/start.sesi
|
|
24
|
-
sesi
|
|
25
|
-
sesi -help "how do I
|
|
26
|
-
|
|
27
|
-
|
|
28
|
+
sesi -e "print 'hello'"
|
|
29
|
+
sesi -help "how do I use memory?"
|
|
30
|
+
`;
|
|
31
|
+
|
|
32
|
+
function parseArgs(args) {
|
|
33
|
+
const options = {
|
|
34
|
+
file: null,
|
|
35
|
+
eval: null,
|
|
36
|
+
helpQuery: null,
|
|
37
|
+
helpFile: null,
|
|
38
|
+
encryptFile: null,
|
|
39
|
+
decryptFile: null,
|
|
40
|
+
password: null,
|
|
41
|
+
sesiOptions: {
|
|
42
|
+
safeMode: true,
|
|
43
|
+
allowedPaths: [process.cwd()]
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
for (let i = 0; i < args.length; i++) {
|
|
48
|
+
const arg = args[i];
|
|
49
|
+
const isHelpFlag = arg === '--help' || arg === '-help' || arg === '-h';
|
|
50
|
+
|
|
51
|
+
if (arg === '--version') {
|
|
52
|
+
console.log('Sesi v1.3.0');
|
|
53
|
+
process.exit(0);
|
|
54
|
+
} else if (isHelpFlag && i === 0 && !options.file && !options.eval) {
|
|
55
|
+
if (args[i + 1] && !args[i + 1].startsWith('-')) {
|
|
56
|
+
options.helpQuery = args.slice(i + 1).join(' ').trim();
|
|
57
|
+
break;
|
|
58
|
+
} else {
|
|
59
|
+
console.log(argsHeader);
|
|
60
|
+
process.exit(0);
|
|
61
|
+
}
|
|
62
|
+
} else if (isHelpFlag && options.file) {
|
|
63
|
+
options.helpFile = options.file;
|
|
64
|
+
options.helpQuery = args[i + 1] && !args[i + 1].startsWith('-')
|
|
65
|
+
? args.slice(i + 1).join(' ').trim()
|
|
66
|
+
: 'Help me understand this file.';
|
|
67
|
+
break;
|
|
68
|
+
} else if (arg === '-e' || arg === '--eval') {
|
|
69
|
+
options.eval = args[++i];
|
|
70
|
+
} else if (arg === '-encrypt' || arg === '--encrypt') {
|
|
71
|
+
options.encryptFile = args[++i];
|
|
72
|
+
} else if (arg === '-decrypt' || arg === '--decrypt') {
|
|
73
|
+
options.decryptFile = args[++i];
|
|
74
|
+
} else if (arg === '-p' || arg === '--password') {
|
|
75
|
+
options.password = args[++i];
|
|
76
|
+
} else if (arg === '--local') {
|
|
77
|
+
options.sesiOptions.safeMode = false;
|
|
78
|
+
options.sesiOptions.allowLocalFs = true;
|
|
79
|
+
} else if (arg === '--allowed-paths') {
|
|
80
|
+
const paths = args[++i].split(',');
|
|
81
|
+
options.sesiOptions.allowedPaths.push(...paths.map(p => path.resolve(p)));
|
|
82
|
+
} else if (!arg.startsWith('-') && !options.file) {
|
|
83
|
+
options.file = arg;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return options;
|
|
28
88
|
}
|
|
29
89
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
90
|
+
const parsed = parseArgs(args);
|
|
91
|
+
|
|
92
|
+
async function main() {
|
|
93
|
+
if (!parsed.file && !parsed.eval && !parsed.helpQuery && !parsed.encryptFile && !parsed.decryptFile) {
|
|
94
|
+
console.log(argsHeader);
|
|
95
|
+
process.exit(0);
|
|
34
96
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
97
|
+
|
|
98
|
+
if (parsed.encryptFile || parsed.decryptFile) {
|
|
99
|
+
if (!parsed.password) {
|
|
100
|
+
console.error('Error: Password is required for encryption/decryption. Use -p <password>.');
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
const crypto = require('crypto');
|
|
104
|
+
const targetFile = parsed.encryptFile || parsed.decryptFile;
|
|
105
|
+
const isEncrypt = !!parsed.encryptFile;
|
|
106
|
+
|
|
107
|
+
if (!fs.existsSync(targetFile)) {
|
|
108
|
+
console.error(`Error: File not found: ${targetFile}`);
|
|
109
|
+
process.exit(1);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const content = fs.readFileSync(targetFile, 'utf-8');
|
|
113
|
+
try {
|
|
114
|
+
const algorithm = 'aes-256-cbc';
|
|
115
|
+
const key = crypto.createHash('sha256').update(String(parsed.password)).digest();
|
|
116
|
+
|
|
117
|
+
if (isEncrypt) {
|
|
118
|
+
const iv = crypto.randomBytes(16);
|
|
119
|
+
const cipher = crypto.createCipheriv(algorithm, key, iv);
|
|
120
|
+
let encrypted = cipher.update(content, 'utf8', 'hex');
|
|
121
|
+
encrypted += cipher.final('hex');
|
|
122
|
+
const finalOutput = iv.toString('hex') + ':' + encrypted;
|
|
123
|
+
fs.writeFileSync(targetFile, finalOutput, 'utf-8');
|
|
124
|
+
console.log(`Successfully encrypted ${targetFile}`);
|
|
125
|
+
} else {
|
|
126
|
+
const parts = content.split(':');
|
|
127
|
+
if (parts.length !== 2) throw new Error('Invalid encrypted format');
|
|
128
|
+
const iv = Buffer.from(parts[0], 'hex');
|
|
129
|
+
const decipher = crypto.createDecipheriv(algorithm, key, iv);
|
|
130
|
+
let decrypted = decipher.update(parts[1], 'hex', 'utf8');
|
|
131
|
+
decrypted += decipher.final('utf8');
|
|
132
|
+
fs.writeFileSync(targetFile, decrypted, 'utf-8');
|
|
133
|
+
console.log(`Successfully decrypted ${targetFile}`);
|
|
134
|
+
}
|
|
135
|
+
} catch (e) {
|
|
136
|
+
console.error(`Error during ${isEncrypt ? 'encryption' : 'decryption'}:`, e.message);
|
|
137
|
+
process.exit(1);
|
|
138
|
+
}
|
|
139
|
+
return;
|
|
51
140
|
}
|
|
52
141
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
142
|
+
if (parsed.helpQuery) {
|
|
143
|
+
fs.writeFileSync('query.txt', parsed.helpQuery, 'utf-8');
|
|
144
|
+
if (parsed.helpFile) {
|
|
145
|
+
const resolvedFile = path.resolve(parsed.helpFile);
|
|
146
|
+
const fileContext = fs.readFileSync(resolvedFile, 'utf-8');
|
|
147
|
+
fs.writeFileSync('help_context.txt', `File: ${resolvedFile}\n\n${fileContext}`, 'utf-8');
|
|
148
|
+
} else if (fs.existsSync('help_context.txt')) {
|
|
149
|
+
fs.unlinkSync('help_context.txt');
|
|
150
|
+
}
|
|
151
|
+
const copilotPath = path.join(__dirname, '../main/sesi_db_chatbot.sesi');
|
|
152
|
+
await runSesiFile(copilotPath).catch((error) => {
|
|
153
|
+
console.error('Fatal error in Sesi Co-Pilot:', error.message);
|
|
154
|
+
process.exit(1);
|
|
155
|
+
});
|
|
156
|
+
} else if (parsed.eval) {
|
|
157
|
+
await runSesi(parsed.eval, process.cwd(), parsed.sesiOptions).catch((error) => {
|
|
158
|
+
console.error('Fatal error:', error.message);
|
|
159
|
+
process.exit(1);
|
|
160
|
+
});
|
|
161
|
+
} else if (parsed.file === '-') {
|
|
162
|
+
let input = '';
|
|
163
|
+
process.stdin.on('data', data => { input += data; });
|
|
164
|
+
process.stdin.on('end', async () => {
|
|
165
|
+
await runSesi(input, process.cwd(), parsed.sesiOptions).catch((error) => {
|
|
166
|
+
console.error('Fatal error:', error.message);
|
|
167
|
+
process.exit(1);
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
} else if (parsed.file) {
|
|
171
|
+
if (!fs.existsSync(parsed.file)) {
|
|
172
|
+
console.error(`Error: File not found: ${parsed.file}`);
|
|
173
|
+
process.exit(1);
|
|
174
|
+
}
|
|
175
|
+
await runSesiFile(parsed.file, parsed.sesiOptions).catch((error) => {
|
|
176
|
+
console.error('Fatal error:', error.message);
|
|
177
|
+
process.exit(1);
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
main();
|
package/dist/builtins.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builtins.d.ts","sourceRoot":"","sources":["../src/builtins.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,eAAe,
|
|
1
|
+
{"version":3,"file":"builtins.d.ts","sourceRoot":"","sources":["../src/builtins.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,eAAe,EAAoB,MAAM,SAAS,CAAC;AAiC1E,wBAAgB,WAAW,CAAC,WAAW,CAAC,EAAE,GAAG,GAAG,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAirB3E;AAqBD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAIrD;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,CAY7C;AAED,wBAAgB,OAAO,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,YAAY,GAAG,OAAO,CAWjE;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,CAmBrD;AAED,wBAAgB,aAAa,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,YAAY,GAAG,MAAM,CAQtE"}
|
package/dist/builtins.js
CHANGED
|
@@ -39,15 +39,18 @@ exports.stripPrototypes = stripPrototypes;
|
|
|
39
39
|
exports.isEqual = isEqual;
|
|
40
40
|
exports.stringify = stringify;
|
|
41
41
|
exports.compareValues = compareValues;
|
|
42
|
+
// Built-in functions for Sesi
|
|
43
|
+
const types_1 = require("./types");
|
|
42
44
|
const fs = __importStar(require("fs"));
|
|
43
45
|
const path = __importStar(require("path"));
|
|
44
46
|
const child_process_1 = require("child_process");
|
|
47
|
+
const ai_runtime_1 = require("./ai-runtime");
|
|
45
48
|
function ensureSafePath(filePath, interpreter, baseDir = process.cwd()) {
|
|
46
49
|
const resolved = path.resolve(baseDir, filePath);
|
|
47
|
-
const
|
|
50
|
+
const allowLocalFs = interpreter?.allowLocalFs ?? (process.env.SESI_LOCAL_FS === 'true');
|
|
48
51
|
const safeMode = interpreter?.safeMode ?? (process.env.SESI_SAFE_MODE !== 'false');
|
|
49
|
-
// If in safe mode,
|
|
50
|
-
if (
|
|
52
|
+
// If in safe mode, allowLocalFs is strictly disabled.
|
|
53
|
+
if (allowLocalFs && !safeMode) {
|
|
51
54
|
return resolved;
|
|
52
55
|
}
|
|
53
56
|
const allowedDirs = [...(interpreter?.allowedPaths || [process.cwd()])];
|
|
@@ -475,6 +478,113 @@ function getBuiltins(interpreter) {
|
|
|
475
478
|
isBuiltin: true,
|
|
476
479
|
builtin: () => Math.random(),
|
|
477
480
|
});
|
|
481
|
+
builtins.set('set_alias', {
|
|
482
|
+
type: 'function',
|
|
483
|
+
name: 'set_alias',
|
|
484
|
+
params: [{ name: 'alias' }, { name: 'model' }],
|
|
485
|
+
body: {},
|
|
486
|
+
closure: {},
|
|
487
|
+
isBuiltin: true,
|
|
488
|
+
builtin: (alias, model) => {
|
|
489
|
+
if (typeof alias !== 'string' || typeof model !== 'string') {
|
|
490
|
+
throw new Error('set_alias expects (string alias, string model)');
|
|
491
|
+
}
|
|
492
|
+
if (!interpreter || typeof interpreter.setModelAlias !== 'function') {
|
|
493
|
+
throw new Error('set_alias interpreter reference is missing');
|
|
494
|
+
}
|
|
495
|
+
interpreter.setModelAlias(alias, model);
|
|
496
|
+
return true;
|
|
497
|
+
},
|
|
498
|
+
});
|
|
499
|
+
builtins.set('error_type', {
|
|
500
|
+
type: 'function',
|
|
501
|
+
name: 'error_type',
|
|
502
|
+
params: [{ name: 'type' }, { name: 'message' }, { name: 'data', defaultValue: null }],
|
|
503
|
+
body: {},
|
|
504
|
+
closure: {},
|
|
505
|
+
isBuiltin: true,
|
|
506
|
+
builtin: (typeVal, messageVal, dataVal = null) => {
|
|
507
|
+
if (typeof typeVal !== 'string' || typeVal.trim() === '') {
|
|
508
|
+
throw new Error('error_type expects a non-empty string type');
|
|
509
|
+
}
|
|
510
|
+
if (typeof messageVal !== 'string') {
|
|
511
|
+
throw new Error('error_type expects a string message');
|
|
512
|
+
}
|
|
513
|
+
const obj = Object.create(null);
|
|
514
|
+
obj.type = typeVal;
|
|
515
|
+
obj.message = messageVal;
|
|
516
|
+
obj.data = dataVal;
|
|
517
|
+
return obj;
|
|
518
|
+
},
|
|
519
|
+
});
|
|
520
|
+
builtins.set('raise_error', {
|
|
521
|
+
type: 'function',
|
|
522
|
+
name: 'raise_error',
|
|
523
|
+
params: [
|
|
524
|
+
{ name: 'type_or_error' },
|
|
525
|
+
{ name: 'message', defaultValue: '' },
|
|
526
|
+
{ name: 'data', defaultValue: null },
|
|
527
|
+
],
|
|
528
|
+
body: {},
|
|
529
|
+
closure: {},
|
|
530
|
+
isBuiltin: true,
|
|
531
|
+
builtin: (typeOrError, messageVal = '', dataVal = null) => {
|
|
532
|
+
if (typeof typeOrError === 'object' && typeOrError !== null && !Array.isArray(typeOrError)) {
|
|
533
|
+
const type = typeOrError.type;
|
|
534
|
+
const message = typeOrError.message;
|
|
535
|
+
const data = typeOrError.data ?? null;
|
|
536
|
+
if (typeof type !== 'string' || type.trim() === '' || typeof message !== 'string') {
|
|
537
|
+
throw new Error('raise_error expects error object with string type and message');
|
|
538
|
+
}
|
|
539
|
+
throw new types_1.SesiRuntimeError(type, message, data);
|
|
540
|
+
}
|
|
541
|
+
if (typeof typeOrError !== 'string' || typeOrError.trim() === '') {
|
|
542
|
+
throw new Error('raise_error expects first argument to be error object or non-empty string type');
|
|
543
|
+
}
|
|
544
|
+
if (typeof messageVal !== 'string' || messageVal.trim() === '') {
|
|
545
|
+
throw new Error('raise_error expects a non-empty string message');
|
|
546
|
+
}
|
|
547
|
+
throw new types_1.SesiRuntimeError(typeOrError, messageVal, dataVal);
|
|
548
|
+
},
|
|
549
|
+
});
|
|
550
|
+
builtins.set('define_tool', {
|
|
551
|
+
type: 'function',
|
|
552
|
+
name: 'define_tool',
|
|
553
|
+
params: [{ name: 'name' }, { name: 'fn' }, { name: 'description', defaultValue: '' }],
|
|
554
|
+
body: {},
|
|
555
|
+
closure: {},
|
|
556
|
+
isBuiltin: true,
|
|
557
|
+
builtin: (name, fn, description = '') => {
|
|
558
|
+
if (typeof name !== 'string') {
|
|
559
|
+
throw new Error('define_tool expects first argument to be a string name');
|
|
560
|
+
}
|
|
561
|
+
if (typeof fn !== 'object' || !fn || fn.type !== 'function') {
|
|
562
|
+
throw new Error('define_tool expects second argument to be a function');
|
|
563
|
+
}
|
|
564
|
+
if (description !== null && typeof description !== 'string') {
|
|
565
|
+
throw new Error('define_tool description must be a string');
|
|
566
|
+
}
|
|
567
|
+
if (!interpreter || typeof interpreter.defineCustomTool !== 'function') {
|
|
568
|
+
throw new Error('define_tool interpreter reference is missing');
|
|
569
|
+
}
|
|
570
|
+
interpreter.defineCustomTool(name, fn, typeof description === 'string' ? description : '');
|
|
571
|
+
return true;
|
|
572
|
+
},
|
|
573
|
+
});
|
|
574
|
+
builtins.set('list_tools', {
|
|
575
|
+
type: 'function',
|
|
576
|
+
name: 'list_tools',
|
|
577
|
+
params: [],
|
|
578
|
+
body: {},
|
|
579
|
+
closure: {},
|
|
580
|
+
isBuiltin: true,
|
|
581
|
+
builtin: () => {
|
|
582
|
+
if (!interpreter || typeof interpreter.listCustomToolNames !== 'function') {
|
|
583
|
+
throw new Error('list_tools interpreter reference is missing');
|
|
584
|
+
}
|
|
585
|
+
return interpreter.listCustomToolNames();
|
|
586
|
+
},
|
|
587
|
+
});
|
|
478
588
|
builtins.set('web_get', {
|
|
479
589
|
type: 'function',
|
|
480
590
|
name: 'web_get',
|
|
@@ -556,7 +666,7 @@ function getBuiltins(interpreter) {
|
|
|
556
666
|
const InterpreterClass = interpreter.constructor;
|
|
557
667
|
const subInterpreter = new InterpreterClass(undefined, {
|
|
558
668
|
safeMode: interpreter.safeMode,
|
|
559
|
-
|
|
669
|
+
allowLocalFs: interpreter.allowLocalFs,
|
|
560
670
|
allowedPaths: interpreter.allowedPaths
|
|
561
671
|
});
|
|
562
672
|
subInterpreter.prompts = new Map(interpreter.prompts);
|
|
@@ -566,8 +676,90 @@ function getBuiltins(interpreter) {
|
|
|
566
676
|
return await Promise.all(promises);
|
|
567
677
|
}
|
|
568
678
|
});
|
|
679
|
+
const workflowBuiltin = {
|
|
680
|
+
type: 'function',
|
|
681
|
+
name: 'workflow',
|
|
682
|
+
params: [{ name: 'steps' }, { name: 'input', defaultValue: '' }],
|
|
683
|
+
body: {},
|
|
684
|
+
closure: {},
|
|
685
|
+
isBuiltin: true,
|
|
686
|
+
builtin: async (...args) => {
|
|
687
|
+
const [stepsVal, inputVal] = args;
|
|
688
|
+
if (!Array.isArray(stepsVal)) {
|
|
689
|
+
throw new Error('workflow expects steps to be an array of objects');
|
|
690
|
+
}
|
|
691
|
+
const initialInput = stringify(inputVal ?? '');
|
|
692
|
+
let previous = initialInput;
|
|
693
|
+
const outputs = [];
|
|
694
|
+
for (let i = 0; i < stepsVal.length; i++) {
|
|
695
|
+
const step = stepsVal[i];
|
|
696
|
+
if (typeof step !== 'object' || step === null || Array.isArray(step)) {
|
|
697
|
+
throw new Error(`workflow step ${i + 1} must be an object`);
|
|
698
|
+
}
|
|
699
|
+
const stepObj = step;
|
|
700
|
+
const rawPrompt = stepObj.prompt;
|
|
701
|
+
if (typeof rawPrompt !== 'string' || rawPrompt.trim() === '') {
|
|
702
|
+
throw new Error(`workflow step ${i + 1} requires a non-empty string prompt`);
|
|
703
|
+
}
|
|
704
|
+
let prompt = rawPrompt;
|
|
705
|
+
const fromRef = typeof stepObj.from === 'string' ? stepObj.from.trim() : '';
|
|
706
|
+
if (fromRef !== '') {
|
|
707
|
+
const context = resolveWorkflowReference(fromRef, initialInput, previous, outputs);
|
|
708
|
+
prompt = context === '' ? rawPrompt : `${rawPrompt} ${context}`;
|
|
709
|
+
}
|
|
710
|
+
else {
|
|
711
|
+
// Intuitive default wiring: first step uses input, later steps use previous output.
|
|
712
|
+
const defaultRef = i === 0 ? 'input' : 'previous';
|
|
713
|
+
const context = resolveWorkflowReference(defaultRef, initialInput, previous, outputs);
|
|
714
|
+
prompt = context === '' ? rawPrompt : `${rawPrompt} ${context}`;
|
|
715
|
+
}
|
|
716
|
+
const modelName = typeof stepObj.model === 'string' && stepObj.model.trim() !== ''
|
|
717
|
+
? stepObj.model
|
|
718
|
+
: 'gemini-3.1-flash-lite';
|
|
719
|
+
const model = interpreter && typeof interpreter.resolveModelName === 'function'
|
|
720
|
+
? interpreter.resolveModelName(modelName)
|
|
721
|
+
: modelName;
|
|
722
|
+
const response = await ai_runtime_1.aiRuntime.callModel({
|
|
723
|
+
model,
|
|
724
|
+
prompt,
|
|
725
|
+
temperature: typeof stepObj.temperature === 'number' ? stepObj.temperature : undefined,
|
|
726
|
+
maxTokens: typeof stepObj.max_tokens === 'number' ? stepObj.max_tokens : undefined,
|
|
727
|
+
topK: typeof stepObj.top_k === 'number' ? stepObj.top_k : undefined,
|
|
728
|
+
topP: typeof stepObj.top_p === 'number' ? stepObj.top_p : undefined,
|
|
729
|
+
thinkingLevel: typeof stepObj.thinkingLevel === 'object' || typeof stepObj.thinkingLevel === 'string'
|
|
730
|
+
? stepObj.thinkingLevel
|
|
731
|
+
: undefined,
|
|
732
|
+
cache: typeof stepObj.cache === 'boolean' ? stepObj.cache : undefined,
|
|
733
|
+
search: typeof stepObj.search === 'boolean' ? stepObj.search : undefined,
|
|
734
|
+
});
|
|
735
|
+
previous = response.text;
|
|
736
|
+
outputs.push(response.text);
|
|
737
|
+
}
|
|
738
|
+
const result = Object.create(null);
|
|
739
|
+
result.input = initialInput;
|
|
740
|
+
result.steps = outputs;
|
|
741
|
+
result.final = previous;
|
|
742
|
+
return result;
|
|
743
|
+
},
|
|
744
|
+
};
|
|
745
|
+
builtins.set('workflow', workflowBuiltin);
|
|
569
746
|
return builtins;
|
|
570
747
|
}
|
|
748
|
+
function resolveWorkflowReference(key, input, previous, outputs) {
|
|
749
|
+
if (key === 'input')
|
|
750
|
+
return input;
|
|
751
|
+
if (key === 'previous')
|
|
752
|
+
return previous;
|
|
753
|
+
const stepMatch = /^step(\d+)$/.exec(key);
|
|
754
|
+
if (stepMatch) {
|
|
755
|
+
const index = Number(stepMatch[1]) - 1;
|
|
756
|
+
if (index >= 0 && index < outputs.length) {
|
|
757
|
+
return outputs[index];
|
|
758
|
+
}
|
|
759
|
+
throw new Error(`workflow reference ${key} is out of range`);
|
|
760
|
+
}
|
|
761
|
+
throw new Error(`workflow reference ${key} is invalid`);
|
|
762
|
+
}
|
|
571
763
|
function isTruthy(value) {
|
|
572
764
|
if (value === null || value === false)
|
|
573
765
|
return false;
|