@smythos/sre 1.5.12 → 1.5.13

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.
@@ -46,8 +46,8 @@ export declare class Conversation extends EventEmitter {
46
46
  agentVersion?: string;
47
47
  });
48
48
  get ready(): any;
49
- prompt(message?: string, toolHeaders?: {}, concurrentToolCalls?: number, abortSignal?: AbortSignal): Promise<any>;
50
- streamPrompt(message?: string, toolHeaders?: {}, concurrentToolCalls?: number, abortSignal?: AbortSignal): Promise<any>;
49
+ prompt(message?: string | any, toolHeaders?: {}, concurrentToolCalls?: number, abortSignal?: AbortSignal): Promise<any>;
50
+ streamPrompt(message?: string | any, toolHeaders?: {}, concurrentToolCalls?: number, abortSignal?: AbortSignal): Promise<any>;
51
51
  private resolveToolEndpoint;
52
52
  private useTool;
53
53
  addTool(tool: {
@@ -27,7 +27,7 @@ export declare class LocalStorage extends StorageConnector {
27
27
  * @param {string} resourceId - The key of the object to be read.
28
28
  * @returns {Promise<any>} - A promise that resolves with the object data.
29
29
  */
30
- read(acRequest: AccessRequest, resourceId: string): Promise<string>;
30
+ read(acRequest: AccessRequest, resourceId: string): Promise<NonSharedBuffer>;
31
31
  getMetadata(acRequest: AccessRequest, resourceId: string): Promise<StorageMetadata | undefined>;
32
32
  setMetadata(acRequest: AccessRequest, resourceId: string, metadata: StorageMetadata): Promise<void>;
33
33
  /**
@@ -5,14 +5,14 @@ import { VaultConnector } from '../VaultConnector';
5
5
  export type JSONFileVaultConfig = {
6
6
  file?: string;
7
7
  fileKey?: string;
8
- shared?: boolean;
8
+ shared?: string;
9
9
  };
10
10
  export declare class JSONFileVault extends VaultConnector {
11
11
  protected _settings: JSONFileVaultConfig;
12
12
  name: string;
13
13
  private vaultData;
14
14
  private index;
15
- private sharedVault;
15
+ private shared;
16
16
  constructor(_settings: JSONFileVaultConfig);
17
17
  private findVaultFile;
18
18
  private getMasterKeyInteractive;
@@ -8,6 +8,7 @@ export declare const isBuffer: (data: any) => boolean;
8
8
  export declare const isBinaryMimeType: (mimetype: any) => boolean;
9
9
  export declare const isBinaryData: (data: any) => boolean;
10
10
  export declare function isUrl(str: string): boolean;
11
+ export declare function isFile(str: string): boolean;
11
12
  export declare function isSmythFsUrl(str: string): boolean;
12
13
  export declare const isSmythFileObject: (data: any) => boolean;
13
14
  export declare const isBufferObject: (data: Record<string, any>) => boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smythos/sre",
3
- "version": "1.5.12",
3
+ "version": "1.5.13",
4
4
  "description": "Smyth Runtime Environment",
5
5
  "author": "Alaa-eddine KADDOURI",
6
6
  "license": "MIT",
@@ -21,6 +21,9 @@ export class SmythRuntime {
21
21
  private defaultConfig: SREConfig = {
22
22
  Vault: {
23
23
  Connector: 'JSONFileVault',
24
+ Settings: {
25
+ shared: 'default', //default team shares its secrets with all other teams
26
+ },
24
27
  },
25
28
  Account: {
26
29
  Connector: 'DummyAccount',
@@ -135,7 +135,7 @@ export class BinaryInput {
135
135
  extension = extension || mime.getExtension(this.mimetype);
136
136
  if (!this._name.endsWith(`.${extension}`)) this._name += `.${extension}`;
137
137
  } catch (error) {
138
- console.error('Error loading binary data from url:', data.url);
138
+ console.error('Error loading binary data from url:', data.url, error);
139
139
  }
140
140
 
141
141
  //this._source = data.url;
@@ -194,15 +194,19 @@ export class BinaryInput {
194
194
  }
195
195
  const ext = mime.getExtension(this.mimetype);
196
196
  if (!this._name.endsWith(`.${ext}`)) this._name += `.${ext}`;
197
+ this._ready = true;
198
+ return;
197
199
  }
198
200
 
199
201
  if (data instanceof Blob) {
200
202
  this._source = Buffer.from(await data.arrayBuffer());
201
203
  this.size = data.size;
202
204
  this.mimetype = data.type;
205
+ this._ready = true;
206
+ return;
203
207
  }
204
208
 
205
- this._ready = true;
209
+
206
210
  }
207
211
 
208
212
  private async getUrlInfo(url) {
@@ -236,6 +240,9 @@ export class BinaryInput {
236
240
  await SmythFS.Instance.write(this.url, this._source, candidate, undefined, ttl);
237
241
  this._uploading = false;
238
242
  }
243
+ else {
244
+ this._uploading = false;
245
+ }
239
246
  } catch (error) {
240
247
  console.error('Error uploading binary data:', error);
241
248
  this._uploading = false;
@@ -217,7 +217,7 @@ export class Conversation extends EventEmitter {
217
217
  model: instance._model,
218
218
  };
219
219
  })
220
- public async prompt(message?: string, toolHeaders = {}, concurrentToolCalls = 4, abortSignal?: AbortSignal) {
220
+ public async prompt(message?: string|any, toolHeaders = {}, concurrentToolCalls = 4, abortSignal?: AbortSignal) {
221
221
  const result = await this.streamPrompt(message, toolHeaders, concurrentToolCalls, abortSignal);
222
222
  return result;
223
223
  }
@@ -232,7 +232,11 @@ export class Conversation extends EventEmitter {
232
232
  model: instance._model,
233
233
  };
234
234
  })
235
- public async streamPrompt(message?: string, toolHeaders = {}, concurrentToolCalls = 4, abortSignal?: AbortSignal) {
235
+ public async streamPrompt(message?: string|any, toolHeaders = {}, concurrentToolCalls = 4, abortSignal?: AbortSignal) {
236
+ let options = typeof message === 'object' ? message : {message};
237
+ message = options?.message;
238
+ const files = options?.files;
239
+
236
240
  if (message) {
237
241
  //initial call, reset stop flag
238
242
 
@@ -287,6 +291,7 @@ export class Conversation extends EventEmitter {
287
291
  const eventEmitter: any = await llmInference
288
292
  .promptStream({
289
293
  contextWindow,
294
+ files,
290
295
  params: {
291
296
  model: this.model,
292
297
  toolsConfig: this._settings?.toolsStrategy ? this._settings.toolsStrategy(toolsConfig) : toolsConfig,
@@ -82,7 +82,7 @@ export class LocalStorage extends StorageConnector {
82
82
  try {
83
83
  const filePath = this.getStorageFilePath(acRequest.candidate.id, resourceId);
84
84
  if (!fs.existsSync(filePath)) return undefined;
85
- const data = fs.readFileSync(filePath, 'utf-8');
85
+ const data = fs.readFileSync(filePath, null);
86
86
  return data;
87
87
  } catch (error) {
88
88
  console.error(`Error reading object from local storage`, error.name, error.message);
@@ -143,10 +143,10 @@ export class LocalStorage extends StorageConnector {
143
143
  }
144
144
  const accessCandidate = acRequest.candidate;
145
145
 
146
- let amzACL = ACL.from(acl).addAccess(accessCandidate.role, accessCandidate.id, TAccessLevel.Owner).ACL;
146
+ let localACL = ACL.from(acl).addAccess(accessCandidate.role, accessCandidate.id, TAccessLevel.Owner).ACL;
147
147
  let fileMetadata = {
148
148
  ...metadata,
149
- acl: amzACL,
149
+ acl: localACL,
150
150
  };
151
151
 
152
152
  //now we can write the file
@@ -124,7 +124,7 @@ export class LLMHelper {
124
124
  throw new Error('Please provide a valid image url!');
125
125
  }
126
126
 
127
- const dimensions = imageSize(buffer);
127
+ const dimensions = imageSize(buffer);
128
128
 
129
129
  return {
130
130
  width: dimensions?.width || 0,
@@ -14,7 +14,7 @@ export class AccessCandidate implements IAccessCandidate {
14
14
 
15
15
  private _validateId(id: string) {
16
16
  if (/[^a-zA-Z0-9-]/.test(id))
17
- throw new Error('Access Candidate ID can only contain alphanumeric characters and hyphens');
17
+ throw new Error(`Access Candidate ID can only contain alphanumeric characters and hyphens, invalid id: ${id}`);
18
18
  return id;
19
19
  }
20
20
 
@@ -20,20 +20,20 @@ const console = Logger('JSONFileVault');
20
20
  export type JSONFileVaultConfig = {
21
21
  file?: string;
22
22
  fileKey?: string;
23
- shared?: boolean;
23
+ shared?: string;
24
24
  };
25
25
 
26
- export class JSONFileVault extends VaultConnector {
26
+ export class JSONFileVault extends VaultConnector {
27
27
  public name: string = 'JSONFileVault';
28
28
  private vaultData: any;
29
29
  private index: any;
30
- private sharedVault: boolean;
30
+ private shared: string;
31
31
 
32
32
  constructor(protected _settings: JSONFileVaultConfig) {
33
33
  super(_settings);
34
34
  //if (!SmythRuntime.Instance) throw new Error('SRE not initialized');
35
35
 
36
- this.sharedVault = _settings.shared || false; //if config.shared, all keys are accessible to all teams, and they are set under the 'shared' teamId
36
+ this.shared = _settings.shared || ''; //if config.shared, all keys are accessible to all teams, and they are set under the 'shared' teamId
37
37
 
38
38
  let vaultFile = this.findVaultFile(_settings.file);
39
39
  this.vaultData = {};
@@ -124,14 +124,14 @@ export class JSONFileVault extends VaultConnector {
124
124
  const accountConnector = ConnectorService.getAccountConnector();
125
125
  const teamId = await accountConnector.getCandidateTeam(acRequest.candidate);
126
126
 
127
- return this.vaultData?.[teamId]?.[keyId] || this.vaultData?.['shared']?.[keyId];
127
+ return this.vaultData?.[teamId]?.[keyId] || this.vaultData?.[this.shared]?.[keyId];
128
128
  }
129
129
 
130
130
  @SecureConnector.AccessControl
131
131
  protected async exists(acRequest: AccessRequest, keyId: string) {
132
132
  const accountConnector = ConnectorService.getAccountConnector();
133
133
  const teamId = await accountConnector.getCandidateTeam(acRequest.candidate);
134
- return !!(this.vaultData?.[teamId]?.[keyId] || this.vaultData?.['shared']?.[keyId]);
134
+ return !!(this.vaultData?.[teamId]?.[keyId] || this.vaultData?.[this.shared]?.[keyId]);
135
135
  }
136
136
 
137
137
  @SecureConnector.AccessControl
@@ -146,7 +146,7 @@ export class JSONFileVault extends VaultConnector {
146
146
  const acl = new ACL();
147
147
 
148
148
  if (resourceId && typeof this.vaultData?.[teamId]?.[resourceId] !== 'string') {
149
- if (this.sharedVault && typeof this.vaultData?.['shared']?.[resourceId] === 'string') {
149
+ if (this.shared && typeof this.vaultData?.[this.shared]?.[resourceId] === 'string') {
150
150
  acl.addAccess(candidate.role, candidate.id, TAccessLevel.Read);
151
151
  }
152
152
 
@@ -157,7 +157,7 @@ export class JSONFileVault extends VaultConnector {
157
157
  .addAccess(TAccessRole.Team, teamId, TAccessLevel.Read)
158
158
  .addAccess(TAccessRole.Team, teamId, TAccessLevel.Write);
159
159
 
160
- if (this.sharedVault && typeof this.vaultData?.['shared']?.[resourceId] === 'string') {
160
+ if (this.shared && typeof this.vaultData?.[this.shared]?.[resourceId] === 'string') {
161
161
  acl.addAccess(candidate.role, candidate.id, TAccessLevel.Read);
162
162
  }
163
163
 
@@ -1,5 +1,6 @@
1
1
  import { Readable } from 'stream';
2
2
  import axios from 'axios';
3
+ import * as fs from 'fs';
3
4
 
4
5
  import { identifyMimeTypeFromBase64DataUrl, isBase64FileUrl, isBase64, identifyMimetypeFromBase64, isBase64DataUrl } from './base64.utils';
5
6
  import { isBinaryFileSync } from 'isbinaryfile';
@@ -123,6 +124,63 @@ export function isUrl(str: string): boolean {
123
124
  return regex.test(str);
124
125
  }
125
126
 
127
+ export function isFile(str: string): boolean {
128
+ // Check if string exists and length is within limit
129
+ if (!str || str.length >= 1000) {
130
+ return false;
131
+ }
132
+
133
+ // Validate path format for both Windows and Unix systems
134
+ if (!isValidPathFormat(str)) {
135
+ return false;
136
+ }
137
+
138
+ // Check if file exists using fs.stat
139
+ try {
140
+ const stats = fs.statSync(str);
141
+ return stats.isFile();
142
+ } catch (error) {
143
+ // File doesn't exist or permission denied
144
+ return false;
145
+ }
146
+ }
147
+
148
+ /**
149
+ * Validates if a string is in a valid file path format for both Windows and Unix systems
150
+ * Supports both absolute and relative paths
151
+ */
152
+ function isValidPathFormat(path: string): boolean {
153
+ // Check for invalid characters that are not allowed in file paths
154
+ const invalidChars = /[\0<>"|?*]/;
155
+ if (invalidChars.test(path)) {
156
+ return false;
157
+ }
158
+
159
+ // Windows path patterns
160
+ const windowsAbsolute = /^[a-zA-Z]:[\\\/]/; // C:\ or C:/
161
+ const windowsUNC = /^\\\\[^\\]+\\[^\\]+/; // \\server\share
162
+ const windowsRelative = /^\.{1,2}[\\\/]/; // .\ or ..\ or ./ or ../
163
+
164
+ // Unix path patterns
165
+ const unixAbsolute = /^\//; // /path/to/file
166
+ const unixHome = /^~[\/]/; // ~/path/to/file
167
+ const unixRelative = /^\.{1,2}\//; // ./ or ../
168
+
169
+ // Relative paths without leading ./ or .\
170
+ const genericRelative = /^[^\\\/]/; // path/to/file or path\to\file
171
+
172
+ // Check if path matches any valid pattern
173
+ return (
174
+ windowsAbsolute.test(path) ||
175
+ windowsUNC.test(path) ||
176
+ windowsRelative.test(path) ||
177
+ unixAbsolute.test(path) ||
178
+ unixHome.test(path) ||
179
+ unixRelative.test(path) ||
180
+ genericRelative.test(path)
181
+ );
182
+ }
183
+
126
184
  export function isSmythFsUrl(str: string): boolean {
127
185
  if (typeof str !== 'string') return false;
128
186
  const regex = /^smythfs:\/\/([^\s.]+\.[^\s]{2,})(:[0-9]{1,5})?(\/[^\s]*)?(\?[^\s]*)?$/i;