@bpmnkit/casen-worker-ai 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/.turbo/turbo-build.log +4 -0
  2. package/.turbo/turbo-check.log +5 -0
  3. package/.turbo/turbo-test.log +18 -0
  4. package/.turbo/turbo-typecheck.log +4 -0
  5. package/CHANGELOG.md +7 -0
  6. package/LICENSE +21 -0
  7. package/README.md +177 -0
  8. package/dist/config.d.ts +13 -0
  9. package/dist/config.d.ts.map +1 -0
  10. package/dist/config.js +19 -0
  11. package/dist/config.js.map +1 -0
  12. package/dist/config.test.d.ts +2 -0
  13. package/dist/config.test.d.ts.map +1 -0
  14. package/dist/config.test.js +35 -0
  15. package/dist/config.test.js.map +1 -0
  16. package/dist/index.d.ts +4 -0
  17. package/dist/index.d.ts.map +1 -0
  18. package/dist/index.js +53 -0
  19. package/dist/index.js.map +1 -0
  20. package/dist/llm.d.ts +18 -0
  21. package/dist/llm.d.ts.map +1 -0
  22. package/dist/llm.js +57 -0
  23. package/dist/llm.js.map +1 -0
  24. package/dist/operations/classify.d.ts +16 -0
  25. package/dist/operations/classify.d.ts.map +1 -0
  26. package/dist/operations/classify.js +74 -0
  27. package/dist/operations/classify.js.map +1 -0
  28. package/dist/operations/classify.test.d.ts +2 -0
  29. package/dist/operations/classify.test.d.ts.map +1 -0
  30. package/dist/operations/classify.test.js +74 -0
  31. package/dist/operations/classify.test.js.map +1 -0
  32. package/dist/operations/decide.d.ts +16 -0
  33. package/dist/operations/decide.d.ts.map +1 -0
  34. package/dist/operations/decide.js +60 -0
  35. package/dist/operations/decide.js.map +1 -0
  36. package/dist/operations/decide.test.d.ts +2 -0
  37. package/dist/operations/decide.test.d.ts.map +1 -0
  38. package/dist/operations/decide.test.js +65 -0
  39. package/dist/operations/decide.test.js.map +1 -0
  40. package/dist/operations/extract.d.ts +16 -0
  41. package/dist/operations/extract.d.ts.map +1 -0
  42. package/dist/operations/extract.js +70 -0
  43. package/dist/operations/extract.js.map +1 -0
  44. package/dist/operations/extract.test.d.ts +2 -0
  45. package/dist/operations/extract.test.d.ts.map +1 -0
  46. package/dist/operations/extract.test.js +65 -0
  47. package/dist/operations/extract.test.js.map +1 -0
  48. package/dist/operations/summarize.d.ts +16 -0
  49. package/dist/operations/summarize.d.ts.map +1 -0
  50. package/dist/operations/summarize.js +59 -0
  51. package/dist/operations/summarize.js.map +1 -0
  52. package/dist/operations/summarize.test.d.ts +2 -0
  53. package/dist/operations/summarize.test.d.ts.map +1 -0
  54. package/dist/operations/summarize.test.js +42 -0
  55. package/dist/operations/summarize.test.js.map +1 -0
  56. package/package.json +69 -0
  57. package/src/config.test.ts +40 -0
  58. package/src/config.ts +27 -0
  59. package/src/index.ts +54 -0
  60. package/src/llm.ts +67 -0
  61. package/src/operations/classify.test.ts +101 -0
  62. package/src/operations/classify.ts +85 -0
  63. package/src/operations/decide.test.ts +82 -0
  64. package/src/operations/decide.ts +70 -0
  65. package/src/operations/extract.test.ts +80 -0
  66. package/src/operations/extract.ts +80 -0
  67. package/src/operations/summarize.test.ts +48 -0
  68. package/src/operations/summarize.ts +68 -0
  69. package/tsconfig.json +10 -0
  70. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,4 @@
1
+
2
+ > @bpmnkit/casen-worker-ai@0.1.0 build /home/adam/github.com/bpmnkit/monorepo/plugins-cli/casen-worker-ai
3
+ > tsc
4
+
@@ -0,0 +1,5 @@
1
+
2
+ > @bpmnkit/casen-worker-ai@0.1.0 check /home/adam/github.com/bpmnkit/monorepo/plugins-cli/casen-worker-ai
3
+ > biome check .
4
+
5
+ Checked 14 files in 13ms. No fixes applied.
@@ -0,0 +1,18 @@
1
+
2
+ > @bpmnkit/casen-worker-ai@0.1.0 test /home/adam/github.com/bpmnkit/monorepo/plugins-cli/casen-worker-ai
3
+ > vitest run
4
+
5
+
6
+ RUN v3.2.4 /home/adam/github.com/bpmnkit/monorepo/plugins-cli/casen-worker-ai
7
+
8
+ ✓ src/config.test.ts (3 tests) 11ms
9
+ ✓ src/operations/summarize.test.ts (3 tests) 11ms
10
+ ✓ src/operations/extract.test.ts (5 tests) 20ms
11
+ ✓ src/operations/classify.test.ts (7 tests) 7ms
12
+ ✓ src/operations/decide.test.ts (5 tests) 16ms
13
+
14
+ Test Files 5 passed (5)
15
+ Tests 23 passed (23)
16
+ Start at 13:49:38
17
+ Duration 1.09s (transform 1.29s, setup 0ms, collect 2.21s, tests 65ms, environment 5ms, prepare 814ms)
18
+
@@ -0,0 +1,4 @@
1
+
2
+ > @bpmnkit/casen-worker-ai@0.1.0 typecheck /home/adam/github.com/bpmnkit/monorepo/plugins-cli/casen-worker-ai
3
+ > tsc --noEmit
4
+
package/CHANGELOG.md ADDED
@@ -0,0 +1,7 @@
1
+ # @bpmnkit/casen-worker-ai
2
+
3
+ ## 0.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Initial release — AI task worker plugin supporting classify, summarize, extract, and decide operations via Claude.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 urbanisierung
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,177 @@
1
+ <div align="center">
2
+ <a href="https://bpmnkit.com"><img src="https://bpmnkit.com/favicon.svg" width="72" height="72" alt="BPMN Kit logo"></a>
3
+ <h1>@bpmnkit/casen-worker-ai</h1>
4
+ <p>AI task worker plugin for casen — classify, summarize, extract, and decide using Claude</p>
5
+
6
+ [![npm](https://img.shields.io/npm/v/@bpmnkit/casen-worker-ai?style=flat-square&color=6244d7)](https://www.npmjs.com/package/@bpmnkit/casen-worker-ai)
7
+ [![license](https://img.shields.io/npm/l/@bpmnkit/casen-worker-ai?style=flat-square)](https://github.com/bpmnkit/monorepo/blob/main/LICENSE)
8
+ [![typescript](https://img.shields.io/badge/TypeScript-strict-6244d7?style=flat-square&logo=typescript&logoColor=white)](https://github.com/bpmnkit/monorepo)
9
+
10
+ [Website](https://bpmnkit.com) · [Documentation](https://docs.bpmnkit.com) · [GitHub](https://github.com/bpmnkit/monorepo) · [Changelog](https://github.com/bpmnkit/monorepo/blob/main/plugins-cli/casen-worker-ai/CHANGELOG.md)
11
+ </div>
12
+
13
+ ---
14
+
15
+ ## Overview
16
+
17
+ `casen-worker-ai` is an official `casen` CLI plugin that brings AI-powered task processing into Camunda 8 workflows. It subscribes to four job types and uses the [Anthropic Claude API](https://anthropic.com) to complete each job with structured output.
18
+
19
+ This is the right tool when you need AI logic in a process but don't want to build a full microservice — start the worker once and any process in your cluster can delegate AI tasks to it.
20
+
21
+ ## Why a worker instead of the HTTP connector?
22
+
23
+ The built-in Camunda HTTP connector can call any API but cannot:
24
+ - Validate or parse the response and fail the job if the output is malformed
25
+ - Route Anthropic rate-limit errors (429) to Camunda's retry budget with back-off
26
+ - Throw a typed BPMN error that an error boundary event can catch
27
+
28
+ The worker handles all three via `failJob` and `throwJobError`, giving your process model clean error paths.
29
+
30
+ ## Installation
31
+
32
+ ```sh
33
+ casen plugin install casen-worker-ai
34
+ ```
35
+
36
+ Set your Anthropic API key before starting:
37
+
38
+ ```sh
39
+ export ANTHROPIC_API_KEY=sk-ant-...
40
+ casen ai-worker
41
+ ```
42
+
43
+ ## Configuration
44
+
45
+ | Environment variable | Default | Description |
46
+ |---|---|---|
47
+ | `ANTHROPIC_API_KEY` | **required** | Your Anthropic API key |
48
+ | `AI_MODEL` | `claude-3-5-haiku-20241022` | Model ID to use |
49
+ | `AI_MAX_TOKENS` | `1024` | Token budget per call |
50
+ | `AI_TIMEOUT_MS` | `60000` | HTTP timeout in ms |
51
+
52
+ ## Operations
53
+
54
+ ### `com.bpmnkit.ai.classify` — Classify text
55
+
56
+ Classifies text into one of the provided categories.
57
+
58
+ **Input variables:**
59
+
60
+ | Variable | Type | Required | Description |
61
+ |---|---|---|---|
62
+ | `input` | string | ✓ | Text to classify |
63
+ | `categories` | string[] | ✓ | Allowed category names |
64
+ | `context` | string | — | Optional domain context |
65
+
66
+ **Output variables:** `category`, `confidence` (0–1), `rationale`, `aiModel`, `processedAt`
67
+
68
+ **BPMN error codes:** `AI_INVALID_CATEGORY`, `AI_PARSE_ERROR`, `AI_API_ERROR`, `AI_INVALID_INPUT`
69
+
70
+ ```xml
71
+ <bpmn:serviceTask id="ClassifyTicket" name="Classify ticket">
72
+ <bpmn:extensionElements>
73
+ <zeebe:taskDefinition type="com.bpmnkit.ai.classify" retries="3" />
74
+ <zeebe:taskHeaders>
75
+ <zeebe:header key="retryBackoff" value="PT30S" />
76
+ </zeebe:taskHeaders>
77
+ <zeebe:ioMapping>
78
+ <zeebe:input source="=ticket.body" target="input" />
79
+ <zeebe:input source='=["billing","technical","cancellation","general"]' target="categories" />
80
+ </zeebe:ioMapping>
81
+ </bpmn:extensionElements>
82
+ </bpmn:serviceTask>
83
+ ```
84
+
85
+ ### `com.bpmnkit.ai.summarize` — Summarize text
86
+
87
+ Summarizes text to a target length and style.
88
+
89
+ **Input variables:**
90
+
91
+ | Variable | Type | Required | Description |
92
+ |---|---|---|---|
93
+ | `input` | string | ✓ | Text to summarize |
94
+ | `maxWords` | number | — | Target word count (default: 100) |
95
+ | `style` | `"bullet"` | `"paragraph"` | — | Output style (default: `"paragraph"`) |
96
+
97
+ **Output variables:** `summary`, `wordCount`, `aiModel`, `processedAt`
98
+
99
+ ### `com.bpmnkit.ai.extract` — Extract structured fields
100
+
101
+ Extracts named fields from unstructured text. Missing fields are reported but the job still completes — use a gateway on `=missingFields` to decide whether to auto-proceed or route to manual review.
102
+
103
+ **Input variables:**
104
+
105
+ | Variable | Type | Required | Description |
106
+ |---|---|---|---|
107
+ | `input` | string | ✓ | Unstructured text |
108
+ | `fields` | string[] | ✓ | Field names to extract |
109
+ | `schema` | object | — | Type hints per field, e.g. `{ amount: "number" }` |
110
+
111
+ **Output variables:** `extracted` (object), `missingFields` (array), `aiModel`, `processedAt`
112
+
113
+ ### `com.bpmnkit.ai.decide` — Make a boolean decision
114
+
115
+ Answers a yes/no question based on context and an optional policy statement. Use `confidence` at a gateway to route low-confidence decisions to human review.
116
+
117
+ **Input variables:**
118
+
119
+ | Variable | Type | Required | Description |
120
+ |---|---|---|---|
121
+ | `question` | string | ✓ | The yes/no question |
122
+ | `context` | string | ✓ | Relevant facts |
123
+ | `policy` | string | — | Natural language policy the model must apply |
124
+
125
+ **Output variables:** `decision` (boolean), `rationale`, `confidence` (0–1), `aiModel`, `processedAt`
126
+
127
+ ## Example workflow: Credit decision
128
+
129
+ ```
130
+ Start Event
131
+ → summarize (summarize application notes, maxWords=150)
132
+ → decide (question="Approve loan?", policy="Score ≥ 680 and amount ≤ 50k")
133
+ → Gateway: decision=true and confidence≥0.8 → Auto-approve
134
+ decision=false and confidence≥0.8 → Auto-deny
135
+ default → Human review
136
+ ```
137
+
138
+ ## Error handling
139
+
140
+ Add boundary events to your service tasks to handle AI failures gracefully:
141
+
142
+ - **Error boundary** catching `AI_PARSE_ERROR` → route to a manual input fallback task
143
+ - **Timer boundary** (PT5M) → escalation path if the worker is not running
144
+ - Set `retries="3"` and `retryBackoff="PT30S"` on the task definition — the worker signals Camunda to retry via `failJob` on rate limits and network timeouts
145
+
146
+ ---
147
+
148
+ ## Related Packages
149
+
150
+ | Package | Description |
151
+ |---------|-------------|
152
+ | [`@bpmnkit/core`](https://www.npmjs.com/package/@bpmnkit/core) | BPMN/DMN/Form parser, builder, layout engine |
153
+ | [`@bpmnkit/canvas`](https://www.npmjs.com/package/@bpmnkit/canvas) | Zero-dependency SVG BPMN viewer |
154
+ | [`@bpmnkit/editor`](https://www.npmjs.com/package/@bpmnkit/editor) | Full-featured interactive BPMN editor |
155
+ | [`@bpmnkit/engine`](https://www.npmjs.com/package/@bpmnkit/engine) | Lightweight BPMN process execution engine |
156
+ | [`@bpmnkit/feel`](https://www.npmjs.com/package/@bpmnkit/feel) | FEEL expression language parser & evaluator |
157
+ | [`@bpmnkit/plugins`](https://www.npmjs.com/package/@bpmnkit/plugins) | 22 composable canvas plugins |
158
+ | [`@bpmnkit/api`](https://www.npmjs.com/package/@bpmnkit/api) | Camunda 8 REST API TypeScript client |
159
+ | [`@bpmnkit/ascii`](https://www.npmjs.com/package/@bpmnkit/ascii) | Render BPMN diagrams as Unicode ASCII art |
160
+ | [`@bpmnkit/ui`](https://www.npmjs.com/package/@bpmnkit/ui) | Shared design tokens and UI components |
161
+ | [`@bpmnkit/profiles`](https://www.npmjs.com/package/@bpmnkit/profiles) | Shared auth, profile storage, and client factories for CLI & proxy |
162
+ | [`@bpmnkit/operate`](https://www.npmjs.com/package/@bpmnkit/operate) | Monitoring & operations frontend for Camunda clusters |
163
+ | [`@bpmnkit/connector-gen`](https://www.npmjs.com/package/@bpmnkit/connector-gen) | Generate connector templates from OpenAPI specs |
164
+ | [`@bpmnkit/cli`](https://www.npmjs.com/package/@bpmnkit/cli) | Camunda 8 command-line interface (casen) |
165
+ | [`@bpmnkit/proxy`](https://www.npmjs.com/package/@bpmnkit/proxy) | Local AI bridge and Camunda API proxy server |
166
+ | [`@bpmnkit/cli-sdk`](https://www.npmjs.com/package/@bpmnkit/cli-sdk) | Plugin authoring SDK for the casen CLI |
167
+ | [`@bpmnkit/create-casen-plugin`](https://www.npmjs.com/package/@bpmnkit/create-casen-plugin) | Scaffold a new casen CLI plugin in seconds |
168
+ | [`@bpmnkit/casen-report`](https://www.npmjs.com/package/@bpmnkit/casen-report) | HTML reports from Camunda 8 incident and SLA data |
169
+ | [`@bpmnkit/casen-worker-http`](https://www.npmjs.com/package/@bpmnkit/casen-worker-http) | Example HTTP worker plugin — completes jobs with live JSONPlaceholder API data |
170
+
171
+ ## License
172
+
173
+ [MIT](https://github.com/bpmnkit/monorepo/blob/main/LICENSE) © BPMN Kit — made by [u11g](https://u11g.com)
174
+
175
+ <div align="center">
176
+ <a href="https://bpmnkit.com"><img src="https://bpmnkit.com/favicon.svg" width="32" height="32" alt="BPMN Kit"></a>
177
+ </div>
@@ -0,0 +1,13 @@
1
+ export interface AiWorkerConfig {
2
+ apiKey: string;
3
+ model: string;
4
+ maxTokens: number;
5
+ timeoutMs: number;
6
+ }
7
+ /**
8
+ * Resolves config from environment variables.
9
+ * Throws immediately if ANTHROPIC_API_KEY is absent so the error surfaces at
10
+ * worker startup rather than mid-job.
11
+ */
12
+ export declare function resolveConfig(): AiWorkerConfig;
13
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC9B,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;CACjB;AAED;;;;GAIG;AACH,wBAAgB,aAAa,IAAI,cAAc,CAc9C"}
package/dist/config.js ADDED
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Resolves config from environment variables.
3
+ * Throws immediately if ANTHROPIC_API_KEY is absent so the error surfaces at
4
+ * worker startup rather than mid-job.
5
+ */
6
+ export function resolveConfig() {
7
+ const apiKey = process.env.ANTHROPIC_API_KEY;
8
+ if (!apiKey) {
9
+ throw new Error("ANTHROPIC_API_KEY is not set. Export it before starting the AI worker:\n" +
10
+ " export ANTHROPIC_API_KEY=sk-ant-...");
11
+ }
12
+ return {
13
+ apiKey,
14
+ model: process.env.AI_MODEL ?? "claude-3-5-haiku-20241022",
15
+ maxTokens: Number(process.env.AI_MAX_TOKENS ?? "1024"),
16
+ timeoutMs: Number(process.env.AI_TIMEOUT_MS ?? "60000"),
17
+ };
18
+ }
19
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAOA;;;;GAIG;AACH,MAAM,UAAU,aAAa;IAC5B,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAA;IAC5C,IAAI,CAAC,MAAM,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACd,0EAA0E;YACzE,uCAAuC,CACxC,CAAA;IACF,CAAC;IACD,OAAO;QACN,MAAM;QACN,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,2BAA2B;QAC1D,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,MAAM,CAAC;QACtD,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,OAAO,CAAC;KACvD,CAAA;AACF,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=config.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.test.d.ts","sourceRoot":"","sources":["../src/config.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,35 @@
1
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
2
+ import { resolveConfig } from "./config.js";
3
+ describe("resolveConfig", () => {
4
+ const original = { ...process.env };
5
+ beforeEach(() => {
6
+ for (const key of ["ANTHROPIC_API_KEY", "AI_MODEL", "AI_MAX_TOKENS", "AI_TIMEOUT_MS"]) {
7
+ Reflect.deleteProperty(process.env, key);
8
+ }
9
+ });
10
+ afterEach(() => {
11
+ Object.assign(process.env, original);
12
+ });
13
+ it("throws when ANTHROPIC_API_KEY is not set", () => {
14
+ expect(() => resolveConfig()).toThrow("ANTHROPIC_API_KEY");
15
+ });
16
+ it("returns defaults when only API key is set", () => {
17
+ process.env.ANTHROPIC_API_KEY = "sk-test";
18
+ const cfg = resolveConfig();
19
+ expect(cfg.apiKey).toBe("sk-test");
20
+ expect(cfg.model).toBe("claude-3-5-haiku-20241022");
21
+ expect(cfg.maxTokens).toBe(1024);
22
+ expect(cfg.timeoutMs).toBe(60000);
23
+ });
24
+ it("overrides defaults from env vars", () => {
25
+ process.env.ANTHROPIC_API_KEY = "sk-test";
26
+ process.env.AI_MODEL = "claude-opus-4-6";
27
+ process.env.AI_MAX_TOKENS = "2048";
28
+ process.env.AI_TIMEOUT_MS = "30000";
29
+ const cfg = resolveConfig();
30
+ expect(cfg.model).toBe("claude-opus-4-6");
31
+ expect(cfg.maxTokens).toBe(2048);
32
+ expect(cfg.timeoutMs).toBe(30000);
33
+ });
34
+ });
35
+ //# sourceMappingURL=config.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.test.js","sourceRoot":"","sources":["../src/config.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AACpE,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAE3C,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC9B,MAAM,QAAQ,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,CAAA;IAEnC,UAAU,CAAC,GAAG,EAAE;QACf,KAAK,MAAM,GAAG,IAAI,CAAC,mBAAmB,EAAE,UAAU,EAAE,eAAe,EAAE,eAAe,CAAC,EAAE,CAAC;YACvF,OAAO,CAAC,cAAc,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;QACzC,CAAC;IACF,CAAC,CAAC,CAAA;IAEF,SAAS,CAAC,GAAG,EAAE;QACd,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAA;IACrC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QACnD,MAAM,CAAC,GAAG,EAAE,CAAC,aAAa,EAAE,CAAC,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAA;IAC3D,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACpD,OAAO,CAAC,GAAG,CAAC,iBAAiB,GAAG,SAAS,CAAA;QACzC,MAAM,GAAG,GAAG,aAAa,EAAE,CAAA;QAC3B,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QAClC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAA;QACnD,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAChC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAClC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC3C,OAAO,CAAC,GAAG,CAAC,iBAAiB,GAAG,SAAS,CAAA;QACzC,OAAO,CAAC,GAAG,CAAC,QAAQ,GAAG,iBAAiB,CAAA;QACxC,OAAO,CAAC,GAAG,CAAC,aAAa,GAAG,MAAM,CAAA;QAClC,OAAO,CAAC,GAAG,CAAC,aAAa,GAAG,OAAO,CAAA;QACnC,MAAM,GAAG,GAAG,aAAa,EAAE,CAAA;QAC3B,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAA;QACzC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAChC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAClC,CAAC,CAAC,CAAA;AACH,CAAC,CAAC,CAAA"}
@@ -0,0 +1,4 @@
1
+ import { type CasenPlugin } from "@bpmnkit/cli-sdk";
2
+ declare const plugin: CasenPlugin;
3
+ export default plugin;
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,WAAW,EAAuB,MAAM,kBAAkB,CAAA;AAOxE,QAAA,MAAM,MAAM,EAAE,WA4Cb,CAAA;AAED,eAAe,MAAM,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,53 @@
1
+ import { createWorkerCommand } from "@bpmnkit/cli-sdk";
2
+ import { resolveConfig } from "./config.js";
3
+ import { classify } from "./operations/classify.js";
4
+ import { decide } from "./operations/decide.js";
5
+ import { extract } from "./operations/extract.js";
6
+ import { summarize } from "./operations/summarize.js";
7
+ const plugin = {
8
+ id: "com.bpmnkit.casen-worker-ai",
9
+ name: "AI Worker",
10
+ version: "0.1.0",
11
+ groups: [
12
+ {
13
+ name: "ai-worker",
14
+ description: "AI-powered job workers — classify, summarize, extract, decide",
15
+ commands: [
16
+ createWorkerCommand({
17
+ jobType: "com.bpmnkit.ai.classify",
18
+ description: "Classify text into one of the given categories",
19
+ defaultVariables: { category: "unknown", confidence: 0, rationale: "no handler" },
20
+ async processJob(job) {
21
+ return classify(job, resolveConfig());
22
+ },
23
+ }),
24
+ createWorkerCommand({
25
+ jobType: "com.bpmnkit.ai.summarize",
26
+ description: "Summarize text to a given length and style",
27
+ defaultVariables: { summary: "", wordCount: 0 },
28
+ async processJob(job) {
29
+ return summarize(job, resolveConfig());
30
+ },
31
+ }),
32
+ createWorkerCommand({
33
+ jobType: "com.bpmnkit.ai.extract",
34
+ description: "Extract structured fields from unstructured text",
35
+ defaultVariables: { extracted: {}, missingFields: [] },
36
+ async processJob(job) {
37
+ return extract(job, resolveConfig());
38
+ },
39
+ }),
40
+ createWorkerCommand({
41
+ jobType: "com.bpmnkit.ai.decide",
42
+ description: "Make a boolean decision based on a question, context, and optional policy",
43
+ defaultVariables: { decision: false, rationale: "", confidence: 0 },
44
+ async processJob(job) {
45
+ return decide(job, resolveConfig());
46
+ },
47
+ }),
48
+ ],
49
+ },
50
+ ],
51
+ };
52
+ export default plugin;
53
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AACxE,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAA;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAA;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAA;AAErD,MAAM,MAAM,GAAgB;IAC3B,EAAE,EAAE,6BAA6B;IACjC,IAAI,EAAE,WAAW;IACjB,OAAO,EAAE,OAAO;IAChB,MAAM,EAAE;QACP;YACC,IAAI,EAAE,WAAW;YACjB,WAAW,EAAE,+DAA+D;YAC5E,QAAQ,EAAE;gBACT,mBAAmB,CAAC;oBACnB,OAAO,EAAE,yBAAyB;oBAClC,WAAW,EAAE,gDAAgD;oBAC7D,gBAAgB,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC,EAAE,SAAS,EAAE,YAAY,EAAE;oBACjF,KAAK,CAAC,UAAU,CAAC,GAAG;wBACnB,OAAO,QAAQ,CAAC,GAAG,EAAE,aAAa,EAAE,CAAC,CAAA;oBACtC,CAAC;iBACD,CAAC;gBACF,mBAAmB,CAAC;oBACnB,OAAO,EAAE,0BAA0B;oBACnC,WAAW,EAAE,4CAA4C;oBACzD,gBAAgB,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,EAAE;oBAC/C,KAAK,CAAC,UAAU,CAAC,GAAG;wBACnB,OAAO,SAAS,CAAC,GAAG,EAAE,aAAa,EAAE,CAAC,CAAA;oBACvC,CAAC;iBACD,CAAC;gBACF,mBAAmB,CAAC;oBACnB,OAAO,EAAE,wBAAwB;oBACjC,WAAW,EAAE,kDAAkD;oBAC/D,gBAAgB,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,aAAa,EAAE,EAAE,EAAE;oBACtD,KAAK,CAAC,UAAU,CAAC,GAAG;wBACnB,OAAO,OAAO,CAAC,GAAG,EAAE,aAAa,EAAE,CAAC,CAAA;oBACrC,CAAC;iBACD,CAAC;gBACF,mBAAmB,CAAC;oBACnB,OAAO,EAAE,uBAAuB;oBAChC,WAAW,EAAE,2EAA2E;oBACxF,gBAAgB,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE;oBACnE,KAAK,CAAC,UAAU,CAAC,GAAG;wBACnB,OAAO,MAAM,CAAC,GAAG,EAAE,aAAa,EAAE,CAAC,CAAA;oBACpC,CAAC;iBACD,CAAC;aACF;SACD;KACD;CACD,CAAA;AAED,eAAe,MAAM,CAAA"}
package/dist/llm.d.ts ADDED
@@ -0,0 +1,18 @@
1
+ import type { AiWorkerConfig } from "./config.js";
2
+ export declare class RetryableError extends Error {
3
+ constructor(message: string);
4
+ }
5
+ /**
6
+ * Calls the Anthropic messages API and returns the text content.
7
+ *
8
+ * Throws {@link RetryableError} for transient failures (rate limits, timeouts,
9
+ * 5xx errors) so callers can return `{ outcome: "fail" }` and let Camunda retry.
10
+ * Throws a plain Error for hard failures (auth, invalid request).
11
+ */
12
+ export declare function callLlm(systemPrompt: string, userMessage: string, config: AiWorkerConfig): Promise<string>;
13
+ /**
14
+ * Parses an LLM response as JSON. Handles responses wrapped in a markdown
15
+ * code fence (```json ... ```) which models sometimes emit.
16
+ */
17
+ export declare function parseJsonResponse<T>(text: string): T;
18
+ //# sourceMappingURL=llm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm.d.ts","sourceRoot":"","sources":["../src/llm.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAEjD,qBAAa,cAAe,SAAQ,KAAK;gBAC5B,OAAO,EAAE,MAAM;CAI3B;AAED;;;;;;GAMG;AACH,wBAAsB,OAAO,CAC5B,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,cAAc,GACpB,OAAO,CAAC,MAAM,CAAC,CAiCjB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC,CAMpD"}
package/dist/llm.js ADDED
@@ -0,0 +1,57 @@
1
+ import Anthropic from "@anthropic-ai/sdk";
2
+ export class RetryableError extends Error {
3
+ constructor(message) {
4
+ super(message);
5
+ this.name = "RetryableError";
6
+ }
7
+ }
8
+ /**
9
+ * Calls the Anthropic messages API and returns the text content.
10
+ *
11
+ * Throws {@link RetryableError} for transient failures (rate limits, timeouts,
12
+ * 5xx errors) so callers can return `{ outcome: "fail" }` and let Camunda retry.
13
+ * Throws a plain Error for hard failures (auth, invalid request).
14
+ */
15
+ export async function callLlm(systemPrompt, userMessage, config) {
16
+ const client = new Anthropic({
17
+ apiKey: config.apiKey,
18
+ timeout: config.timeoutMs,
19
+ maxRetries: 0, // we let Camunda handle retries via failJob
20
+ });
21
+ let message;
22
+ try {
23
+ message = await client.messages.create({
24
+ model: config.model,
25
+ max_tokens: config.maxTokens,
26
+ system: systemPrompt,
27
+ messages: [{ role: "user", content: userMessage }],
28
+ });
29
+ }
30
+ catch (err) {
31
+ if (err instanceof Anthropic.RateLimitError ||
32
+ err instanceof Anthropic.APIConnectionTimeoutError) {
33
+ throw new RetryableError(err.message);
34
+ }
35
+ if (err instanceof Anthropic.InternalServerError) {
36
+ throw new RetryableError(err.message);
37
+ }
38
+ throw err;
39
+ }
40
+ const block = message.content[0];
41
+ if (!block || block.type !== "text") {
42
+ throw new Error("Unexpected response shape from Anthropic API");
43
+ }
44
+ return block.text;
45
+ }
46
+ /**
47
+ * Parses an LLM response as JSON. Handles responses wrapped in a markdown
48
+ * code fence (```json ... ```) which models sometimes emit.
49
+ */
50
+ export function parseJsonResponse(text) {
51
+ const stripped = text
52
+ .replace(/^```(?:json)?\s*/i, "")
53
+ .replace(/\s*```\s*$/, "")
54
+ .trim();
55
+ return JSON.parse(stripped);
56
+ }
57
+ //# sourceMappingURL=llm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm.js","sourceRoot":"","sources":["../src/llm.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,mBAAmB,CAAA;AAGzC,MAAM,OAAO,cAAe,SAAQ,KAAK;IACxC,YAAY,OAAe;QAC1B,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAA;IAC7B,CAAC;CACD;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAC5B,YAAoB,EACpB,WAAmB,EACnB,MAAsB;IAEtB,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC5B,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,OAAO,EAAE,MAAM,CAAC,SAAS;QACzB,UAAU,EAAE,CAAC,EAAE,4CAA4C;KAC3D,CAAC,CAAA;IAEF,IAAI,OAA0B,CAAA;IAC9B,IAAI,CAAC;QACJ,OAAO,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;YACtC,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,UAAU,EAAE,MAAM,CAAC,SAAS;YAC5B,MAAM,EAAE,YAAY;YACpB,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC;SAClD,CAAC,CAAA;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACd,IACC,GAAG,YAAY,SAAS,CAAC,cAAc;YACvC,GAAG,YAAY,SAAS,CAAC,yBAAyB,EACjD,CAAC;YACF,MAAM,IAAI,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;QACtC,CAAC;QACD,IAAI,GAAG,YAAY,SAAS,CAAC,mBAAmB,EAAE,CAAC;YAClD,MAAM,IAAI,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;QACtC,CAAC;QACD,MAAM,GAAG,CAAA;IACV,CAAC;IAED,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;IAChC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QACrC,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAA;IAChE,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAA;AAClB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAI,IAAY;IAChD,MAAM,QAAQ,GAAG,IAAI;SACnB,OAAO,CAAC,mBAAmB,EAAE,EAAE,CAAC;SAChC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC;SACzB,IAAI,EAAE,CAAA;IACR,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAM,CAAA;AACjC,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { WorkerJob, WorkerJobResult } from "@bpmnkit/cli-sdk";
2
+ import type { AiWorkerConfig } from "../config.js";
3
+ /**
4
+ * Classifies job.variables.input into one of job.variables.categories.
5
+ *
6
+ * Required job variables:
7
+ * - input: string — the text to classify
8
+ * - categories: string[] — allowed category names
9
+ *
10
+ * Optional:
11
+ * - context: string — additional domain context for the model
12
+ *
13
+ * Output variables: category, confidence, rationale, aiModel, processedAt
14
+ */
15
+ export declare function classify(job: WorkerJob, config: AiWorkerConfig): Promise<WorkerJobResult>;
16
+ //# sourceMappingURL=classify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"classify.d.ts","sourceRoot":"","sources":["../../src/operations/classify.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAClE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAelD;;;;;;;;;;;GAWG;AACH,wBAAsB,QAAQ,CAAC,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC,CAwD/F"}
@@ -0,0 +1,74 @@
1
+ import { RetryableError, callLlm, parseJsonResponse } from "../llm.js";
2
+ const SYSTEM_PROMPT = `You are a text classification assistant.
3
+ The user will provide text to classify and a list of allowed categories.
4
+ Respond ONLY with valid JSON matching this exact shape:
5
+ { "category": "<one of the allowed categories>", "confidence": <0.0–1.0>, "rationale": "<one sentence>" }
6
+ Do not include any prose outside the JSON object.`;
7
+ /**
8
+ * Classifies job.variables.input into one of job.variables.categories.
9
+ *
10
+ * Required job variables:
11
+ * - input: string — the text to classify
12
+ * - categories: string[] — allowed category names
13
+ *
14
+ * Optional:
15
+ * - context: string — additional domain context for the model
16
+ *
17
+ * Output variables: category, confidence, rationale, aiModel, processedAt
18
+ */
19
+ export async function classify(job, config) {
20
+ const input = String(job.variables.input ?? "");
21
+ const categories = job.variables.categories;
22
+ if (!Array.isArray(categories) || categories.length === 0) {
23
+ return {
24
+ outcome: "error",
25
+ errorCode: "AI_INVALID_INPUT",
26
+ errorMessage: 'Job variable "categories" must be a non-empty array of strings.',
27
+ };
28
+ }
29
+ const context = job.variables.context ? `\nContext: ${String(job.variables.context)}` : "";
30
+ const userMessage = `Allowed categories: ${JSON.stringify(categories)}${context}\n\nText to classify:\n${input}`;
31
+ let raw;
32
+ try {
33
+ raw = await callLlm(SYSTEM_PROMPT, userMessage, config);
34
+ }
35
+ catch (err) {
36
+ if (err instanceof RetryableError) {
37
+ return { outcome: "fail", errorMessage: err.message, retries: 2, retryBackOff: 30_000 };
38
+ }
39
+ return {
40
+ outcome: "error",
41
+ errorCode: "AI_API_ERROR",
42
+ errorMessage: err instanceof Error ? err.message : String(err),
43
+ };
44
+ }
45
+ let parsed;
46
+ try {
47
+ parsed = parseJsonResponse(raw);
48
+ }
49
+ catch {
50
+ return {
51
+ outcome: "error",
52
+ errorCode: "AI_PARSE_ERROR",
53
+ errorMessage: `Model returned non-JSON response: ${raw.slice(0, 200)}`,
54
+ };
55
+ }
56
+ if (!categories.includes(parsed.category)) {
57
+ return {
58
+ outcome: "error",
59
+ errorCode: "AI_INVALID_CATEGORY",
60
+ errorMessage: `Model returned category "${parsed.category}" which is not in the allowed list: ${JSON.stringify(categories)}`,
61
+ };
62
+ }
63
+ return {
64
+ outcome: "complete",
65
+ variables: {
66
+ category: parsed.category,
67
+ confidence: parsed.confidence,
68
+ rationale: parsed.rationale,
69
+ aiModel: config.model,
70
+ processedAt: new Date().toISOString(),
71
+ },
72
+ };
73
+ }
74
+ //# sourceMappingURL=classify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"classify.js","sourceRoot":"","sources":["../../src/operations/classify.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAQtE,MAAM,aAAa,GAAG;;;;kDAI4B,CAAA;AAElD;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,GAAc,EAAE,MAAsB;IACpE,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,IAAI,EAAE,CAAC,CAAA;IAC/C,MAAM,UAAU,GAAG,GAAG,CAAC,SAAS,CAAC,UAAU,CAAA;IAC3C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3D,OAAO;YACN,OAAO,EAAE,OAAO;YAChB,SAAS,EAAE,kBAAkB;YAC7B,YAAY,EAAE,iEAAiE;SAC/E,CAAA;IACF,CAAC;IACD,MAAM,OAAO,GAAG,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,cAAc,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;IAC1F,MAAM,WAAW,GAAG,uBAAuB,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG,OAAO,0BAA0B,KAAK,EAAE,CAAA;IAEhH,IAAI,GAAW,CAAA;IACf,IAAI,CAAC;QACJ,GAAG,GAAG,MAAM,OAAO,CAAC,aAAa,EAAE,WAAW,EAAE,MAAM,CAAC,CAAA;IACxD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACd,IAAI,GAAG,YAAY,cAAc,EAAE,CAAC;YACnC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,YAAY,EAAE,MAAM,EAAE,CAAA;QACxF,CAAC;QACD,OAAO;YACN,OAAO,EAAE,OAAO;YAChB,SAAS,EAAE,cAAc;YACzB,YAAY,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;SAC9D,CAAA;IACF,CAAC;IAED,IAAI,MAAwB,CAAA;IAC5B,IAAI,CAAC;QACJ,MAAM,GAAG,iBAAiB,CAAmB,GAAG,CAAC,CAAA;IAClD,CAAC;IAAC,MAAM,CAAC;QACR,OAAO;YACN,OAAO,EAAE,OAAO;YAChB,SAAS,EAAE,gBAAgB;YAC3B,YAAY,EAAE,qCAAqC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;SACtE,CAAA;IACF,CAAC;IAED,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC3C,OAAO;YACN,OAAO,EAAE,OAAO;YAChB,SAAS,EAAE,qBAAqB;YAChC,YAAY,EAAE,4BAA4B,MAAM,CAAC,QAAQ,uCAAuC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE;SAC5H,CAAA;IACF,CAAC;IAED,OAAO;QACN,OAAO,EAAE,UAAU;QACnB,SAAS,EAAE;YACV,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,UAAU,EAAE,MAAM,CAAC,UAAU;YAC7B,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,OAAO,EAAE,MAAM,CAAC,KAAK;YACrB,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACrC;KACD,CAAA;AACF,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=classify.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"classify.test.d.ts","sourceRoot":"","sources":["../../src/operations/classify.test.ts"],"names":[],"mappings":""}