@agentforge/core 0.11.8 → 0.12.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/dist/index.js CHANGED
@@ -2515,14 +2515,14 @@ var withLogging = (options) => {
2515
2515
  onComplete,
2516
2516
  onError
2517
2517
  } = options;
2518
- const logger4 = providedLogger || createLogger(name, { level });
2518
+ const logger5 = providedLogger || createLogger(name, { level });
2519
2519
  return (node) => {
2520
2520
  return async (state) => {
2521
2521
  const startTime = Date.now();
2522
2522
  try {
2523
2523
  if (logInput) {
2524
2524
  const data = extractData ? extractData(state) : { state };
2525
- logger4.info("Node execution started", data);
2525
+ logger5.info("Node execution started", data);
2526
2526
  }
2527
2527
  if (onStart) {
2528
2528
  onStart(state);
@@ -2532,9 +2532,9 @@ var withLogging = (options) => {
2532
2532
  if (logOutput) {
2533
2533
  const data = extractData ? extractData(result) : { result };
2534
2534
  if (logDuration) {
2535
- logger4.info(`Node execution completed (${duration}ms)`, data);
2535
+ logger5.info(`Node execution completed (${duration}ms)`, data);
2536
2536
  } else {
2537
- logger4.info("Node execution completed", data);
2537
+ logger5.info("Node execution completed", data);
2538
2538
  }
2539
2539
  }
2540
2540
  if (onComplete) {
@@ -2545,7 +2545,7 @@ var withLogging = (options) => {
2545
2545
  const duration = Date.now() - startTime;
2546
2546
  const err = error instanceof Error ? error : new Error(String(error));
2547
2547
  if (logErrors) {
2548
- logger4.error(`Node execution failed (${duration}ms)`, {
2548
+ logger5.error(`Node execution failed (${duration}ms)`, {
2549
2549
  error: err.message,
2550
2550
  stack: err.stack
2551
2551
  });
@@ -2581,7 +2581,7 @@ function withLogging2(options) {
2581
2581
  function production(node, options) {
2582
2582
  const {
2583
2583
  nodeName,
2584
- logger: logger4,
2584
+ logger: logger5,
2585
2585
  enableMetrics = true,
2586
2586
  enableTracing = true,
2587
2587
  enableRetry = true,
@@ -2589,7 +2589,7 @@ function production(node, options) {
2589
2589
  retryOptions = {},
2590
2590
  errorOptions = {}
2591
2591
  } = options;
2592
- const actualLogger = logger4 || createLogger(nodeName, { level: "info" /* INFO */ });
2592
+ const actualLogger = logger5 || createLogger(nodeName, { level: "info" /* INFO */ });
2593
2593
  const middleware = [];
2594
2594
  middleware.push(
2595
2595
  withLogging2({
@@ -2653,9 +2653,9 @@ function development(node, options) {
2653
2653
  const {
2654
2654
  nodeName,
2655
2655
  verbose = true,
2656
- logger: logger4
2656
+ logger: logger5
2657
2657
  } = options;
2658
- const actualLogger = logger4 || createLogger(nodeName, { level: "debug" /* DEBUG */ });
2658
+ const actualLogger = logger5 || createLogger(nodeName, { level: "debug" /* DEBUG */ });
2659
2659
  return withLogging2({
2660
2660
  logger: actualLogger,
2661
2661
  name: nodeName,
@@ -4767,6 +4767,485 @@ function createCircuitBreaker(options) {
4767
4767
  return new CircuitBreaker(options);
4768
4768
  }
4769
4769
 
4770
+ // src/monitoring/health.ts
4771
+ var HealthChecker = class {
4772
+ constructor(options) {
4773
+ this.options = options;
4774
+ }
4775
+ checkTimer;
4776
+ lastReport;
4777
+ startTime = Date.now();
4778
+ running = false;
4779
+ start() {
4780
+ if (this.running) {
4781
+ return;
4782
+ }
4783
+ this.running = true;
4784
+ const interval = this.options.interval || 3e4;
4785
+ this.runChecks().catch((error) => {
4786
+ console.error("Initial health check failed:", error);
4787
+ });
4788
+ this.checkTimer = setInterval(() => {
4789
+ this.runChecks().catch((error) => {
4790
+ console.error("Health check failed:", error);
4791
+ });
4792
+ }, interval);
4793
+ }
4794
+ stop() {
4795
+ if (!this.running) {
4796
+ return;
4797
+ }
4798
+ this.running = false;
4799
+ if (this.checkTimer) {
4800
+ clearInterval(this.checkTimer);
4801
+ this.checkTimer = void 0;
4802
+ }
4803
+ }
4804
+ async getHealth() {
4805
+ if (!this.lastReport) {
4806
+ return this.runChecks();
4807
+ }
4808
+ return this.lastReport;
4809
+ }
4810
+ async getLiveness() {
4811
+ return {
4812
+ healthy: true,
4813
+ status: "healthy",
4814
+ message: "Application is running",
4815
+ timestamp: Date.now()
4816
+ };
4817
+ }
4818
+ async getReadiness() {
4819
+ return this.getHealth();
4820
+ }
4821
+ async runChecks() {
4822
+ const timeout2 = this.options.timeout || 5e3;
4823
+ const results = {};
4824
+ const checkPromises = Object.entries(this.options.checks).map(async ([name, check]) => {
4825
+ const startTime = Date.now();
4826
+ try {
4827
+ const result = await Promise.race([
4828
+ check(),
4829
+ new Promise(
4830
+ (_, reject) => setTimeout(() => reject(new Error("Health check timeout")), timeout2)
4831
+ )
4832
+ ]);
4833
+ results[name] = {
4834
+ ...result,
4835
+ timestamp: Date.now(),
4836
+ duration: Date.now() - startTime
4837
+ };
4838
+ } catch (error) {
4839
+ const errorMessage = error.message;
4840
+ results[name] = {
4841
+ healthy: false,
4842
+ status: "unhealthy",
4843
+ error: errorMessage,
4844
+ timestamp: Date.now(),
4845
+ duration: Date.now() - startTime
4846
+ };
4847
+ this.options.onCheckFail?.(name, error);
4848
+ }
4849
+ });
4850
+ await Promise.all(checkPromises);
4851
+ const allHealthy = Object.values(results).every((r) => r.healthy);
4852
+ const anyUnhealthy = Object.values(results).some((r) => r.status === "unhealthy");
4853
+ const status = allHealthy ? "healthy" : anyUnhealthy ? "unhealthy" : "degraded";
4854
+ const report = {
4855
+ healthy: allHealthy,
4856
+ status,
4857
+ timestamp: Date.now(),
4858
+ checks: results,
4859
+ uptime: Date.now() - this.startTime
4860
+ };
4861
+ if (this.lastReport && this.lastReport.healthy !== report.healthy) {
4862
+ this.options.onHealthChange?.(report);
4863
+ }
4864
+ this.lastReport = report;
4865
+ return report;
4866
+ }
4867
+ };
4868
+ function createHealthChecker(options) {
4869
+ return new HealthChecker(options);
4870
+ }
4871
+
4872
+ // src/monitoring/profiler.ts
4873
+ var Profiler = class {
4874
+ profiles = /* @__PURE__ */ new Map();
4875
+ enabled;
4876
+ sampleRate;
4877
+ includeMemory;
4878
+ includeStack;
4879
+ maxSamples;
4880
+ constructor(options = {}) {
4881
+ this.enabled = options.enabled ?? true;
4882
+ this.sampleRate = options.sampleRate ?? 1;
4883
+ this.includeMemory = options.includeMemory ?? false;
4884
+ this.includeStack = options.includeStack ?? false;
4885
+ this.maxSamples = options.maxSamples ?? 1e3;
4886
+ }
4887
+ profile(name, fn) {
4888
+ return async (...args) => {
4889
+ if (!this.enabled || Math.random() > this.sampleRate) {
4890
+ return fn(...args);
4891
+ }
4892
+ const startTime = Date.now();
4893
+ const startMemory = this.includeMemory ? process.memoryUsage() : void 0;
4894
+ const stack = this.includeStack ? new Error().stack : void 0;
4895
+ try {
4896
+ const result = await fn(...args);
4897
+ this.recordSample(name, startTime, startMemory, stack);
4898
+ return result;
4899
+ } catch (error) {
4900
+ this.recordSample(name, startTime, startMemory, stack);
4901
+ throw error;
4902
+ }
4903
+ };
4904
+ }
4905
+ wrap(name, promise) {
4906
+ if (!this.enabled || Math.random() > this.sampleRate) {
4907
+ return promise;
4908
+ }
4909
+ const startTime = Date.now();
4910
+ const startMemory = this.includeMemory ? process.memoryUsage() : void 0;
4911
+ const stack = this.includeStack ? new Error().stack : void 0;
4912
+ return promise.finally(() => {
4913
+ this.recordSample(name, startTime, startMemory, stack);
4914
+ });
4915
+ }
4916
+ recordSample(name, startTime, startMemory, stack) {
4917
+ const duration = Date.now() - startTime;
4918
+ const sample = {
4919
+ timestamp: startTime,
4920
+ duration
4921
+ };
4922
+ if (this.includeMemory && startMemory) {
4923
+ const currentMemory = process.memoryUsage();
4924
+ sample.memory = {
4925
+ heapUsed: currentMemory.heapUsed - startMemory.heapUsed,
4926
+ heapTotal: currentMemory.heapTotal,
4927
+ external: currentMemory.external
4928
+ };
4929
+ }
4930
+ if (this.includeStack && stack) {
4931
+ sample.stack = stack;
4932
+ }
4933
+ if (!this.profiles.has(name)) {
4934
+ this.profiles.set(name, []);
4935
+ }
4936
+ const samples = this.profiles.get(name);
4937
+ samples.push(sample);
4938
+ if (samples.length > this.maxSamples) {
4939
+ samples.shift();
4940
+ }
4941
+ }
4942
+ getReport() {
4943
+ const report = {};
4944
+ for (const [name, samples] of this.profiles.entries()) {
4945
+ if (samples.length === 0) {
4946
+ continue;
4947
+ }
4948
+ const durations = samples.map((s) => s.duration).sort((a, b) => a - b);
4949
+ const totalTime = durations.reduce((sum, d) => sum + d, 0);
4950
+ const stats = {
4951
+ calls: samples.length,
4952
+ totalTime,
4953
+ avgTime: totalTime / samples.length,
4954
+ minTime: durations[0],
4955
+ maxTime: durations[durations.length - 1],
4956
+ p50: this.percentile(durations, 0.5),
4957
+ p95: this.percentile(durations, 0.95),
4958
+ p99: this.percentile(durations, 0.99),
4959
+ samples
4960
+ };
4961
+ if (this.includeMemory) {
4962
+ const memorySamples = samples.filter((s) => s.memory).map((s) => s.memory.heapUsed);
4963
+ if (memorySamples.length > 0) {
4964
+ stats.memory = {
4965
+ avgHeapUsed: memorySamples.reduce((sum, m) => sum + m, 0) / memorySamples.length,
4966
+ maxHeapUsed: Math.max(...memorySamples),
4967
+ minHeapUsed: Math.min(...memorySamples)
4968
+ };
4969
+ }
4970
+ }
4971
+ report[name] = stats;
4972
+ }
4973
+ return report;
4974
+ }
4975
+ percentile(sorted, p) {
4976
+ const index = Math.ceil(sorted.length * p) - 1;
4977
+ return sorted[Math.max(0, index)];
4978
+ }
4979
+ reset(name) {
4980
+ if (name) {
4981
+ this.profiles.delete(name);
4982
+ } else {
4983
+ this.profiles.clear();
4984
+ }
4985
+ }
4986
+ export(path) {
4987
+ const report = this.getReport();
4988
+ console.log("Exporting profile report to:", path);
4989
+ console.log(JSON.stringify(report, null, 2));
4990
+ }
4991
+ };
4992
+ function createProfiler(options) {
4993
+ return new Profiler(options);
4994
+ }
4995
+
4996
+ // src/monitoring/alerts.ts
4997
+ var logger4 = createLogger("agentforge:core:monitoring:alerts", { level: "info" /* INFO */ });
4998
+ var AlertManager = class {
4999
+ constructor(options) {
5000
+ this.options = options;
5001
+ }
5002
+ lastAlertTime = /* @__PURE__ */ new Map();
5003
+ monitorTimer;
5004
+ running = false;
5005
+ start(metrics, interval = 6e4) {
5006
+ if (this.running || !metrics) {
5007
+ return;
5008
+ }
5009
+ this.running = true;
5010
+ this.monitorTimer = setInterval(() => {
5011
+ const currentMetrics = metrics();
5012
+ this.checkRules(currentMetrics);
5013
+ }, interval);
5014
+ }
5015
+ stop() {
5016
+ if (!this.running) {
5017
+ return;
5018
+ }
5019
+ this.running = false;
5020
+ if (this.monitorTimer) {
5021
+ clearInterval(this.monitorTimer);
5022
+ this.monitorTimer = void 0;
5023
+ }
5024
+ }
5025
+ async alert(alert) {
5026
+ const fullAlert = {
5027
+ ...alert,
5028
+ timestamp: alert.timestamp || Date.now()
5029
+ };
5030
+ if (this.isThrottled(alert.name)) {
5031
+ return;
5032
+ }
5033
+ this.lastAlertTime.set(alert.name, Date.now());
5034
+ this.options.onAlert?.(fullAlert);
5035
+ logger4.warn("Alert triggered", {
5036
+ name: alert.name,
5037
+ severity: alert.severity,
5038
+ message: alert.message,
5039
+ data: alert.data
5040
+ });
5041
+ }
5042
+ checkRules(metrics) {
5043
+ if (!this.options.rules) {
5044
+ return;
5045
+ }
5046
+ for (const rule of this.options.rules) {
5047
+ try {
5048
+ if (rule.condition(metrics)) {
5049
+ this.alert({
5050
+ name: rule.name,
5051
+ severity: rule.severity,
5052
+ message: rule.message || `Alert triggered: ${rule.name}`,
5053
+ data: { metrics }
5054
+ });
5055
+ }
5056
+ } catch (error) {
5057
+ logger4.error("Rule check failed", {
5058
+ ruleName: rule.name,
5059
+ error: error instanceof Error ? error.message : String(error),
5060
+ stack: error instanceof Error ? error.stack : void 0
5061
+ });
5062
+ }
5063
+ }
5064
+ }
5065
+ isThrottled(name) {
5066
+ const rule = this.options.rules?.find((r) => r.name === name);
5067
+ if (!rule?.throttle) {
5068
+ return false;
5069
+ }
5070
+ const lastTime = this.lastAlertTime.get(name);
5071
+ if (!lastTime) {
5072
+ return false;
5073
+ }
5074
+ return Date.now() - lastTime < rule.throttle;
5075
+ }
5076
+ async sendToChannel(channelName, alert) {
5077
+ const channel = this.options.channels[channelName];
5078
+ if (!channel) {
5079
+ throw new Error(`Channel not found: ${channelName}`);
5080
+ }
5081
+ switch (channel.type) {
5082
+ case "email":
5083
+ logger4.info("Alert sent to email", {
5084
+ channel: channelName,
5085
+ to: channel.config.to,
5086
+ alert: { name: alert.name, severity: alert.severity, message: alert.message }
5087
+ });
5088
+ break;
5089
+ case "slack":
5090
+ logger4.info("Alert sent to Slack", {
5091
+ channel: channelName,
5092
+ webhookUrl: channel.config.webhookUrl,
5093
+ alert: { name: alert.name, severity: alert.severity, message: alert.message }
5094
+ });
5095
+ break;
5096
+ case "webhook":
5097
+ logger4.info("Alert sent to webhook", {
5098
+ channel: channelName,
5099
+ url: channel.config.url,
5100
+ alert: { name: alert.name, severity: alert.severity, message: alert.message }
5101
+ });
5102
+ break;
5103
+ default:
5104
+ logger4.info("Alert sent", {
5105
+ channel: channelName,
5106
+ channelType: channel.type,
5107
+ alert: { name: alert.name, severity: alert.severity, message: alert.message }
5108
+ });
5109
+ }
5110
+ }
5111
+ getAlertHistory(name, limit = 100) {
5112
+ return [];
5113
+ }
5114
+ clearAlertHistory(name) {
5115
+ if (name) {
5116
+ this.lastAlertTime.delete(name);
5117
+ } else {
5118
+ this.lastAlertTime.clear();
5119
+ }
5120
+ }
5121
+ };
5122
+ function createAlertManager(options) {
5123
+ return new AlertManager(options);
5124
+ }
5125
+
5126
+ // src/monitoring/audit.ts
5127
+ var AuditLogger = class {
5128
+ constructor(options = {}) {
5129
+ this.options = options;
5130
+ if (options.retention?.autoCleanup) {
5131
+ this.startCleanup();
5132
+ }
5133
+ }
5134
+ logs = [];
5135
+ cleanupTimer;
5136
+ async log(entry) {
5137
+ const fullEntry = {
5138
+ ...entry,
5139
+ id: this.generateId(),
5140
+ timestamp: entry.timestamp || Date.now(),
5141
+ success: entry.success ?? true
5142
+ };
5143
+ const fields = this.options.fields || {};
5144
+ const filteredEntry = {
5145
+ id: fullEntry.id,
5146
+ userId: fields.userId !== false ? fullEntry.userId : "",
5147
+ action: fields.action !== false ? fullEntry.action : "",
5148
+ resource: fields.resource !== false ? fullEntry.resource : "",
5149
+ timestamp: fields.timestamp !== false ? fullEntry.timestamp : void 0
5150
+ };
5151
+ if (fields.input !== false && fullEntry.input) {
5152
+ filteredEntry.input = fullEntry.input;
5153
+ }
5154
+ if (fields.output !== false && fullEntry.output) {
5155
+ filteredEntry.output = fullEntry.output;
5156
+ }
5157
+ if (fullEntry.metadata) {
5158
+ filteredEntry.metadata = fullEntry.metadata;
5159
+ }
5160
+ if (fullEntry.error) {
5161
+ filteredEntry.error = fullEntry.error;
5162
+ filteredEntry.success = false;
5163
+ }
5164
+ this.logs.push(filteredEntry);
5165
+ this.options.onLog?.(filteredEntry);
5166
+ }
5167
+ async query(query = {}) {
5168
+ let results = [...this.logs];
5169
+ if (query.userId) {
5170
+ results = results.filter((log) => log.userId === query.userId);
5171
+ }
5172
+ if (query.action) {
5173
+ results = results.filter((log) => log.action === query.action);
5174
+ }
5175
+ if (query.resource) {
5176
+ results = results.filter((log) => log.resource === query.resource);
5177
+ }
5178
+ if (query.startDate) {
5179
+ const startTime = query.startDate.getTime();
5180
+ results = results.filter((log) => (log.timestamp || 0) >= startTime);
5181
+ }
5182
+ if (query.endDate) {
5183
+ const endTime = query.endDate.getTime();
5184
+ results = results.filter((log) => (log.timestamp || 0) <= endTime);
5185
+ }
5186
+ const offset = query.offset || 0;
5187
+ const limit = query.limit || 100;
5188
+ results = results.slice(offset, offset + limit);
5189
+ return results;
5190
+ }
5191
+ async export(path, options = {}) {
5192
+ const logs = await this.query({
5193
+ startDate: options.startDate,
5194
+ endDate: options.endDate
5195
+ });
5196
+ const format = options.format || "json";
5197
+ if (format === "json") {
5198
+ console.log(`Exporting ${logs.length} audit logs to ${path} (JSON)`);
5199
+ console.log(JSON.stringify(logs, null, 2));
5200
+ } else if (format === "csv") {
5201
+ console.log(`Exporting ${logs.length} audit logs to ${path} (CSV)`);
5202
+ const csv = this.convertToCSV(logs);
5203
+ console.log(csv);
5204
+ }
5205
+ }
5206
+ convertToCSV(logs) {
5207
+ if (logs.length === 0) {
5208
+ return "";
5209
+ }
5210
+ const headers = ["id", "userId", "action", "resource", "timestamp", "success"];
5211
+ const rows = logs.map((log) => [
5212
+ log.id,
5213
+ log.userId,
5214
+ log.action,
5215
+ log.resource,
5216
+ log.timestamp,
5217
+ log.success
5218
+ ]);
5219
+ return [headers.join(","), ...rows.map((row) => row.join(","))].join("\n");
5220
+ }
5221
+ startCleanup() {
5222
+ const interval = 24 * 60 * 60 * 1e3;
5223
+ this.cleanupTimer = setInterval(() => {
5224
+ this.cleanup();
5225
+ }, interval);
5226
+ }
5227
+ cleanup() {
5228
+ if (!this.options.retention) {
5229
+ return;
5230
+ }
5231
+ const retentionMs = this.options.retention.days * 24 * 60 * 60 * 1e3;
5232
+ const cutoffTime = Date.now() - retentionMs;
5233
+ this.logs = this.logs.filter((log) => (log.timestamp || 0) >= cutoffTime);
5234
+ }
5235
+ generateId() {
5236
+ return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
5237
+ }
5238
+ stop() {
5239
+ if (this.cleanupTimer) {
5240
+ clearInterval(this.cleanupTimer);
5241
+ this.cleanupTimer = void 0;
5242
+ }
5243
+ }
5244
+ };
5245
+ function createAuditLogger(options) {
5246
+ return new AuditLogger(options);
5247
+ }
5248
+
4770
5249
  // src/prompt-loader/index.ts
4771
5250
  import { readFileSync } from "fs";
4772
5251
  import { join } from "path";
@@ -4830,10 +5309,13 @@ function loadPrompt(promptName, options = {}, promptsDir) {
4830
5309
  }
4831
5310
  export {
4832
5311
  AgentError,
5312
+ AlertManager,
5313
+ AuditLogger,
4833
5314
  BatchProcessor,
4834
5315
  CircuitBreaker,
4835
5316
  ConnectionPool,
4836
5317
  DatabasePool,
5318
+ HealthChecker,
4837
5319
  HttpPool,
4838
5320
  LogLevel,
4839
5321
  ManagedTool,
@@ -4841,6 +5323,7 @@ export {
4841
5323
  MetricType,
4842
5324
  MiddlewareChain,
4843
5325
  MissingDescriptionError,
5326
+ Profiler,
4844
5327
  RegistryEvent,
4845
5328
  TimeoutError,
4846
5329
  ToolBuilder,
@@ -4864,7 +5347,9 @@ export {
4864
5347
  composeWithOptions,
4865
5348
  conditional,
4866
5349
  configureLangSmith,
5350
+ createAlertManager,
4867
5351
  createApprovalRequiredInterrupt,
5352
+ createAuditLogger,
4868
5353
  createBatchProcessor,
4869
5354
  createBinaryRouter,
4870
5355
  createCircuitBreaker,
@@ -4874,6 +5359,7 @@ export {
4874
5359
  createCustomInterrupt,
4875
5360
  createDatabasePool,
4876
5361
  createErrorReporter,
5362
+ createHealthChecker,
4877
5363
  createHeartbeat,
4878
5364
  createHttpPool,
4879
5365
  createHumanRequestInterrupt,
@@ -4887,6 +5373,7 @@ export {
4887
5373
  createMockTool,
4888
5374
  createMultiRouter,
4889
5375
  createParallelWorkflow,
5376
+ createProfiler,
4890
5377
  createProgressTracker,
4891
5378
  createSSEFormatter,
4892
5379
  createSequentialWorkflow,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentforge/core",
3
- "version": "0.11.8",
3
+ "version": "0.12.0",
4
4
  "description": "Core abstractions for AgentForge - production-ready deep agents framework",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",