@loopstack/observability-examples 0.1.0 → 0.1.2

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 (66) hide show
  1. package/README.md +60 -6
  2. package/dist/index.d.ts +10 -0
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +10 -0
  5. package/dist/index.js.map +1 -1
  6. package/dist/observability-examples.module.d.ts +6 -1
  7. package/dist/observability-examples.module.d.ts.map +1 -1
  8. package/dist/observability-examples.module.js +36 -4
  9. package/dist/observability-examples.module.js.map +1 -1
  10. package/dist/workflows/audit-log/audit-log-example.workflow.d.ts +10 -0
  11. package/dist/workflows/audit-log/audit-log-example.workflow.d.ts.map +1 -0
  12. package/dist/workflows/audit-log/audit-log-example.workflow.js +66 -0
  13. package/dist/workflows/audit-log/audit-log-example.workflow.js.map +1 -0
  14. package/dist/workflows/audit-log/listeners/audit.listener.d.ts +9 -0
  15. package/dist/workflows/audit-log/listeners/audit.listener.d.ts.map +1 -0
  16. package/dist/workflows/audit-log/listeners/audit.listener.js +44 -0
  17. package/dist/workflows/audit-log/listeners/audit.listener.js.map +1 -0
  18. package/dist/workflows/audit-log/services/audit-log.service.d.ts +11 -0
  19. package/dist/workflows/audit-log/services/audit-log.service.d.ts.map +1 -0
  20. package/dist/workflows/audit-log/services/audit-log.service.js +28 -0
  21. package/dist/workflows/audit-log/services/audit-log.service.js.map +1 -0
  22. package/dist/workflows/custom-calculator/calculators/words-processed.calculator.d.ts +7 -0
  23. package/dist/workflows/custom-calculator/calculators/words-processed.calculator.d.ts.map +1 -0
  24. package/dist/workflows/custom-calculator/calculators/words-processed.calculator.js +15 -0
  25. package/dist/workflows/custom-calculator/calculators/words-processed.calculator.js.map +1 -0
  26. package/dist/workflows/custom-calculator/custom-calculator-example.workflow.d.ts +17 -0
  27. package/dist/workflows/custom-calculator/custom-calculator-example.workflow.d.ts.map +1 -0
  28. package/dist/workflows/custom-calculator/custom-calculator-example.workflow.js +66 -0
  29. package/dist/workflows/custom-calculator/custom-calculator-example.workflow.js.map +1 -0
  30. package/dist/workflows/custom-calculator/tools/analyze-text.tool.d.ts +19 -0
  31. package/dist/workflows/custom-calculator/tools/analyze-text.tool.d.ts.map +1 -0
  32. package/dist/workflows/custom-calculator/tools/analyze-text.tool.js +35 -0
  33. package/dist/workflows/custom-calculator/tools/analyze-text.tool.js.map +1 -0
  34. package/dist/workflows/quota/quota-example.workflow.js +1 -1
  35. package/dist/workflows/quota/quota-example.workflow.js.map +1 -1
  36. package/dist/workflows/tracing/interceptors/tracing.interceptor.d.ts +10 -0
  37. package/dist/workflows/tracing/interceptors/tracing.interceptor.d.ts.map +1 -0
  38. package/dist/workflows/tracing/interceptors/tracing.interceptor.js +48 -0
  39. package/dist/workflows/tracing/interceptors/tracing.interceptor.js.map +1 -0
  40. package/dist/workflows/tracing/services/tool-trace.service.d.ts +12 -0
  41. package/dist/workflows/tracing/services/tool-trace.service.d.ts.map +1 -0
  42. package/dist/workflows/tracing/services/tool-trace.service.js +28 -0
  43. package/dist/workflows/tracing/services/tool-trace.service.js.map +1 -0
  44. package/dist/workflows/tracing/tools/simulate-work.tool.d.ts +20 -0
  45. package/dist/workflows/tracing/tools/simulate-work.tool.d.ts.map +1 -0
  46. package/dist/workflows/tracing/tools/simulate-work.tool.js +36 -0
  47. package/dist/workflows/tracing/tools/simulate-work.tool.js.map +1 -0
  48. package/dist/workflows/tracing/tracing-example.workflow.d.ts +17 -0
  49. package/dist/workflows/tracing/tracing-example.workflow.d.ts.map +1 -0
  50. package/dist/workflows/tracing/tracing-example.workflow.js +62 -0
  51. package/dist/workflows/tracing/tracing-example.workflow.js.map +1 -0
  52. package/package.json +4 -2
  53. package/src/index.ts +10 -0
  54. package/src/observability-examples.module.ts +33 -6
  55. package/src/workflows/audit-log/audit-log-example.workflow.ts +43 -0
  56. package/src/workflows/audit-log/listeners/audit.listener.ts +22 -0
  57. package/src/workflows/audit-log/services/audit-log.service.ts +25 -0
  58. package/src/workflows/custom-calculator/__tests__/custom-calculator-example.spec.ts +27 -0
  59. package/src/workflows/custom-calculator/calculators/words-processed.calculator.ts +15 -0
  60. package/src/workflows/custom-calculator/custom-calculator-example.workflow.ts +52 -0
  61. package/src/workflows/custom-calculator/tools/analyze-text.tool.ts +32 -0
  62. package/src/workflows/quota/quota-example.workflow.ts +1 -1
  63. package/src/workflows/tracing/interceptors/tracing.interceptor.ts +31 -0
  64. package/src/workflows/tracing/services/tool-trace.service.ts +26 -0
  65. package/src/workflows/tracing/tools/simulate-work.tool.ts +33 -0
  66. package/src/workflows/tracing/tracing-example.workflow.ts +47 -0
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  title: Observability Examples
3
- description: Workflow examples for observability in Loopstack — opt-in quota tracking and enforcement
3
+ description: Workflow examples for observability in Loopstack — quota tracking, custom tool interceptors for tracing, custom quota calculators, and event-driven audit logging
4
4
  ---
5
5
 
6
6
  # @loopstack/observability-examples
@@ -40,26 +40,80 @@ import { ObservabilityExamplesModule } from '@loopstack/observability-examples';
40
40
 
41
41
  ## Examples
42
42
 
43
- | Example | Studio title | Description |
44
- | --------------- | ------------------------------- | ----------------------------------------------------------------------- |
45
- | [Quota](#quota) | `Observability - Quota Example` | Check + report usage with `@loopstack/quota`, Redis-backed when enabled |
43
+ | Example | Studio title | Description |
44
+ | --------------------------------------------------- | ------------------------------------------------- | --------------------------------------------------------------------------------- |
45
+ | [Quota](#quota) | `Observability - Quota Example` | Manual check + report usage with `@loopstack/quota`, Redis-backed when enabled |
46
+ | [Tracing Interceptor](#tracing-interceptor) | `Observability - Tracing Interceptor Example` | Custom `ToolInterceptor` measuring every tool execution app-wide |
47
+ | [Custom Quota Calculator](#custom-quota-calculator) | `Observability - Custom Quota Calculator Example` | Custom `ToolQuotaCalculator` metering a tool automatically via `QuotaInterceptor` |
48
+ | [Audit Log](#audit-log) | `Observability - Audit Log Example` | `@OnEvent` listener recording workflow & document lifecycle events |
46
49
 
47
50
  ---
48
51
 
49
52
  ## Quota
50
53
 
51
- Demonstrates opt-in quota tracking using `@loopstack/quota`:
54
+ Demonstrates the manual quota API of `@loopstack/quota`:
52
55
 
53
56
  1. `quotaClient.checkQuota(userId, quotaType)` — verify available budget
54
57
  2. Perform the (placeholder) operation if allowed
55
58
  3. `quotaClient.report(userId, quotaType, amount)` — charge against the quota
56
59
 
57
- When `QuotaModule.forRoot({ enabled: false })`, both calls no-op. Set `enabled: true` plus Redis connection options to enforce real limits.
60
+ When `QuotaModule.forRoot({ enabled: false })`, both calls no-op. Set `enabled: true` plus Redis connection options to enforce real limits. Note: with quota enabled, a user without a limit key in Redis is blocked by default.
61
+
62
+ Built-in quota types: `llm-cost` (LLM token cost in microcents) and `processing-time-ms` (tool execution time).
58
63
 
59
64
  ### Files
60
65
 
61
66
  - `quota-example.workflow.ts` — workflow class
62
67
 
68
+ ## Tracing Interceptor
69
+
70
+ Demonstrates writing a custom `ToolInterceptor`:
71
+
72
+ - `@UseToolInterceptor({ priority: 10 })` registers the class app-wide — the framework discovers it via NestJS `DiscoveryService`, no manual wiring
73
+ - The interceptor wraps **every** tool call (all modules), measures duration, and records entries in an injectable `ToolTraceService`
74
+ - The workflow runs a few `SimulateWorkTool` calls, then filters the trace by its own `workflowId` and renders a markdown table
75
+
76
+ Interceptors follow a chain pattern like NestJS interceptors: run logic before/after `next()`, transform results, short-circuit (caching), or catch errors. Lower priority runs first (outermost).
77
+
78
+ ### Files
79
+
80
+ - `tracing-example.workflow.ts` — workflow class
81
+ - `interceptors/tracing.interceptor.ts` — the custom `ToolInterceptor`
82
+ - `services/tool-trace.service.ts` — injectable trace store
83
+ - `tools/simulate-work.tool.ts` — demo tool that sleeps for a configurable duration
84
+
85
+ ## Custom Quota Calculator
86
+
87
+ Demonstrates extending the quota system with a custom `ToolQuotaCalculator`:
88
+
89
+ - `WordsProcessedQuotaCalculator` defines quota type `words-processed` and derives the charged amount from the tool result (word count)
90
+ - The module registers it for `AnalyzeTextTool` in `onModuleInit` via `QuotaCalculatorRegistry`
91
+ - The built-in `QuotaInterceptor` then checks the quota **before** and reports usage **after** every `AnalyzeTextTool` execution — the workflow just calls the tool, no manual check/report
92
+
93
+ This is the recommended pattern for metering tools: the workflow stays clean, enforcement lives in the interceptor.
94
+
95
+ ### Files
96
+
97
+ - `custom-calculator-example.workflow.ts` — workflow class
98
+ - `calculators/words-processed.calculator.ts` — the custom `ToolQuotaCalculator`
99
+ - `tools/analyze-text.tool.ts` — demo tool whose usage is metered
100
+
101
+ ## Audit Log
102
+
103
+ Demonstrates subscribing to framework events for monitoring:
104
+
105
+ - The framework dispatches lifecycle events on the `client.message` channel — e.g. `workflow.created`, `workflow.updated`, `document.created`
106
+ - `AuditListener` uses `@OnEvent('client.message')` to capture every event into an injectable `AuditLogService` (bounded in-memory store)
107
+ - The workflow saves a few documents to generate events, then renders its own audit trail filtered by `workflowId`
108
+
109
+ This is the event-driven counterpart to the tracing interceptor: interceptors wrap tool calls, event listeners observe workflow and document lifecycle. Swap the in-memory store for a database or metrics exporter in production.
110
+
111
+ ### Files
112
+
113
+ - `audit-log-example.workflow.ts` — workflow class
114
+ - `listeners/audit.listener.ts` — the `@OnEvent` listener
115
+ - `services/audit-log.service.ts` — injectable audit store
116
+
63
117
  ## About
64
118
 
65
119
  Author: [Jakob Klippel](https://www.linkedin.com/in/jakob-klippel/)
package/dist/index.d.ts CHANGED
@@ -1,3 +1,13 @@
1
1
  export * from './observability-examples.module';
2
2
  export * from './workflows/quota/quota-example.workflow';
3
+ export * from './workflows/tracing/tracing-example.workflow';
4
+ export * from './workflows/tracing/services/tool-trace.service';
5
+ export * from './workflows/tracing/interceptors/tracing.interceptor';
6
+ export * from './workflows/tracing/tools/simulate-work.tool';
7
+ export * from './workflows/custom-calculator/custom-calculator-example.workflow';
8
+ export * from './workflows/custom-calculator/calculators/words-processed.calculator';
9
+ export * from './workflows/custom-calculator/tools/analyze-text.tool';
10
+ export * from './workflows/audit-log/audit-log-example.workflow';
11
+ export * from './workflows/audit-log/services/audit-log.service';
12
+ export * from './workflows/audit-log/listeners/audit.listener';
3
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iCAAiC,CAAC;AAChD,cAAc,0CAA0C,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iCAAiC,CAAC;AAChD,cAAc,0CAA0C,CAAC;AACzD,cAAc,8CAA8C,CAAC;AAC7D,cAAc,iDAAiD,CAAC;AAChE,cAAc,sDAAsD,CAAC;AACrE,cAAc,8CAA8C,CAAC;AAC7D,cAAc,kEAAkE,CAAC;AACjF,cAAc,sEAAsE,CAAC;AACrF,cAAc,uDAAuD,CAAC;AACtE,cAAc,kDAAkD,CAAC;AACjE,cAAc,kDAAkD,CAAC;AACjE,cAAc,gDAAgD,CAAC"}
package/dist/index.js CHANGED
@@ -16,4 +16,14 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./observability-examples.module"), exports);
18
18
  __exportStar(require("./workflows/quota/quota-example.workflow"), exports);
19
+ __exportStar(require("./workflows/tracing/tracing-example.workflow"), exports);
20
+ __exportStar(require("./workflows/tracing/services/tool-trace.service"), exports);
21
+ __exportStar(require("./workflows/tracing/interceptors/tracing.interceptor"), exports);
22
+ __exportStar(require("./workflows/tracing/tools/simulate-work.tool"), exports);
23
+ __exportStar(require("./workflows/custom-calculator/custom-calculator-example.workflow"), exports);
24
+ __exportStar(require("./workflows/custom-calculator/calculators/words-processed.calculator"), exports);
25
+ __exportStar(require("./workflows/custom-calculator/tools/analyze-text.tool"), exports);
26
+ __exportStar(require("./workflows/audit-log/audit-log-example.workflow"), exports);
27
+ __exportStar(require("./workflows/audit-log/services/audit-log.service"), exports);
28
+ __exportStar(require("./workflows/audit-log/listeners/audit.listener"), exports);
19
29
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,kEAAgD;AAChD,2EAAyD"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,kEAAgD;AAChD,2EAAyD;AACzD,+EAA6D;AAC7D,kFAAgE;AAChE,uFAAqE;AACrE,+EAA6D;AAC7D,mGAAiF;AACjF,uGAAqF;AACrF,wFAAsE;AACtE,mFAAiE;AACjE,mFAAiE;AACjE,iFAA+D"}
@@ -1,3 +1,8 @@
1
- export declare class ObservabilityExamplesModule {
1
+ import { OnModuleInit } from '@nestjs/common';
2
+ import { QuotaCalculatorRegistry } from '@loopstack/quota';
3
+ export declare class ObservabilityExamplesModule implements OnModuleInit {
4
+ private readonly calculatorRegistry;
5
+ constructor(calculatorRegistry: QuotaCalculatorRegistry);
6
+ onModuleInit(): void;
2
7
  }
3
8
  //# sourceMappingURL=observability-examples.module.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"observability-examples.module.d.ts","sourceRoot":"","sources":["../src/observability-examples.module.ts"],"names":[],"mappings":"AAKA,qBASa,2BAA2B;CAAG"}
1
+ {"version":3,"file":"observability-examples.module.d.ts","sourceRoot":"","sources":["../src/observability-examples.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEtD,OAAO,EAAE,uBAAuB,EAAe,MAAM,kBAAkB,CAAC;AAaxE,qBAoBa,2BAA4B,YAAW,YAAY;IAClD,OAAO,CAAC,QAAQ,CAAC,kBAAkB;gBAAlB,kBAAkB,EAAE,uBAAuB;IAExE,YAAY;CAGb"}
@@ -5,24 +5,56 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
5
5
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
6
  return c > 3 && r && Object.defineProperty(target, key, r), r;
7
7
  };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
8
11
  Object.defineProperty(exports, "__esModule", { value: true });
9
12
  exports.ObservabilityExamplesModule = void 0;
10
13
  const common_1 = require("@nestjs/common");
11
14
  const common_2 = require("@loopstack/common");
12
15
  const quota_1 = require("@loopstack/quota");
16
+ const audit_log_example_workflow_1 = require("./workflows/audit-log/audit-log-example.workflow");
17
+ const audit_listener_1 = require("./workflows/audit-log/listeners/audit.listener");
18
+ const audit_log_service_1 = require("./workflows/audit-log/services/audit-log.service");
19
+ const words_processed_calculator_1 = require("./workflows/custom-calculator/calculators/words-processed.calculator");
20
+ const custom_calculator_example_workflow_1 = require("./workflows/custom-calculator/custom-calculator-example.workflow");
21
+ const analyze_text_tool_1 = require("./workflows/custom-calculator/tools/analyze-text.tool");
13
22
  const quota_example_workflow_1 = require("./workflows/quota/quota-example.workflow");
23
+ const tracing_interceptor_1 = require("./workflows/tracing/interceptors/tracing.interceptor");
24
+ const tool_trace_service_1 = require("./workflows/tracing/services/tool-trace.service");
25
+ const simulate_work_tool_1 = require("./workflows/tracing/tools/simulate-work.tool");
26
+ const tracing_example_workflow_1 = require("./workflows/tracing/tracing-example.workflow");
14
27
  let ObservabilityExamplesModule = class ObservabilityExamplesModule {
28
+ calculatorRegistry;
29
+ constructor(calculatorRegistry) {
30
+ this.calculatorRegistry = calculatorRegistry;
31
+ }
32
+ onModuleInit() {
33
+ this.calculatorRegistry.register('AnalyzeTextTool', new words_processed_calculator_1.WordsProcessedQuotaCalculator());
34
+ }
15
35
  };
16
36
  exports.ObservabilityExamplesModule = ObservabilityExamplesModule;
17
37
  exports.ObservabilityExamplesModule = ObservabilityExamplesModule = __decorate([
18
38
  (0, common_2.StudioApp)({
19
39
  title: 'Observability Examples',
20
- workflows: [quota_example_workflow_1.QuotaExampleWorkflow],
40
+ workflows: [quota_example_workflow_1.QuotaExampleWorkflow, tracing_example_workflow_1.TracingExampleWorkflow, custom_calculator_example_workflow_1.CustomCalculatorExampleWorkflow, audit_log_example_workflow_1.AuditLogExampleWorkflow],
21
41
  }),
22
42
  (0, common_1.Module)({
23
43
  imports: [quota_1.QuotaModule.forRoot({ enabled: false })],
24
- providers: [quota_example_workflow_1.QuotaExampleWorkflow],
25
- exports: [quota_example_workflow_1.QuotaExampleWorkflow],
26
- })
44
+ providers: [
45
+ quota_example_workflow_1.QuotaExampleWorkflow,
46
+ tracing_example_workflow_1.TracingExampleWorkflow,
47
+ tool_trace_service_1.ToolTraceService,
48
+ tracing_interceptor_1.TracingInterceptor,
49
+ simulate_work_tool_1.SimulateWorkTool,
50
+ custom_calculator_example_workflow_1.CustomCalculatorExampleWorkflow,
51
+ analyze_text_tool_1.AnalyzeTextTool,
52
+ audit_log_example_workflow_1.AuditLogExampleWorkflow,
53
+ audit_log_service_1.AuditLogService,
54
+ audit_listener_1.AuditListener,
55
+ ],
56
+ exports: [quota_example_workflow_1.QuotaExampleWorkflow, tracing_example_workflow_1.TracingExampleWorkflow, custom_calculator_example_workflow_1.CustomCalculatorExampleWorkflow, audit_log_example_workflow_1.AuditLogExampleWorkflow],
57
+ }),
58
+ __metadata("design:paramtypes", [quota_1.QuotaCalculatorRegistry])
27
59
  ], ObservabilityExamplesModule);
28
60
  //# sourceMappingURL=observability-examples.module.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"observability-examples.module.js","sourceRoot":"","sources":["../src/observability-examples.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,8CAA8C;AAC9C,4CAA+C;AAC/C,qFAAgF;AAWzE,IAAM,2BAA2B,GAAjC,MAAM,2BAA2B;CAAG,CAAA;AAA9B,kEAA2B;sCAA3B,2BAA2B;IATvC,IAAA,kBAAS,EAAC;QACT,KAAK,EAAE,wBAAwB;QAC/B,SAAS,EAAE,CAAC,6CAAoB,CAAC;KAClC,CAAC;IACD,IAAA,eAAM,EAAC;QACN,OAAO,EAAE,CAAC,mBAAW,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;QAClD,SAAS,EAAE,CAAC,6CAAoB,CAAC;QACjC,OAAO,EAAE,CAAC,6CAAoB,CAAC;KAChC,CAAC;GACW,2BAA2B,CAAG"}
1
+ {"version":3,"file":"observability-examples.module.js","sourceRoot":"","sources":["../src/observability-examples.module.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAAsD;AACtD,8CAA8C;AAC9C,4CAAwE;AACxE,iGAA2F;AAC3F,mFAA+E;AAC/E,wFAAmF;AACnF,qHAAqH;AACrH,yHAAmH;AACnH,6FAAwF;AACxF,qFAAgF;AAChF,8FAA0F;AAC1F,wFAAmF;AACnF,qFAAgF;AAChF,2FAAsF;AAsB/E,IAAM,2BAA2B,GAAjC,MAAM,2BAA2B;IACT;IAA7B,YAA6B,kBAA2C;QAA3C,uBAAkB,GAAlB,kBAAkB,CAAyB;IAAG,CAAC;IAE5E,YAAY;QACV,IAAI,CAAC,kBAAkB,CAAC,QAAQ,CAAC,iBAAiB,EAAE,IAAI,0DAA6B,EAAE,CAAC,CAAC;IAC3F,CAAC;CACF,CAAA;AANY,kEAA2B;sCAA3B,2BAA2B;IApBvC,IAAA,kBAAS,EAAC;QACT,KAAK,EAAE,wBAAwB;QAC/B,SAAS,EAAE,CAAC,6CAAoB,EAAE,iDAAsB,EAAE,oEAA+B,EAAE,oDAAuB,CAAC;KACpH,CAAC;IACD,IAAA,eAAM,EAAC;QACN,OAAO,EAAE,CAAC,mBAAW,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;QAClD,SAAS,EAAE;YACT,6CAAoB;YACpB,iDAAsB;YACtB,qCAAgB;YAChB,wCAAkB;YAClB,qCAAgB;YAChB,oEAA+B;YAC/B,mCAAe;YACf,oDAAuB;YACvB,mCAAe;YACf,8BAAa;SACd;QACD,OAAO,EAAE,CAAC,6CAAoB,EAAE,iDAAsB,EAAE,oEAA+B,EAAE,oDAAuB,CAAC;KAClH,CAAC;qCAEiD,+BAAuB;GAD7D,2BAA2B,CAMvC"}
@@ -0,0 +1,10 @@
1
+ import { BaseWorkflow } from '@loopstack/common';
2
+ import type { RunContext } from '@loopstack/common';
3
+ import { AuditLogService } from './services/audit-log.service';
4
+ export declare class AuditLogExampleWorkflow extends BaseWorkflow {
5
+ private readonly auditLog;
6
+ constructor(auditLog: AuditLogService);
7
+ doWork(): Promise<void>;
8
+ renderAudit(_state: object, ctx: RunContext): Promise<void>;
9
+ }
10
+ //# sourceMappingURL=audit-log-example.workflow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-log-example.workflow.d.ts","sourceRoot":"","sources":["../../../src/workflows/audit-log/audit-log-example.workflow.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAA2D,MAAM,mBAAmB,CAAC;AAC1G,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAE/D,qBAKa,uBAAwB,SAAQ,YAAY;IAC3C,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAAR,QAAQ,EAAE,eAAe;IAKhD,MAAM;IAYN,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU;CAelD"}
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.AuditLogExampleWorkflow = void 0;
13
+ const common_1 = require("@loopstack/common");
14
+ const audit_log_service_1 = require("./services/audit-log.service");
15
+ let AuditLogExampleWorkflow = class AuditLogExampleWorkflow extends common_1.BaseWorkflow {
16
+ auditLog;
17
+ constructor(auditLog) {
18
+ super();
19
+ this.auditLog = auditLog;
20
+ }
21
+ async doWork() {
22
+ await this.documentStore.save(common_1.MessageDocument, {
23
+ role: 'assistant',
24
+ text: 'Doing some work — each saved document emits a `document.created` event.',
25
+ });
26
+ await this.documentStore.save(common_1.MessageDocument, {
27
+ role: 'assistant',
28
+ text: 'The audit listener captures these events app-wide.',
29
+ });
30
+ }
31
+ async renderAudit(_state, ctx) {
32
+ const entries = this.auditLog.forWorkflow(ctx.workflowId);
33
+ await this.documentStore.save(common_1.MarkdownDocument, {
34
+ markdown: [
35
+ '## Audit Trail',
36
+ '',
37
+ `Captured by \`AuditListener\` via \`@OnEvent('client.message')\` for workflow \`${ctx.workflowId}\`.`,
38
+ '',
39
+ '| Event type | User |',
40
+ '| ---------- | ---- |',
41
+ ...entries.map((e) => `| \`${e.type}\` | \`${e.userId ?? 'anonymous'}\` |`),
42
+ ].join('\n'),
43
+ });
44
+ }
45
+ };
46
+ exports.AuditLogExampleWorkflow = AuditLogExampleWorkflow;
47
+ __decorate([
48
+ (0, common_1.Transition)({ to: 'auditing' }),
49
+ __metadata("design:type", Function),
50
+ __metadata("design:paramtypes", []),
51
+ __metadata("design:returntype", Promise)
52
+ ], AuditLogExampleWorkflow.prototype, "doWork", null);
53
+ __decorate([
54
+ (0, common_1.Transition)({ from: 'auditing', to: 'end' }),
55
+ __metadata("design:type", Function),
56
+ __metadata("design:paramtypes", [Object, Object]),
57
+ __metadata("design:returntype", Promise)
58
+ ], AuditLogExampleWorkflow.prototype, "renderAudit", null);
59
+ exports.AuditLogExampleWorkflow = AuditLogExampleWorkflow = __decorate([
60
+ (0, common_1.Workflow)({
61
+ title: 'Observability - Audit Log Example',
62
+ description: 'Demonstrates subscribing to framework events — an @OnEvent("client.message") listener records every workflow and document lifecycle event into an injectable service. The workflow emits a few events, then renders its own audit trail.',
63
+ }),
64
+ __metadata("design:paramtypes", [audit_log_service_1.AuditLogService])
65
+ ], AuditLogExampleWorkflow);
66
+ //# sourceMappingURL=audit-log-example.workflow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-log-example.workflow.js","sourceRoot":"","sources":["../../../src/workflows/audit-log/audit-log-example.workflow.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,8CAA0G;AAE1G,oEAA+D;AAOxD,IAAM,uBAAuB,GAA7B,MAAM,uBAAwB,SAAQ,qBAAY;IAC1B;IAA7B,YAA6B,QAAyB;QACpD,KAAK,EAAE,CAAC;QADmB,aAAQ,GAAR,QAAQ,CAAiB;IAEtD,CAAC;IAGK,AAAN,KAAK,CAAC,MAAM;QACV,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,wBAAe,EAAE;YAC7C,IAAI,EAAE,WAAW;YACjB,IAAI,EAAE,yEAAyE;SAChF,CAAC,CAAC;QACH,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,wBAAe,EAAE;YAC7C,IAAI,EAAE,WAAW;YACjB,IAAI,EAAE,oDAAoD;SAC3D,CAAC,CAAC;IACL,CAAC;IAGK,AAAN,KAAK,CAAC,WAAW,CAAC,MAAc,EAAE,GAAe;QAC/C,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAE1D,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,yBAAgB,EAAE;YAC9C,QAAQ,EAAE;gBACR,gBAAgB;gBAChB,EAAE;gBACF,mFAAmF,GAAG,CAAC,UAAU,KAAK;gBACtG,EAAE;gBACF,uBAAuB;gBACvB,uBAAuB;gBACvB,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,UAAU,CAAC,CAAC,MAAM,IAAI,WAAW,MAAM,CAAC;aAC5E,CAAC,IAAI,CAAC,IAAI,CAAC;SACb,CAAC,CAAC;IACL,CAAC;CACF,CAAA;AAjCY,0DAAuB;AAM5B;IADL,IAAA,mBAAU,EAAC,EAAE,EAAE,EAAE,UAAU,EAAE,CAAC;;;;qDAU9B;AAGK;IADL,IAAA,mBAAU,EAAC,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC;;;;0DAe3C;kCAhCU,uBAAuB;IALnC,IAAA,iBAAQ,EAAC;QACR,KAAK,EAAE,mCAAmC;QAC1C,WAAW,EACT,0OAA0O;KAC7O,CAAC;qCAEuC,mCAAe;GAD3C,uBAAuB,CAiCnC"}
@@ -0,0 +1,9 @@
1
+ import type { ClientMessage } from '@loopstack/contracts/events';
2
+ import { AuditLogService } from '../services/audit-log.service';
3
+ export declare class AuditListener {
4
+ private readonly auditLog;
5
+ private readonly logger;
6
+ constructor(auditLog: AuditLogService);
7
+ handle(payload: ClientMessage): void;
8
+ }
9
+ //# sourceMappingURL=audit.listener.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.listener.d.ts","sourceRoot":"","sources":["../../../../src/workflows/audit-log/listeners/audit.listener.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAEhE,qBACa,aAAa;IAGZ,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAFrC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkC;gBAE5B,QAAQ,EAAE,eAAe;IAGtD,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI;CASrC"}
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var AuditListener_1;
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.AuditListener = void 0;
14
+ const common_1 = require("@nestjs/common");
15
+ const event_emitter_1 = require("@nestjs/event-emitter");
16
+ const audit_log_service_1 = require("../services/audit-log.service");
17
+ let AuditListener = AuditListener_1 = class AuditListener {
18
+ auditLog;
19
+ logger = new common_1.Logger(AuditListener_1.name);
20
+ constructor(auditLog) {
21
+ this.auditLog = auditLog;
22
+ }
23
+ handle(payload) {
24
+ const workflowId = 'workflowId' in payload ? payload.workflowId : undefined;
25
+ this.auditLog.record({
26
+ type: payload.type,
27
+ workflowId,
28
+ userId: payload.userId,
29
+ });
30
+ this.logger.log(`${payload.type} (workflow ${workflowId ?? '-'})`);
31
+ }
32
+ };
33
+ exports.AuditListener = AuditListener;
34
+ __decorate([
35
+ (0, event_emitter_1.OnEvent)('client.message'),
36
+ __metadata("design:type", Function),
37
+ __metadata("design:paramtypes", [Object]),
38
+ __metadata("design:returntype", void 0)
39
+ ], AuditListener.prototype, "handle", null);
40
+ exports.AuditListener = AuditListener = AuditListener_1 = __decorate([
41
+ (0, common_1.Injectable)(),
42
+ __metadata("design:paramtypes", [audit_log_service_1.AuditLogService])
43
+ ], AuditListener);
44
+ //# sourceMappingURL=audit.listener.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.listener.js","sourceRoot":"","sources":["../../../../src/workflows/audit-log/listeners/audit.listener.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,2CAAoD;AACpD,yDAAgD;AAEhD,qEAAgE;AAGzD,IAAM,aAAa,qBAAnB,MAAM,aAAa;IAGK;IAFZ,MAAM,GAAG,IAAI,eAAM,CAAC,eAAa,CAAC,IAAI,CAAC,CAAC;IAEzD,YAA6B,QAAyB;QAAzB,aAAQ,GAAR,QAAQ,CAAiB;IAAG,CAAC;IAG1D,MAAM,CAAC,OAAsB;QAC3B,MAAM,UAAU,GAAG,YAAY,IAAI,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC;QAC5E,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;YACnB,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,UAAU;YACV,MAAM,EAAE,OAAO,CAAC,MAAM;SACvB,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,IAAI,cAAc,UAAU,IAAI,GAAG,GAAG,CAAC,CAAC;IACrE,CAAC;CACF,CAAA;AAfY,sCAAa;AAMxB;IADC,IAAA,uBAAO,EAAC,gBAAgB,CAAC;;;;2CASzB;wBAdU,aAAa;IADzB,IAAA,mBAAU,GAAE;qCAI4B,mCAAe;GAH3C,aAAa,CAezB"}
@@ -0,0 +1,11 @@
1
+ export interface AuditEntry {
2
+ type: string;
3
+ workflowId?: string;
4
+ userId: string | null;
5
+ }
6
+ export declare class AuditLogService {
7
+ private readonly entries;
8
+ record(entry: AuditEntry): void;
9
+ forWorkflow(workflowId: string): AuditEntry[];
10
+ }
11
+ //# sourceMappingURL=audit-log.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-log.service.d.ts","sourceRoot":"","sources":["../../../../src/workflows/audit-log/services/audit-log.service.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAID,qBACa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoB;IAE5C,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAO/B,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU,EAAE;CAG9C"}
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.AuditLogService = void 0;
10
+ const common_1 = require("@nestjs/common");
11
+ const MAX_ENTRIES = 200;
12
+ let AuditLogService = class AuditLogService {
13
+ entries = [];
14
+ record(entry) {
15
+ this.entries.push(entry);
16
+ if (this.entries.length > MAX_ENTRIES) {
17
+ this.entries.shift();
18
+ }
19
+ }
20
+ forWorkflow(workflowId) {
21
+ return this.entries.filter((entry) => entry.workflowId === workflowId);
22
+ }
23
+ };
24
+ exports.AuditLogService = AuditLogService;
25
+ exports.AuditLogService = AuditLogService = __decorate([
26
+ (0, common_1.Injectable)()
27
+ ], AuditLogService);
28
+ //# sourceMappingURL=audit-log.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-log.service.js","sourceRoot":"","sources":["../../../../src/workflows/audit-log/services/audit-log.service.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAA4C;AAQ5C,MAAM,WAAW,GAAG,GAAG,CAAC;AAGjB,IAAM,eAAe,GAArB,MAAM,eAAe;IACT,OAAO,GAAiB,EAAE,CAAC;IAE5C,MAAM,CAAC,KAAiB;QACtB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzB,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,WAAW,EAAE,CAAC;YACtC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACvB,CAAC;IACH,CAAC;IAED,WAAW,CAAC,UAAkB;QAC5B,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,UAAU,KAAK,UAAU,CAAC,CAAC;IACzE,CAAC;CACF,CAAA;AAbY,0CAAe;0BAAf,eAAe;IAD3B,IAAA,mBAAU,GAAE;GACA,eAAe,CAa3B"}
@@ -0,0 +1,7 @@
1
+ import { ToolEnvelope, ToolExecutionContext } from '@loopstack/common';
2
+ import { QuotaUsage, ToolQuotaCalculator } from '@loopstack/quota';
3
+ export declare class WordsProcessedQuotaCalculator implements ToolQuotaCalculator {
4
+ quotaType: string;
5
+ calculateQuotaUsage(_context: ToolExecutionContext, result: ToolEnvelope): QuotaUsage | null;
6
+ }
7
+ //# sourceMappingURL=words-processed.calculator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"words-processed.calculator.d.ts","sourceRoot":"","sources":["../../../../src/workflows/custom-calculator/calculators/words-processed.calculator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAGnE,qBAAa,6BAA8B,YAAW,mBAAmB;IACvE,SAAS,SAAqB;IAE9B,mBAAmB,CAAC,QAAQ,EAAE,oBAAoB,EAAE,MAAM,EAAE,YAAY,GAAG,UAAU,GAAG,IAAI;CAO7F"}
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WordsProcessedQuotaCalculator = void 0;
4
+ class WordsProcessedQuotaCalculator {
5
+ quotaType = 'words-processed';
6
+ calculateQuotaUsage(_context, result) {
7
+ const data = result.data;
8
+ if (typeof data?.words !== 'number') {
9
+ return null;
10
+ }
11
+ return { quotaType: this.quotaType, actualAmount: data.words };
12
+ }
13
+ }
14
+ exports.WordsProcessedQuotaCalculator = WordsProcessedQuotaCalculator;
15
+ //# sourceMappingURL=words-processed.calculator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"words-processed.calculator.js","sourceRoot":"","sources":["../../../../src/workflows/custom-calculator/calculators/words-processed.calculator.ts"],"names":[],"mappings":";;;AAIA,MAAa,6BAA6B;IACxC,SAAS,GAAG,iBAAiB,CAAC;IAE9B,mBAAmB,CAAC,QAA8B,EAAE,MAAoB;QACtE,MAAM,IAAI,GAAG,MAAM,CAAC,IAAyC,CAAC;QAC9D,IAAI,OAAO,IAAI,EAAE,KAAK,KAAK,QAAQ,EAAE,CAAC;YACpC,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,YAAY,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;IACjE,CAAC;CACF;AAVD,sEAUC"}
@@ -0,0 +1,17 @@
1
+ import { z } from 'zod';
2
+ import { BaseWorkflow } from '@loopstack/common';
3
+ import type { RunContext } from '@loopstack/common';
4
+ import { QuotaClientService } from '@loopstack/quota';
5
+ import { AnalyzeTextTool } from './tools/analyze-text.tool';
6
+ declare const CustomCalculatorExampleArgsSchema: z.ZodObject<{
7
+ text: z.ZodDefault<z.ZodString>;
8
+ }, z.core.$strip>;
9
+ type CustomCalculatorExampleArgs = z.infer<typeof CustomCalculatorExampleArgsSchema>;
10
+ export declare class CustomCalculatorExampleWorkflow extends BaseWorkflow<CustomCalculatorExampleArgs> {
11
+ private readonly analyzeTextTool;
12
+ private readonly quotaClient;
13
+ constructor(analyzeTextTool: AnalyzeTextTool, quotaClient: QuotaClientService);
14
+ analyze(_state: object, ctx: RunContext<CustomCalculatorExampleArgs>): Promise<void>;
15
+ }
16
+ export {};
17
+ //# sourceMappingURL=custom-calculator-example.workflow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"custom-calculator-example.workflow.d.ts","sourceRoot":"","sources":["../../../src/workflows/custom-calculator/custom-calculator-example.workflow.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAA0C,MAAM,mBAAmB,CAAC;AACzF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAG5D,QAAA,MAAM,iCAAiC;;iBAErC,CAAC;AAEH,KAAK,2BAA2B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iCAAiC,CAAC,CAAC;AAErF,qBAMa,+BAAgC,SAAQ,YAAY,CAAC,2BAA2B,CAAC;IAE1F,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,WAAW;gBADX,eAAe,EAAE,eAAe,EAChC,WAAW,EAAE,kBAAkB;IAM5C,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,CAAC,2BAA2B,CAAC;CAuB3E"}
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.CustomCalculatorExampleWorkflow = void 0;
13
+ const zod_1 = require("zod");
14
+ const common_1 = require("@loopstack/common");
15
+ const quota_1 = require("@loopstack/quota");
16
+ const analyze_text_tool_1 = require("./tools/analyze-text.tool");
17
+ const CustomCalculatorExampleArgsSchema = zod_1.z.object({
18
+ text: zod_1.z.string().default('The quick brown fox jumps over the lazy dog'),
19
+ });
20
+ let CustomCalculatorExampleWorkflow = class CustomCalculatorExampleWorkflow extends common_1.BaseWorkflow {
21
+ analyzeTextTool;
22
+ quotaClient;
23
+ constructor(analyzeTextTool, quotaClient) {
24
+ super();
25
+ this.analyzeTextTool = analyzeTextTool;
26
+ this.quotaClient = quotaClient;
27
+ }
28
+ async analyze(_state, ctx) {
29
+ const result = await this.analyzeTextTool.call({ text: ctx.args.text });
30
+ const analysis = result.data;
31
+ const quota = await this.quotaClient.checkQuota(ctx.userId, 'words-processed');
32
+ await this.documentStore.save(common_1.MarkdownDocument, {
33
+ markdown: [
34
+ '## Text Analysis',
35
+ '',
36
+ `- Words: \`${analysis.words}\``,
37
+ `- Characters: \`${analysis.characters}\``,
38
+ '',
39
+ '## Quota `words-processed`',
40
+ '',
41
+ `- Used: \`${quota.used}\``,
42
+ `- Limit: \`${quota.limit}\` (\`-1\` = unlimited / quota disabled)`,
43
+ '',
44
+ 'The `QuotaInterceptor` charged the word count automatically via `WordsProcessedQuotaCalculator`.',
45
+ 'With `QuotaModule.forRoot({ enabled: false })` all quota calls no-op.',
46
+ ].join('\n'),
47
+ });
48
+ }
49
+ };
50
+ exports.CustomCalculatorExampleWorkflow = CustomCalculatorExampleWorkflow;
51
+ __decorate([
52
+ (0, common_1.Transition)({ to: 'end' }),
53
+ __metadata("design:type", Function),
54
+ __metadata("design:paramtypes", [Object, Object]),
55
+ __metadata("design:returntype", Promise)
56
+ ], CustomCalculatorExampleWorkflow.prototype, "analyze", null);
57
+ exports.CustomCalculatorExampleWorkflow = CustomCalculatorExampleWorkflow = __decorate([
58
+ (0, common_1.Workflow)({
59
+ title: 'Observability - Custom Quota Calculator Example',
60
+ description: 'Demonstrates a custom ToolQuotaCalculator — WordsProcessedQuotaCalculator meters AnalyzeTextTool by words in the result. The built-in QuotaInterceptor checks and reports the quota automatically; the workflow only calls the tool.',
61
+ schema: CustomCalculatorExampleArgsSchema,
62
+ }),
63
+ __metadata("design:paramtypes", [analyze_text_tool_1.AnalyzeTextTool,
64
+ quota_1.QuotaClientService])
65
+ ], CustomCalculatorExampleWorkflow);
66
+ //# sourceMappingURL=custom-calculator-example.workflow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"custom-calculator-example.workflow.js","sourceRoot":"","sources":["../../../src/workflows/custom-calculator/custom-calculator-example.workflow.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,6BAAwB;AACxB,8CAAyF;AAEzF,4CAAsD;AACtD,iEAA4D;AAG5D,MAAM,iCAAiC,GAAG,OAAC,CAAC,MAAM,CAAC;IACjD,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,6CAA6C,CAAC;CACxE,CAAC,CAAC;AAUI,IAAM,+BAA+B,GAArC,MAAM,+BAAgC,SAAQ,qBAAyC;IAEzE;IACA;IAFnB,YACmB,eAAgC,EAChC,WAA+B;QAEhD,KAAK,EAAE,CAAC;QAHS,oBAAe,GAAf,eAAe,CAAiB;QAChC,gBAAW,GAAX,WAAW,CAAoB;IAGlD,CAAC;IAGK,AAAN,KAAK,CAAC,OAAO,CAAC,MAAc,EAAE,GAA4C;QACxE,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QACxE,MAAM,QAAQ,GAAG,MAAM,CAAC,IAA6B,CAAC;QAEtD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;QAE/E,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,yBAAgB,EAAE;YAC9C,QAAQ,EAAE;gBACR,kBAAkB;gBAClB,EAAE;gBACF,cAAc,QAAQ,CAAC,KAAK,IAAI;gBAChC,mBAAmB,QAAQ,CAAC,UAAU,IAAI;gBAC1C,EAAE;gBACF,4BAA4B;gBAC5B,EAAE;gBACF,aAAa,KAAK,CAAC,IAAI,IAAI;gBAC3B,cAAc,KAAK,CAAC,KAAK,0CAA0C;gBACnE,EAAE;gBACF,kGAAkG;gBAClG,uEAAuE;aACxE,CAAC,IAAI,CAAC,IAAI,CAAC;SACb,CAAC,CAAC;IACL,CAAC;CACF,CAAA;AAhCY,0EAA+B;AASpC;IADL,IAAA,mBAAU,EAAC,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC;;;;8DAuBzB;0CA/BU,+BAA+B;IAN3C,IAAA,iBAAQ,EAAC;QACR,KAAK,EAAE,iDAAiD;QACxD,WAAW,EACT,sOAAsO;QACxO,MAAM,EAAE,iCAAiC;KAC1C,CAAC;qCAGoC,mCAAe;QACnB,0BAAkB;GAHvC,+BAA+B,CAgC3C"}
@@ -0,0 +1,19 @@
1
+ import { z } from 'zod';
2
+ import { BaseTool, ToolEnvelope } from '@loopstack/common';
3
+ declare const AnalyzeTextSchema: z.ZodObject<{
4
+ text: z.ZodString;
5
+ }, z.core.$strip>;
6
+ type AnalyzeTextArgs = z.infer<typeof AnalyzeTextSchema>;
7
+ export interface AnalyzeTextToolResult {
8
+ words: number;
9
+ characters: number;
10
+ }
11
+ export declare const AnalyzeTextToolResultSchema: z.ZodObject<{
12
+ words: z.ZodNumber;
13
+ characters: z.ZodNumber;
14
+ }, z.core.$strict>;
15
+ export declare class AnalyzeTextTool extends BaseTool<AnalyzeTextArgs, object, AnalyzeTextToolResult> {
16
+ protected handle(args: AnalyzeTextArgs): Promise<ToolEnvelope<AnalyzeTextToolResult>>;
17
+ }
18
+ export {};
19
+ //# sourceMappingURL=analyze-text.tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyze-text.tool.d.ts","sourceRoot":"","sources":["../../../../src/workflows/custom-calculator/tools/analyze-text.tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,QAAQ,EAAQ,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjE,QAAA,MAAM,iBAAiB;;iBAErB,CAAC;AAEH,KAAK,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAEzD,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,2BAA2B;;;kBAGtC,CAAC;AAEH,qBAOa,eAAgB,SAAQ,QAAQ,CAAC,eAAe,EAAE,MAAM,EAAE,qBAAqB,CAAC;cAC3E,MAAM,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,YAAY,CAAC,qBAAqB,CAAC,CAAC;CAI5F"}
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.AnalyzeTextTool = exports.AnalyzeTextToolResultSchema = void 0;
10
+ const zod_1 = require("zod");
11
+ const common_1 = require("@loopstack/common");
12
+ const AnalyzeTextSchema = zod_1.z.object({
13
+ text: zod_1.z.string(),
14
+ });
15
+ exports.AnalyzeTextToolResultSchema = zod_1.z.strictObject({
16
+ words: zod_1.z.number(),
17
+ characters: zod_1.z.number(),
18
+ });
19
+ let AnalyzeTextTool = class AnalyzeTextTool extends common_1.BaseTool {
20
+ async handle(args) {
21
+ const words = args.text.split(/\s+/).filter(Boolean).length;
22
+ return Promise.resolve({ data: { words, characters: args.text.length } });
23
+ }
24
+ };
25
+ exports.AnalyzeTextTool = AnalyzeTextTool;
26
+ exports.AnalyzeTextTool = AnalyzeTextTool = __decorate([
27
+ (0, common_1.Tool)({
28
+ name: 'analyze_text',
29
+ description: 'Counts words and characters in a text. Its usage is metered by WordsProcessedQuotaCalculator.',
30
+ schema: AnalyzeTextSchema,
31
+ resultSchema: exports.AnalyzeTextToolResultSchema,
32
+ effects: 'none',
33
+ })
34
+ ], AnalyzeTextTool);
35
+ //# sourceMappingURL=analyze-text.tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyze-text.tool.js","sourceRoot":"","sources":["../../../../src/workflows/custom-calculator/tools/analyze-text.tool.ts"],"names":[],"mappings":";;;;;;;;;AAAA,6BAAwB;AACxB,8CAAiE;AAEjE,MAAM,iBAAiB,GAAG,OAAC,CAAC,MAAM,CAAC;IACjC,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE;CACjB,CAAC,CAAC;AASU,QAAA,2BAA2B,GAAG,OAAC,CAAC,YAAY,CAAC;IACxD,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE;IACjB,UAAU,EAAE,OAAC,CAAC,MAAM,EAAE;CACvB,CAAC,CAAC;AASI,IAAM,eAAe,GAArB,MAAM,eAAgB,SAAQ,iBAAwD;IACjF,KAAK,CAAC,MAAM,CAAC,IAAqB;QAC1C,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;QAC5D,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC5E,CAAC;CACF,CAAA;AALY,0CAAe;0BAAf,eAAe;IAP3B,IAAA,aAAI,EAAC;QACJ,IAAI,EAAE,cAAc;QACpB,WAAW,EAAE,+FAA+F;QAC5G,MAAM,EAAE,iBAAiB;QACzB,YAAY,EAAE,mCAA2B;QACzC,OAAO,EAAE,MAAM;KAChB,CAAC;GACW,eAAe,CAK3B"}