@smythos/sre 1.5.55 → 1.5.60

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.
@@ -2,6 +2,29 @@ import { IAgent as Agent } from '@sre/types/Agent.types';
2
2
  import { Component } from './Component.class';
3
3
  import Joi from 'joi';
4
4
  export declare class ScrapflyWebScrape extends Component {
5
+ protected schema: {
6
+ name: string;
7
+ description: string;
8
+ inputs: {
9
+ URLs: {
10
+ type: string;
11
+ description: string;
12
+ default: boolean;
13
+ };
14
+ };
15
+ outputs: {
16
+ Results: {
17
+ type: string;
18
+ description: string;
19
+ default: boolean;
20
+ };
21
+ FailedURLs: {
22
+ type: string;
23
+ description: string;
24
+ default: boolean;
25
+ };
26
+ };
27
+ };
5
28
  protected configSchema: Joi.ObjectSchema<any>;
6
29
  constructor();
7
30
  init(): void;
@@ -5,6 +5,7 @@ export declare class SmythRuntime {
5
5
  get smythDir(): string;
6
6
  private _readyPromise;
7
7
  private _readyResolve;
8
+ get version(): string;
8
9
  private defaultConfig;
9
10
  protected constructor();
10
11
  protected static instance?: SmythRuntime;
@@ -41,7 +41,9 @@ export declare class RuntimeContext extends EventEmitter {
41
41
  private reset;
42
42
  private initRuntimeContext;
43
43
  ready(): Promise<boolean>;
44
- sync(): Promise<void>;
44
+ private sync;
45
+ private _syncQueue;
46
+ enqueueSync(): void;
45
47
  incStep(): void;
46
48
  updateComponent(componentId: string, data: any): void;
47
49
  resetComponent(componentId: string): void;
@@ -384,6 +384,8 @@ export type TLLMModelsList = {
384
384
  [key: string]: TLLMModel | TCustomLLMModel;
385
385
  };
386
386
  export declare enum TLLMEvent {
387
+ /** Generated response chunks */
388
+ Data = "data",
387
389
  /** Generated response chunks */
388
390
  Content = "content",
389
391
  /** Thinking blocks/chunks */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smythos/sre",
3
- "version": "1.5.55",
3
+ "version": "1.5.60",
4
4
  "description": "Smyth Runtime Environment",
5
5
  "author": "Alaa-eddine KADDOURI",
6
6
  "license": "MIT",
@@ -56,7 +56,7 @@
56
56
  "@google/genai": "^1.10.0",
57
57
  "@google/generative-ai": "^0.14.1",
58
58
  "@huggingface/inference": "^2.8.0",
59
- "@modelcontextprotocol/sdk": "^1.10.1",
59
+ "@modelcontextprotocol/sdk": "^1.17.4",
60
60
  "@pinecone-database/pinecone": "^3.0.0",
61
61
  "@runware/sdk-js": "^1.1.36",
62
62
  "@smithy/smithy-client": "^4.4.3",
@@ -9,6 +9,30 @@ import { getCredentials } from '../subsystems/Security/Credentials.helper';
9
9
  // const CREDITS_PER_URL = 0.2;
10
10
 
11
11
  export class ScrapflyWebScrape extends Component {
12
+ protected schema = {
13
+ name: 'ScrapflyWebScrape',
14
+ description: 'Use this component to scrape web pages',
15
+ inputs: {
16
+ URLs: {
17
+ type: 'Array',
18
+ description: 'The URLs to scrape',
19
+ default: true,
20
+ },
21
+ },
22
+ outputs: {
23
+ Results: {
24
+ type: 'Array',
25
+ description: 'The scraped results',
26
+ default: true,
27
+ },
28
+ FailedURLs: {
29
+ type: 'Array',
30
+ description: 'The URLs that failed to scrape',
31
+ default: true,
32
+ },
33
+ },
34
+ };
35
+
12
36
  protected configSchema = Joi.object({
13
37
  // includeImages: Joi.boolean().default(false).label('Include Image Results'),
14
38
  antiScrapingProtection: Joi.boolean().default(false).label('Enable Anti-Scraping Protection'),
@@ -82,7 +82,12 @@ export class TavilyWebSearch extends Component {
82
82
  return { ...Output, _error, _debug: logger.output };
83
83
  } catch (err: any) {
84
84
  const _error = err?.message || err?.response?.data || err.toString();
85
- logger.error(` Error scraping web \n${JSON.stringify(_error)}\n`);
85
+
86
+ if (err?.status === 401) {
87
+ logger.error(`Tavily Web Search Auth failed, make sure that you have the vault key "tavily" is present and valid`);
88
+ } else {
89
+ logger.error(` Error scraping web \n${JSON.stringify(_error)}\n`);
90
+ }
86
91
  return { Output: undefined, _error, _debug: logger.output };
87
92
  }
88
93
  }
@@ -5,6 +5,7 @@ import { Logger } from '../helpers/Log.helper';
5
5
  import { ConnectorService } from './ConnectorsService';
6
6
  import { SystemEvents } from './SystemEvents';
7
7
  import { findSmythPath } from '../helpers/Sysconfig.helper';
8
+ import pkg from '../../package.json';
8
9
 
9
10
  const logger = Logger('SRE');
10
11
 
@@ -18,6 +19,10 @@ export class SmythRuntime {
18
19
  private _readyPromise: Promise<boolean>;
19
20
  private _readyResolve: (value: boolean) => void;
20
21
 
22
+ public get version() {
23
+ return pkg.version;
24
+ }
25
+
21
26
  private defaultConfig: SREConfig = {
22
27
  Vault: {
23
28
  Connector: 'JSONFileVault',
@@ -88,6 +93,7 @@ export class SmythRuntime {
88
93
  private _initialized = false;
89
94
 
90
95
  public init(_config?: SREConfig): SmythRuntime {
96
+ logger.info(`SRE v${this.version} initializing...`);
91
97
  if (!_config || JSON.stringify(_config) === '{}') {
92
98
  this._smythDir = findSmythPath();
93
99
  logger.info('.smyth directory found in:', this._smythDir);
@@ -342,6 +342,11 @@ export class Conversation extends EventEmitter {
342
342
  this.emit(TLLMEvent.Thinking, thinking);
343
343
  });
344
344
 
345
+ eventEmitter.on(TLLMEvent.Data, (data) => {
346
+ if (this.stop) return;
347
+ this.emit(TLLMEvent.Data, data);
348
+ });
349
+
345
350
  eventEmitter.on(TLLMEvent.Content, (content) => {
346
351
  if (this.stop) return;
347
352
  // if (toolHeaders['x-passthrough']) {
@@ -1,13 +1,11 @@
1
- import fs from 'fs';
2
- import path from 'path';
3
- import { Agent } from './Agent.class';
4
1
  import { Component } from '@sre/Components/Component.class';
2
+ import { Agent } from './Agent.class';
5
3
 
6
4
  import { Logger } from '@sre/helpers/Log.helper';
7
- import { uid } from '@sre/utils';
8
- import { RuntimeContext } from '@sre/MemoryManager/RuntimeContext';
9
5
  import { LLMCache } from '@sre/MemoryManager/LLMCache';
6
+ import { RuntimeContext } from '@sre/MemoryManager/RuntimeContext';
10
7
  import { AccessCandidate } from '@sre/Security/AccessControl/AccessCandidate.class';
8
+ import { uid } from '@sre/utils';
11
9
 
12
10
  const console = Logger('AgentRuntime');
13
11
  const AgentRuntimeUnavailable = new Proxy(
@@ -201,7 +199,7 @@ export class AgentRuntime {
201
199
  delete AgentRuntime.tagsData[this.reqTag];
202
200
  }
203
201
 
204
- this.agentContext.sync();
202
+ this.agentContext.enqueueSync();
205
203
  }
206
204
  public getWaitingComponents() {
207
205
  const ctxData = this.agentContext;
@@ -265,6 +265,9 @@ export class LLMInference {
265
265
  console.warn('Max input context is 0, returning empty context window, This usually indicates a wrong model configuration');
266
266
  }
267
267
 
268
+ console.debug(
269
+ `Context Window Configuration: Max Input Tokens: ${maxInputContext}, Max Output Tokens: ${maxOutputContext}, Max Model Tokens: ${maxModelContext}`
270
+ );
268
271
  const systemMessage = { role: 'system', content: systemPrompt };
269
272
 
270
273
  let smythContextWindow = [];
@@ -188,7 +188,7 @@ export class ChatCompletionsApiInterface extends OpenAIApiInterface {
188
188
  // Handle OpenAI tool definition format
189
189
  if ('parameters' in tool) {
190
190
  return {
191
- type: 'function',
191
+ type: 'function' as const,
192
192
  function: {
193
193
  name: tool.name,
194
194
  description: tool.description,
@@ -199,7 +199,7 @@ export class ChatCompletionsApiInterface extends OpenAIApiInterface {
199
199
 
200
200
  // Handle legacy format for backward compatibility
201
201
  return {
202
- type: 'function',
202
+ type: 'function' as const,
203
203
  function: {
204
204
  name: tool.name,
205
205
  description: tool.description,
@@ -132,6 +132,9 @@ export abstract class ModelsProviderConnector extends SecureConnector {
132
132
  hasAPIKey: boolean;
133
133
  }) => {
134
134
  //const teamModels = typeof model === 'string' ? await loadTeamModels() : {};
135
+ if (Array.isArray(model?.tags) && model?.tags?.includes('sdk')) {
136
+ return; //skip check for SDK
137
+ }
135
138
  const modelInfo = await this.getModelInfo(candidate.readRequest, {}, model, hasAPIKey);
136
139
  const allowedContextTokens = modelInfo?.tokens;
137
140
  const totalTokens = promptTokens + completionTokens;
@@ -21,6 +21,7 @@ type TComponentContext = {
21
21
  input?: { [key: string]: any };
22
22
  output?: { [key: string]: any };
23
23
  };
24
+
24
25
  export class RuntimeContext extends EventEmitter {
25
26
  public circularLimitReached: string | boolean = false;
26
27
  public step: number = 0;
@@ -120,10 +121,10 @@ export class RuntimeContext extends EventEmitter {
120
121
  cpt.ctx.active = true;
121
122
  }
122
123
  }
123
- //fs.writeFileSync(this.ctxFile, JSON.stringify(ctxData, null, 2));
124
+
124
125
  await this._cacheConnector
125
126
  .requester(AccessCandidate.agent(this.runtime.agent.id))
126
- .set(this.ctxFile, JSON.stringify(ctxData, null, 2), null, null, 6 * 60 * 60); //expires in 6 hours max
127
+ .set(this.ctxFile, JSON.stringify(ctxData), null, null, 1 * 60 * 60); //expires in 1 hour
127
128
  } else {
128
129
  ctxData = JSON.parse(data);
129
130
  if (!ctxData.step) ctxData.step = 0;
@@ -133,46 +134,38 @@ export class RuntimeContext extends EventEmitter {
133
134
  this._runtimeFileReady = true;
134
135
  this.emit('ready');
135
136
  });
136
-
137
- // if (!fs.existsSync(this.ctxFile)) {
138
- // ctxData = JSON.parse(JSON.stringify({ components: agent.components, connections: agent.connections, timestamp: Date.now() }));
139
- // if (!ctxData.step) ctxData.step = 0;
140
- // for (let cptId in ctxData.components) {
141
- // ctxData.components[cptId] = {
142
- // id: cptId,
143
- // name: ctxData.components[cptId].name,
144
- // //dbg: { active: false, name: ctxData.components[cptId].name },
145
- // ctx: { active: false, name: ctxData.components[cptId].name },
146
- // };
147
-
148
- // const cpt = ctxData.components[cptId];
149
- // //if this debug session was initiated from an endpoint, we mark the endpoint component as active
150
- // if (endpoint && endpoint.id != undefined && cpt.id == endpoint.id && endpointDBGCall) {
151
- // //cpt.dbg.active = true;
152
- // cpt.ctx.active = true;
153
- // }
154
- // }
155
- // fs.writeFileSync(this.ctxFile, JSON.stringify(ctxData, null, 2));
156
- // } else {
157
- // ctxData = JSON.parse(fs.readFileSync(this.ctxFile, 'utf8'));
158
- // if (!ctxData.step) ctxData.step = 0;
159
- // }
160
-
161
- // this.deserialize(ctxData);
162
- // this._runtimeFileReady = true;
163
- // this.emit('ready');
164
137
  }
165
138
 
166
139
  public async ready() {
167
140
  if (this._runtimeFileReady) return true;
168
141
  return this._readyPromise;
169
142
  }
170
- public async sync() {
143
+ private async sync() {
171
144
  if (!this.ctxFile) return;
145
+
172
146
  this.emit('syncing');
173
147
 
174
148
  const deleteSession = this.runtime.sessionClosed;
175
149
 
150
+ //TODO : Do we need to cache the context if not in debug mode ?
151
+
152
+ const data = this.serialize();
153
+ //if (data) fs.writeFileSync(this.ctxFile, JSON.stringify(data, null, 2));
154
+ if (data) {
155
+ let serializedData = JSON.stringify(data);
156
+ console.debug('Agent Context Size', this.ctxFile, serializedData.length, AccessCandidate.agent(this.runtime.agent.id));
157
+
158
+ await this._cacheConnector
159
+ .requester(AccessCandidate.agent(this.runtime.agent.id))
160
+ .set(this.ctxFile, serializedData, null, null, 3 * 60 * 60); //expires in 3 hours max
161
+
162
+ const mb = serializedData.length / 1024 / 1024;
163
+ const cooldown = (mb / 10) * 1000;
164
+ serializedData = null;
165
+
166
+ await delay(cooldown);
167
+ }
168
+
176
169
  if (deleteSession) {
177
170
  const exists = await this._cacheConnector.requester(AccessCandidate.agent(this.runtime.agent.id)).exists(this.ctxFile);
178
171
 
@@ -183,23 +176,24 @@ export class RuntimeContext extends EventEmitter {
183
176
  else this._cacheConnector.requester(AccessCandidate.agent(this.runtime.agent.id)).delete(this.ctxFile);
184
177
  //if (this.runtime.debug && fs.existsSync(this.ctxFile)) await delay(1000 * 60); //if we're in debug mode, we keep the file for a while to allow final state read
185
178
  //if (fs.existsSync(this.ctxFile)) fs.unlinkSync(this.ctxFile);
186
- }
187
- } else {
188
- const data = this.serialize();
189
- //if (data) fs.writeFileSync(this.ctxFile, JSON.stringify(data, null, 2));
190
- if (data) {
191
- const serializedData = JSON.stringify(data, null, 2);
192
- console.debug('Agent Context Size', this.ctxFile, serializedData.length, AccessCandidate.agent(this.runtime.agent.id));
193
- await this._cacheConnector
194
- .requester(AccessCandidate.agent(this.runtime.agent.id))
195
- .set(this.ctxFile, serializedData, null, null, 3 * 60 * 60); //expires in 3 hours max
179
+ this.ctxFile = null;
196
180
  }
197
181
  }
198
182
  }
183
+ private _syncQueue = Promise.resolve();
199
184
 
185
+ public enqueueSync() {
186
+ if (!this.ctxFile) return;
187
+ console.log('ENQUEUE SYNC');
188
+ this._syncQueue = this._syncQueue
189
+ .then(() => this.sync())
190
+ .catch((err) => {
191
+ console.error('Error syncing context', err);
192
+ }); // avoid unhandled rejections
193
+ }
200
194
  public incStep() {
201
195
  this.step++;
202
- this.sync();
196
+ //this.sync();
203
197
  }
204
198
 
205
199
  public updateComponent(componentId: string, data: any) {
@@ -217,11 +211,16 @@ export class RuntimeContext extends EventEmitter {
217
211
  console.debug('>>> ctxFile', this.ctxFile, AccessCandidate.agent(this.runtime.agent.id));
218
212
  console.debug('>>> ctxData', ctxData, AccessCandidate.agent(this.runtime.agent.id));
219
213
  }
220
- component.ctx = { ...component.ctx, ...data, step: this.step };
214
+ //component.ctx = { ...component.ctx, ...data, step: this.step };
215
+ // minimal allocations
216
+
217
+ if (!component.ctx) component.ctx = { active: false, name: '', step: 0 };
218
+ Object.assign(component.ctx, data);
219
+ component.ctx.step = this.step;
221
220
 
222
221
  //if (this.debug) component.dbg = { ...component.dbg, ...data };
223
222
 
224
- this.sync();
223
+ this.enqueueSync();
225
224
  }
226
225
  public resetComponent(componentId: string) {
227
226
  const ctxData = this;
@@ -240,8 +239,13 @@ export class RuntimeContext extends EventEmitter {
240
239
  //component.dbg.runtimeData = {};
241
240
  component.ctx.runtimeData = {};
242
241
  component.ctx.active = false;
242
+ if (!this.runtime.debug) {
243
+ //console.debug('NOT in debug mode, clearing context input/output');
244
+ component.ctx.input = undefined;
245
+ component.ctx.output = undefined;
246
+ }
243
247
 
244
- this.sync();
248
+ this.enqueueSync();
245
249
  }
246
250
 
247
251
  public getComponentData(componentId: string) {
@@ -427,6 +427,8 @@ export type TLLMModelsList = {
427
427
  };
428
428
 
429
429
  export enum TLLMEvent {
430
+ /** Generated response chunks */
431
+ Data = 'data',
430
432
  /** Generated response chunks */
431
433
  Content = 'content',
432
434
  /** Thinking blocks/chunks */