@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.
Files changed (52) hide show
  1. package/README.md +101 -35
  2. package/bin/sesi.js +163 -38
  3. package/dist/builtins.d.ts.map +1 -1
  4. package/dist/builtins.js +196 -4
  5. package/dist/builtins.js.map +1 -1
  6. package/dist/index.d.ts +7 -2
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +30 -5
  9. package/dist/index.js.map +1 -1
  10. package/dist/interpreter.d.ts +11 -2
  11. package/dist/interpreter.d.ts.map +1 -1
  12. package/dist/interpreter.js +181 -88
  13. package/dist/interpreter.js.map +1 -1
  14. package/dist/lexer.d.ts.map +1 -1
  15. package/dist/lexer.js +8 -4
  16. package/dist/lexer.js.map +1 -1
  17. package/dist/parser.d.ts +1 -0
  18. package/dist/parser.d.ts.map +1 -1
  19. package/dist/parser.js +18 -8
  20. package/dist/parser.js.map +1 -1
  21. package/dist/types.d.ts +13 -1
  22. package/dist/types.d.ts.map +1 -1
  23. package/dist/types.js +33 -1
  24. package/dist/types.js.map +1 -1
  25. package/docs/ARCHITECTURE.md +22 -9
  26. package/docs/BUILTINS.md +111 -13
  27. package/docs/COMPARISON.md +7 -9
  28. package/docs/{DISTRIBUTED_SYSTEMS.md → CONCURRENCY.md} +11 -11
  29. package/docs/IMAGE_GENERATION.md +13 -14
  30. package/docs/IMPLEMENTATION_SUMMARY.md +141 -84
  31. package/docs/QUICKSTART.md +81 -28
  32. package/docs/README.md +140 -34
  33. package/docs/{SYSTEMS_REASONING.md → REASONING.md} +100 -110
  34. package/docs/ROADMAP.md +42 -43
  35. package/docs/SKILLS.md +56 -28
  36. package/docs/SPECIFICATION.md +25 -18
  37. package/docs/sesi_ai_chronicles.md +96 -209
  38. package/examples/07_prompts.sesi +1 -1
  39. package/examples/08_model_call.sesi +1 -1
  40. package/examples/09_structured_output.sesi +1 -1
  41. package/examples/10_code_generation.sesi +1 -1
  42. package/examples/13_data_pipeline.sesi +1 -1
  43. package/examples/14_folder_explainer.sesi +2 -2
  44. package/examples/15_image_generation.sesi +1 -1
  45. package/examples/16_modules.sesi +27 -27
  46. package/examples/20_model_aliases.sesi +22 -0
  47. package/examples/21_custom_tools.sesi +27 -0
  48. package/examples/22_reasoning_plus_custom_tools.sesi +19 -0
  49. package/main/orchestrator.sesi +2 -2
  50. package/main/sesi_db_chatbot.sesi +6 -2
  51. package/main/tests/test_grounding.sesi +2 -0
  52. 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 High-Performance Systems Language</h1>
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-Ready-blue?logo=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 high-performance <strong>Systems Language</strong> designed for building resilient, stateful applications. It provides first-class primitives for process management, filesystem orchestration, and integrated reasoning, enabling developers to build complex logic with a fraction of the boilerplate required by traditional languages.
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
- allowUnsafeFs: false, // Block directory escapes (on by default)
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 Guide](./docs/SYSTEMS_REASONING.md)
159
- - [Distributed Systems](./docs/DISTRIBUTED_SYSTEMS.md)
178
+ - [Reasoning](./docs/REASONING.md)
179
+ - [Concurrency Systems](./docs/CONCURRENCY.md)
160
180
  - [Runtime Architecture](./docs/ARCHITECTURE.md)
161
181
 
162
- ## AI Agent Context
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 # AI-agent workspace context and repo guardrails
171
- ├── index.html # Sesi-generated landing page
172
- ├── eslint.config.mjs # ESLint configuration
173
- ├── dist/ # Compiled TypeScript output
174
- ├── example.js # Helper script to run basic examples
175
- ├── example-ai.js # Helper script to run Reasoning examples
176
- ├── package.json # Dependencies & scripts
177
- ├── tsconfig.json # TypeScript configuration
178
- ├── QUICKSTART.md # Quick start guide
179
- ├── IMPLEMENTATION_SUMMARY.md # Progress and tracking
180
- ├── src/
181
- ├── types.ts # Type system & AST nodes
182
- ├── lexer.ts # Tokenization
183
- │ ├── parser.ts # AST generation
184
- │ ├── interpreter.ts # Execution engine
185
- │ ├── builtins.ts # Standard library
186
- │ ├── ai-runtime.ts # Gemini integration
187
- └── index.ts # Main entry point
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 # CLI executable
190
- ├── examples/ # 18 sample programs demonstrating all features
191
- ├── main/ # Main entry and specialized tests
192
- │ ├── playground.sesi # Main playground script
193
- │ ├── start.sesi # Beginner script
194
- ├── build_website.sesi # Sesi-powered landing page generator
195
- └── tests/ # Debug and syntax scripts
196
- ├── tests/ # Test suite
197
- └── docs/ # Documentation (ARCHITECTURE, BUILTINS, SPECIFICATION, etc.)
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.2 Features (In Progress)
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
- if (args.length === 0) {
10
- console.log(`
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> Run a Sesi program
15
- sesi -help <query> Ask for help from our Sesi Co-Pilot
16
- sesi --help <query>
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
- --version Show version
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 examples/01_hello.sesi
25
- sesi -help "how do I parse a json string?"
26
- `);
27
- process.exit(0);
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
- if (args[0] === '--help' || args[0] === '-help' || args[0] === '-h') {
31
- let queryText = args.slice(1).join(' ').trim();
32
- if (!queryText) {
33
- queryText = "how do I parse a json string?";
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
- fs.writeFileSync('query.txt', queryText, 'utf-8');
36
-
37
- const copilotPath = path.join(__dirname, '../main/sesi_db_chatbot.sesi');
38
- runSesiFile(copilotPath).catch((error) => {
39
- console.error('Fatal error in Sesi Co-Pilot:', error.message);
40
- process.exit(1);
41
- });
42
- } else if (args[0] === '--version') {
43
- console.log('Sesi v1.2.2');
44
- process.exit(0);
45
- } else {
46
- const filePath = args[0];
47
-
48
- if (!fs.existsSync(filePath)) {
49
- console.error(`Error: File not found: ${filePath}`);
50
- process.exit(1);
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
- runSesiFile(filePath).catch((error) => {
54
- console.error('Fatal error:', error.message);
55
- process.exit(1);
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();
@@ -1 +1 @@
1
- {"version":3,"file":"builtins.d.ts","sourceRoot":"","sources":["../src/builtins.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAgCxD,wBAAgB,WAAW,CAAC,WAAW,CAAC,EAAE,GAAG,GAAG,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAgf3E;AAED,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"}
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 allowUnsafeFs = interpreter?.allowUnsafeFs ?? (process.env.SESI_UNSAFE_FS === 'true');
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, allowUnsafeFs is strictly disabled.
50
- if (allowUnsafeFs && !safeMode) {
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
- allowUnsafeFs: interpreter.allowUnsafeFs,
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;