@snap-agent/core 0.1.0 → 0.1.3
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 +286 -31
- package/dist/{chunk-Y5TTFQWC.mjs → chunk-FS7G3ID4.mjs} +4 -2
- package/dist/{index-CDsqnM8L.d.mts → index-m2vDW79n.d.mts} +59 -1
- package/dist/{index-CDsqnM8L.d.ts → index-m2vDW79n.d.ts} +59 -1
- package/dist/index.d.mts +162 -9
- package/dist/index.d.ts +162 -9
- package/dist/index.js +268 -13
- package/dist/index.mjs +263 -14
- package/dist/storage/index.d.mts +1 -1
- package/dist/storage/index.d.ts +1 -1
- package/dist/storage/index.js +4 -2
- package/dist/storage/index.mjs +1 -1
- package/package.json +7 -6
package/dist/index.mjs
CHANGED
|
@@ -2,10 +2,10 @@ import {
|
|
|
2
2
|
MemoryStorage,
|
|
3
3
|
MongoDBStorage,
|
|
4
4
|
UpstashStorage
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-FS7G3ID4.mjs";
|
|
6
6
|
|
|
7
7
|
// src/core/Agent.ts
|
|
8
|
-
import { generateText, streamText } from "ai";
|
|
8
|
+
import { generateText, streamText, Output } from "ai";
|
|
9
9
|
|
|
10
10
|
// src/core/PluginManager.ts
|
|
11
11
|
var PluginManager = class {
|
|
@@ -219,33 +219,88 @@ var Agent = class _Agent {
|
|
|
219
219
|
}
|
|
220
220
|
/**
|
|
221
221
|
* Create a new agent
|
|
222
|
+
*
|
|
223
|
+
* If plugins are provided, their configurations will be extracted (if they implement getConfig())
|
|
224
|
+
* and stored in the database for later reinstantiation.
|
|
222
225
|
*/
|
|
223
226
|
static async create(config, storage, providerFactory) {
|
|
224
|
-
const
|
|
227
|
+
const pluginConfigs = config.pluginConfigs || [];
|
|
228
|
+
if (config.plugins && config.plugins.length > 0) {
|
|
229
|
+
for (const plugin of config.plugins) {
|
|
230
|
+
if ("getConfig" in plugin && typeof plugin.getConfig === "function") {
|
|
231
|
+
pluginConfigs.push({
|
|
232
|
+
type: plugin.type,
|
|
233
|
+
name: plugin.name,
|
|
234
|
+
config: plugin.getConfig(),
|
|
235
|
+
priority: plugin.priority,
|
|
236
|
+
enabled: true
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
const configWithPluginConfigs = {
|
|
242
|
+
...config,
|
|
243
|
+
pluginConfigs
|
|
244
|
+
};
|
|
245
|
+
const agentId = await storage.createAgent(configWithPluginConfigs);
|
|
225
246
|
const data = await storage.getAgent(agentId);
|
|
226
247
|
if (!data) {
|
|
227
248
|
throw new AgentNotFoundError(agentId);
|
|
228
249
|
}
|
|
250
|
+
data.plugins = config.plugins || [];
|
|
229
251
|
return new _Agent(data, storage, providerFactory);
|
|
230
252
|
}
|
|
231
253
|
/**
|
|
232
254
|
* Load an existing agent by ID
|
|
233
|
-
|
|
234
|
-
|
|
255
|
+
*
|
|
256
|
+
* Plugins can be attached in three ways (in order of priority):
|
|
257
|
+
* 1. Direct plugins array - runtime plugin instances passed directly
|
|
258
|
+
* 2. Plugin registry - reinstantiate from stored configs using registered factories
|
|
259
|
+
* 3. No plugins - agent loads without plugin functionality
|
|
260
|
+
*
|
|
261
|
+
* @param agentId - The agent ID to load
|
|
262
|
+
* @param storage - Storage adapter
|
|
263
|
+
* @param providerFactory - Provider factory
|
|
264
|
+
* @param options - Either:
|
|
265
|
+
* - Plugin[] array (legacy, for backwards compatibility)
|
|
266
|
+
* - Options object with plugins and/or registry
|
|
267
|
+
*/
|
|
268
|
+
static async load(agentId, storage, providerFactory, options) {
|
|
235
269
|
const data = await storage.getAgent(agentId);
|
|
236
270
|
if (!data) {
|
|
237
271
|
return null;
|
|
238
272
|
}
|
|
273
|
+
if (Array.isArray(options)) {
|
|
274
|
+
data.plugins = options;
|
|
275
|
+
return new _Agent(data, storage, providerFactory);
|
|
276
|
+
}
|
|
277
|
+
if (options?.plugins && options.plugins.length > 0) {
|
|
278
|
+
data.plugins = options.plugins;
|
|
279
|
+
} else if (options?.registry && data.pluginConfigs && data.pluginConfigs.length > 0) {
|
|
280
|
+
try {
|
|
281
|
+
data.plugins = await options.registry.instantiateAll(data.pluginConfigs);
|
|
282
|
+
} catch (error) {
|
|
283
|
+
console.error("Failed to reinstantiate plugins from stored configs:", error);
|
|
284
|
+
throw error;
|
|
285
|
+
}
|
|
286
|
+
} else {
|
|
287
|
+
data.plugins = [];
|
|
288
|
+
}
|
|
239
289
|
return new _Agent(data, storage, providerFactory);
|
|
240
290
|
}
|
|
241
291
|
/**
|
|
242
292
|
* Update agent properties
|
|
243
293
|
*/
|
|
244
294
|
async update(updates) {
|
|
295
|
+
const currentPlugins = this.data.plugins || [];
|
|
245
296
|
await this.storage.updateAgent(this.data.id, updates);
|
|
246
297
|
const updatedData = await this.storage.getAgent(this.data.id);
|
|
247
298
|
if (updatedData) {
|
|
299
|
+
updatedData.plugins = updates.plugins || currentPlugins;
|
|
248
300
|
this.data = updatedData;
|
|
301
|
+
if (updates.plugins) {
|
|
302
|
+
this.pluginManager = new PluginManager(updatedData.plugins);
|
|
303
|
+
}
|
|
249
304
|
}
|
|
250
305
|
}
|
|
251
306
|
/**
|
|
@@ -297,11 +352,37 @@ var Agent = class _Agent {
|
|
|
297
352
|
ragMetadata = allMetadata;
|
|
298
353
|
}
|
|
299
354
|
const model = await this.providerFactory.getModel(this.data.provider, this.data.model);
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
355
|
+
let text;
|
|
356
|
+
let parsed;
|
|
357
|
+
if (options?.output?.mode === "object") {
|
|
358
|
+
const result = await generateText({
|
|
359
|
+
model,
|
|
360
|
+
messages: beforeResult.messages,
|
|
361
|
+
system: systemPrompt,
|
|
362
|
+
experimental_output: Output.object({ schema: options.output.schema })
|
|
363
|
+
});
|
|
364
|
+
text = JSON.stringify(result.experimental_output);
|
|
365
|
+
parsed = result.experimental_output;
|
|
366
|
+
} else if (options?.output?.mode === "json") {
|
|
367
|
+
const jsonSystemPrompt = systemPrompt + "\n\n---\nOUTPUT FORMAT: You MUST respond with valid JSON only. No markdown code blocks, no explanations, no additional text - just raw JSON that can be parsed directly.";
|
|
368
|
+
const result = await generateText({
|
|
369
|
+
model,
|
|
370
|
+
messages: beforeResult.messages,
|
|
371
|
+
system: jsonSystemPrompt
|
|
372
|
+
});
|
|
373
|
+
text = result.text;
|
|
374
|
+
try {
|
|
375
|
+
parsed = JSON.parse(text);
|
|
376
|
+
} catch {
|
|
377
|
+
}
|
|
378
|
+
} else {
|
|
379
|
+
const result = await generateText({
|
|
380
|
+
model,
|
|
381
|
+
messages: beforeResult.messages,
|
|
382
|
+
system: systemPrompt
|
|
383
|
+
});
|
|
384
|
+
text = result.text;
|
|
385
|
+
}
|
|
305
386
|
const afterResult = await this.pluginManager.executeAfterResponse(text, {
|
|
306
387
|
agentId: this.data.id,
|
|
307
388
|
threadId: options?.threadId,
|
|
@@ -317,6 +398,7 @@ var Agent = class _Agent {
|
|
|
317
398
|
});
|
|
318
399
|
return {
|
|
319
400
|
text: afterResult.response,
|
|
401
|
+
...parsed !== void 0 && { parsed },
|
|
320
402
|
metadata: {
|
|
321
403
|
...afterResult.metadata,
|
|
322
404
|
ragMetadata,
|
|
@@ -1058,6 +1140,7 @@ var AgentClient = class {
|
|
|
1058
1140
|
this.storage = config.storage;
|
|
1059
1141
|
this.providers = config.providers;
|
|
1060
1142
|
this.providerFactory = new ProviderFactory(config.providers);
|
|
1143
|
+
this.pluginRegistry = config.pluginRegistry;
|
|
1061
1144
|
}
|
|
1062
1145
|
validateConfig(config) {
|
|
1063
1146
|
if (!config.storage) {
|
|
@@ -1100,9 +1183,28 @@ var AgentClient = class {
|
|
|
1100
1183
|
}
|
|
1101
1184
|
/**
|
|
1102
1185
|
* Get an agent by ID
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1186
|
+
*
|
|
1187
|
+
* Plugin loading priority:
|
|
1188
|
+
* 1. Direct plugins array passed to this method
|
|
1189
|
+
* 2. Plugin registry (if configured) - reinstantiates from stored configs
|
|
1190
|
+
* 3. No plugins
|
|
1191
|
+
*
|
|
1192
|
+
* @param agentId - The agent ID to load
|
|
1193
|
+
* @param options - Either Plugin[] for backwards compatibility, or options object
|
|
1194
|
+
*/
|
|
1195
|
+
async getAgent(agentId, options) {
|
|
1196
|
+
if (Array.isArray(options)) {
|
|
1197
|
+
const agent2 = await Agent.load(agentId, this.storage, this.providerFactory, options);
|
|
1198
|
+
if (!agent2) {
|
|
1199
|
+
throw new AgentNotFoundError(agentId);
|
|
1200
|
+
}
|
|
1201
|
+
return agent2;
|
|
1202
|
+
}
|
|
1203
|
+
const registry = options?.registry || this.pluginRegistry;
|
|
1204
|
+
const agent = await Agent.load(agentId, this.storage, this.providerFactory, {
|
|
1205
|
+
plugins: options?.plugins,
|
|
1206
|
+
registry
|
|
1207
|
+
});
|
|
1106
1208
|
if (!agent) {
|
|
1107
1209
|
throw new AgentNotFoundError(agentId);
|
|
1108
1210
|
}
|
|
@@ -1260,6 +1362,149 @@ Return only the title without additional explanations.`
|
|
|
1260
1362
|
}
|
|
1261
1363
|
};
|
|
1262
1364
|
|
|
1365
|
+
// src/core/PluginRegistry.ts
|
|
1366
|
+
function resolveEnvVars(config) {
|
|
1367
|
+
const resolved = {};
|
|
1368
|
+
for (const [key, value] of Object.entries(config)) {
|
|
1369
|
+
if (typeof value === "string") {
|
|
1370
|
+
const envMatch = value.match(/^\$\{([^}:]+)(?::([^}]*))?\}$/);
|
|
1371
|
+
if (envMatch) {
|
|
1372
|
+
const [, envVar, defaultValue] = envMatch;
|
|
1373
|
+
const envValue = process.env[envVar];
|
|
1374
|
+
if (envValue !== void 0) {
|
|
1375
|
+
resolved[key] = envValue;
|
|
1376
|
+
} else if (defaultValue !== void 0) {
|
|
1377
|
+
resolved[key] = defaultValue;
|
|
1378
|
+
} else {
|
|
1379
|
+
throw new Error(
|
|
1380
|
+
`Environment variable ${envVar} is required for plugin config but not set`
|
|
1381
|
+
);
|
|
1382
|
+
}
|
|
1383
|
+
} else {
|
|
1384
|
+
resolved[key] = value;
|
|
1385
|
+
}
|
|
1386
|
+
} else if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
1387
|
+
resolved[key] = resolveEnvVars(value);
|
|
1388
|
+
} else {
|
|
1389
|
+
resolved[key] = value;
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
return resolved;
|
|
1393
|
+
}
|
|
1394
|
+
var PluginRegistry = class {
|
|
1395
|
+
constructor() {
|
|
1396
|
+
this.registrations = /* @__PURE__ */ new Map();
|
|
1397
|
+
}
|
|
1398
|
+
/**
|
|
1399
|
+
* Register a plugin factory
|
|
1400
|
+
*
|
|
1401
|
+
* @param name - Unique plugin identifier (e.g., "@snap-agent/rag-ecommerce")
|
|
1402
|
+
* @param factory - Function that creates plugin instance from config
|
|
1403
|
+
* @param defaultConfig - Optional default configuration values
|
|
1404
|
+
*/
|
|
1405
|
+
register(name, factory, defaultConfig) {
|
|
1406
|
+
if (this.registrations.has(name)) {
|
|
1407
|
+
console.warn(`Plugin "${name}" is already registered. Overwriting.`);
|
|
1408
|
+
}
|
|
1409
|
+
this.registrations.set(name, { factory, defaultConfig });
|
|
1410
|
+
}
|
|
1411
|
+
/**
|
|
1412
|
+
* Unregister a plugin factory
|
|
1413
|
+
*/
|
|
1414
|
+
unregister(name) {
|
|
1415
|
+
return this.registrations.delete(name);
|
|
1416
|
+
}
|
|
1417
|
+
/**
|
|
1418
|
+
* Check if a plugin is registered
|
|
1419
|
+
*/
|
|
1420
|
+
isRegistered(name) {
|
|
1421
|
+
return this.registrations.has(name);
|
|
1422
|
+
}
|
|
1423
|
+
/**
|
|
1424
|
+
* Get all registered plugin names
|
|
1425
|
+
*/
|
|
1426
|
+
getRegisteredPlugins() {
|
|
1427
|
+
return Array.from(this.registrations.keys());
|
|
1428
|
+
}
|
|
1429
|
+
/**
|
|
1430
|
+
* Instantiate a plugin from stored configuration
|
|
1431
|
+
*
|
|
1432
|
+
* @param storedConfig - Serialized plugin configuration from database
|
|
1433
|
+
* @returns Plugin instance
|
|
1434
|
+
* @throws Error if plugin is not registered
|
|
1435
|
+
*/
|
|
1436
|
+
async instantiate(storedConfig) {
|
|
1437
|
+
const registration = this.registrations.get(storedConfig.name);
|
|
1438
|
+
if (!registration) {
|
|
1439
|
+
throw new Error(
|
|
1440
|
+
`Plugin "${storedConfig.name}" is not registered. Available plugins: ${this.getRegisteredPlugins().join(", ") || "none"}. Make sure to register the plugin before loading the agent.`
|
|
1441
|
+
);
|
|
1442
|
+
}
|
|
1443
|
+
const mergedConfig = {
|
|
1444
|
+
...registration.defaultConfig,
|
|
1445
|
+
...storedConfig.config
|
|
1446
|
+
};
|
|
1447
|
+
const resolvedConfig = resolveEnvVars(mergedConfig);
|
|
1448
|
+
const plugin = await registration.factory(resolvedConfig);
|
|
1449
|
+
if (storedConfig.priority !== void 0) {
|
|
1450
|
+
plugin.priority = storedConfig.priority;
|
|
1451
|
+
}
|
|
1452
|
+
return plugin;
|
|
1453
|
+
}
|
|
1454
|
+
/**
|
|
1455
|
+
* Instantiate multiple plugins from stored configurations
|
|
1456
|
+
*
|
|
1457
|
+
* @param storedConfigs - Array of serialized plugin configurations
|
|
1458
|
+
* @returns Array of plugin instances (skips disabled plugins)
|
|
1459
|
+
*/
|
|
1460
|
+
async instantiateAll(storedConfigs) {
|
|
1461
|
+
const plugins = [];
|
|
1462
|
+
for (const config of storedConfigs) {
|
|
1463
|
+
if (config.enabled === false) {
|
|
1464
|
+
continue;
|
|
1465
|
+
}
|
|
1466
|
+
try {
|
|
1467
|
+
const plugin = await this.instantiate(config);
|
|
1468
|
+
plugins.push(plugin);
|
|
1469
|
+
} catch (error) {
|
|
1470
|
+
console.error(`Failed to instantiate plugin "${config.name}":`, error);
|
|
1471
|
+
throw error;
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1474
|
+
return plugins;
|
|
1475
|
+
}
|
|
1476
|
+
/**
|
|
1477
|
+
* Extract serializable configuration from a plugin instance
|
|
1478
|
+
* Requires the plugin to implement getConfig() method
|
|
1479
|
+
*
|
|
1480
|
+
* @param plugin - Plugin instance
|
|
1481
|
+
* @returns Stored plugin configuration
|
|
1482
|
+
*/
|
|
1483
|
+
extractConfig(plugin) {
|
|
1484
|
+
const config = plugin.getConfig?.() ?? {};
|
|
1485
|
+
return {
|
|
1486
|
+
type: plugin.type,
|
|
1487
|
+
name: plugin.name,
|
|
1488
|
+
config,
|
|
1489
|
+
priority: plugin.priority,
|
|
1490
|
+
enabled: true
|
|
1491
|
+
};
|
|
1492
|
+
}
|
|
1493
|
+
/**
|
|
1494
|
+
* Extract configurations from multiple plugins
|
|
1495
|
+
*/
|
|
1496
|
+
extractAllConfigs(plugins) {
|
|
1497
|
+
return plugins.map((plugin) => this.extractConfig(plugin));
|
|
1498
|
+
}
|
|
1499
|
+
};
|
|
1500
|
+
var pluginRegistry = new PluginRegistry();
|
|
1501
|
+
function envRef(envVarName, defaultValue) {
|
|
1502
|
+
if (defaultValue !== void 0) {
|
|
1503
|
+
return `\${${envVarName}:${defaultValue}}`;
|
|
1504
|
+
}
|
|
1505
|
+
return `\${${envVarName}}`;
|
|
1506
|
+
}
|
|
1507
|
+
|
|
1263
1508
|
// src/index.ts
|
|
1264
1509
|
function createClient(config) {
|
|
1265
1510
|
return new AgentClient(config);
|
|
@@ -1275,10 +1520,14 @@ export {
|
|
|
1275
1520
|
Models,
|
|
1276
1521
|
MongoDBStorage,
|
|
1277
1522
|
PluginManager,
|
|
1523
|
+
PluginRegistry,
|
|
1278
1524
|
ProviderFactory,
|
|
1279
1525
|
ProviderNotFoundError,
|
|
1280
1526
|
Thread,
|
|
1281
1527
|
ThreadNotFoundError,
|
|
1282
1528
|
UpstashStorage,
|
|
1283
|
-
createClient
|
|
1529
|
+
createClient,
|
|
1530
|
+
envRef,
|
|
1531
|
+
pluginRegistry,
|
|
1532
|
+
resolveEnvVars
|
|
1284
1533
|
};
|
package/dist/storage/index.d.mts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { W as MemoryStorage, V as MongoDBStorage, Y as MongoDBStorageConfig, X as UpstashStorage, Z as UpstashStorageConfig } from '../index-m2vDW79n.mjs';
|
package/dist/storage/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { W as MemoryStorage, V as MongoDBStorage, Y as MongoDBStorageConfig, X as UpstashStorage, Z as UpstashStorageConfig } from '../index-m2vDW79n.js';
|
package/dist/storage/index.js
CHANGED
|
@@ -79,7 +79,8 @@ var MongoDBStorage = class {
|
|
|
79
79
|
createdAt: /* @__PURE__ */ new Date(),
|
|
80
80
|
updatedAt: /* @__PURE__ */ new Date(),
|
|
81
81
|
files: [],
|
|
82
|
-
metadata: config.metadata || {}
|
|
82
|
+
metadata: config.metadata || {},
|
|
83
|
+
pluginConfigs: config.pluginConfigs || []
|
|
83
84
|
};
|
|
84
85
|
const result = await collection.insertOne(doc);
|
|
85
86
|
return result.insertedId.toString();
|
|
@@ -262,7 +263,8 @@ var MongoDBStorage = class {
|
|
|
262
263
|
createdAt: doc.createdAt,
|
|
263
264
|
updatedAt: doc.updatedAt,
|
|
264
265
|
files: doc.files,
|
|
265
|
-
metadata: doc.metadata
|
|
266
|
+
metadata: doc.metadata,
|
|
267
|
+
pluginConfigs: doc.pluginConfigs
|
|
266
268
|
};
|
|
267
269
|
}
|
|
268
270
|
threadDocToData(doc) {
|
package/dist/storage/index.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@snap-agent/core",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "SnapAgent - The lightweight, snap-in AI agent SDK. Multi-provider support
|
|
3
|
+
"version": "0.1.3",
|
|
4
|
+
"description": "SnapAgent - The lightweight, snap-in AI agent SDK. Multi-provider support. Edge-runtime compatible.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
@@ -63,8 +63,8 @@
|
|
|
63
63
|
"author": "ViloTech",
|
|
64
64
|
"license": "MIT",
|
|
65
65
|
"peerDependencies": {
|
|
66
|
-
"@ai-sdk/openai": "^2.0.0",
|
|
67
|
-
"ai": "^5.0.0",
|
|
66
|
+
"@ai-sdk/openai": "^2.0.0 || ^3.0.0",
|
|
67
|
+
"ai": "^5.0.0 || ^6.0.0",
|
|
68
68
|
"mongodb": "^6.0.0 || ^7.0.0"
|
|
69
69
|
},
|
|
70
70
|
"peerDependenciesMeta": {
|
|
@@ -82,13 +82,14 @@
|
|
|
82
82
|
}
|
|
83
83
|
},
|
|
84
84
|
"devDependencies": {
|
|
85
|
-
"@ai-sdk/anthropic": "^2.0.0",
|
|
86
|
-
"@ai-sdk/google": "^2.0.0",
|
|
85
|
+
"@ai-sdk/anthropic": "^2.0.0 || ^3.0.0",
|
|
86
|
+
"@ai-sdk/google": "^2.0.0 || ^3.0.0",
|
|
87
87
|
"@types/node": "^24.0.0",
|
|
88
88
|
"dotenv": "^17.2.3",
|
|
89
89
|
"eslint": "^8.0.0",
|
|
90
90
|
"mongodb": "^7.0.0",
|
|
91
91
|
"tsup": "^8.0.0",
|
|
92
|
+
"tsx": "^4.21.0",
|
|
92
93
|
"typescript": "^5.8.0",
|
|
93
94
|
"vitest": "^1.0.0"
|
|
94
95
|
},
|