@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.
- package/README.md +60 -6
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -1
- package/dist/observability-examples.module.d.ts +6 -1
- package/dist/observability-examples.module.d.ts.map +1 -1
- package/dist/observability-examples.module.js +36 -4
- package/dist/observability-examples.module.js.map +1 -1
- package/dist/workflows/audit-log/audit-log-example.workflow.d.ts +10 -0
- package/dist/workflows/audit-log/audit-log-example.workflow.d.ts.map +1 -0
- package/dist/workflows/audit-log/audit-log-example.workflow.js +66 -0
- package/dist/workflows/audit-log/audit-log-example.workflow.js.map +1 -0
- package/dist/workflows/audit-log/listeners/audit.listener.d.ts +9 -0
- package/dist/workflows/audit-log/listeners/audit.listener.d.ts.map +1 -0
- package/dist/workflows/audit-log/listeners/audit.listener.js +44 -0
- package/dist/workflows/audit-log/listeners/audit.listener.js.map +1 -0
- package/dist/workflows/audit-log/services/audit-log.service.d.ts +11 -0
- package/dist/workflows/audit-log/services/audit-log.service.d.ts.map +1 -0
- package/dist/workflows/audit-log/services/audit-log.service.js +28 -0
- package/dist/workflows/audit-log/services/audit-log.service.js.map +1 -0
- package/dist/workflows/custom-calculator/calculators/words-processed.calculator.d.ts +7 -0
- package/dist/workflows/custom-calculator/calculators/words-processed.calculator.d.ts.map +1 -0
- package/dist/workflows/custom-calculator/calculators/words-processed.calculator.js +15 -0
- package/dist/workflows/custom-calculator/calculators/words-processed.calculator.js.map +1 -0
- package/dist/workflows/custom-calculator/custom-calculator-example.workflow.d.ts +17 -0
- package/dist/workflows/custom-calculator/custom-calculator-example.workflow.d.ts.map +1 -0
- package/dist/workflows/custom-calculator/custom-calculator-example.workflow.js +66 -0
- package/dist/workflows/custom-calculator/custom-calculator-example.workflow.js.map +1 -0
- package/dist/workflows/custom-calculator/tools/analyze-text.tool.d.ts +19 -0
- package/dist/workflows/custom-calculator/tools/analyze-text.tool.d.ts.map +1 -0
- package/dist/workflows/custom-calculator/tools/analyze-text.tool.js +35 -0
- package/dist/workflows/custom-calculator/tools/analyze-text.tool.js.map +1 -0
- package/dist/workflows/quota/quota-example.workflow.js +1 -1
- package/dist/workflows/quota/quota-example.workflow.js.map +1 -1
- package/dist/workflows/tracing/interceptors/tracing.interceptor.d.ts +10 -0
- package/dist/workflows/tracing/interceptors/tracing.interceptor.d.ts.map +1 -0
- package/dist/workflows/tracing/interceptors/tracing.interceptor.js +48 -0
- package/dist/workflows/tracing/interceptors/tracing.interceptor.js.map +1 -0
- package/dist/workflows/tracing/services/tool-trace.service.d.ts +12 -0
- package/dist/workflows/tracing/services/tool-trace.service.d.ts.map +1 -0
- package/dist/workflows/tracing/services/tool-trace.service.js +28 -0
- package/dist/workflows/tracing/services/tool-trace.service.js.map +1 -0
- package/dist/workflows/tracing/tools/simulate-work.tool.d.ts +20 -0
- package/dist/workflows/tracing/tools/simulate-work.tool.d.ts.map +1 -0
- package/dist/workflows/tracing/tools/simulate-work.tool.js +36 -0
- package/dist/workflows/tracing/tools/simulate-work.tool.js.map +1 -0
- package/dist/workflows/tracing/tracing-example.workflow.d.ts +17 -0
- package/dist/workflows/tracing/tracing-example.workflow.d.ts.map +1 -0
- package/dist/workflows/tracing/tracing-example.workflow.js +62 -0
- package/dist/workflows/tracing/tracing-example.workflow.js.map +1 -0
- package/package.json +4 -2
- package/src/index.ts +10 -0
- package/src/observability-examples.module.ts +33 -6
- package/src/workflows/audit-log/audit-log-example.workflow.ts +43 -0
- package/src/workflows/audit-log/listeners/audit.listener.ts +22 -0
- package/src/workflows/audit-log/services/audit-log.service.ts +25 -0
- package/src/workflows/custom-calculator/__tests__/custom-calculator-example.spec.ts +27 -0
- package/src/workflows/custom-calculator/calculators/words-processed.calculator.ts +15 -0
- package/src/workflows/custom-calculator/custom-calculator-example.workflow.ts +52 -0
- package/src/workflows/custom-calculator/tools/analyze-text.tool.ts +32 -0
- package/src/workflows/quota/quota-example.workflow.ts +1 -1
- package/src/workflows/tracing/interceptors/tracing.interceptor.ts +31 -0
- package/src/workflows/tracing/services/tool-trace.service.ts +26 -0
- package/src/workflows/tracing/tools/simulate-work.tool.ts +33 -0
- 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 —
|
|
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
|
|
44
|
-
|
|
|
45
|
-
| [Quota](#quota)
|
|
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
|
|
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
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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
|
-
|
|
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":"
|
|
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: [
|
|
25
|
-
|
|
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":"
|
|
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"}
|