callman-core 1.28.0 → 1.28.1

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 (98) hide show
  1. package/ai-packs/scenario-nodes.md +451 -0
  2. package/dist/ai/index.d.ts +1 -0
  3. package/dist/ai/index.d.ts.map +1 -1
  4. package/dist/ai/index.js +1 -0
  5. package/dist/ai/index.js.map +1 -1
  6. package/dist/ai/prompts/scenario.d.ts.map +1 -1
  7. package/dist/ai/prompts/scenario.js +9 -8
  8. package/dist/ai/prompts/scenario.js.map +1 -1
  9. package/dist/ai/prompts/scenarioNodeReference.d.ts +16 -0
  10. package/dist/ai/prompts/scenarioNodeReference.d.ts.map +1 -0
  11. package/dist/ai/prompts/scenarioNodeReference.js +882 -0
  12. package/dist/ai/prompts/scenarioNodeReference.js.map +1 -0
  13. package/dist/http-file/flatImport.d.ts +1 -0
  14. package/dist/http-file/flatImport.d.ts.map +1 -1
  15. package/dist/http-file/flatImport.js.map +1 -1
  16. package/dist/http-file/index.d.ts +1 -1
  17. package/dist/http-file/index.d.ts.map +1 -1
  18. package/dist/http-file/index.js +1 -1
  19. package/dist/http-file/index.js.map +1 -1
  20. package/dist/http-file/parseHttpFile.d.ts +1 -0
  21. package/dist/http-file/parseHttpFile.d.ts.map +1 -1
  22. package/dist/http-file/parseHttpFile.js +40 -8
  23. package/dist/http-file/parseHttpFile.js.map +1 -1
  24. package/dist/index.d.ts +1 -0
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +3 -0
  27. package/dist/index.js.map +1 -1
  28. package/dist/request/requestBody.d.ts +55 -0
  29. package/dist/request/requestBody.d.ts.map +1 -0
  30. package/dist/request/requestBody.js +198 -0
  31. package/dist/request/requestBody.js.map +1 -0
  32. package/dist/runner/requestRunner.d.ts.map +1 -1
  33. package/dist/runner/requestRunner.js +127 -43
  34. package/dist/runner/requestRunner.js.map +1 -1
  35. package/dist/runner/runCollection.d.ts +1 -1
  36. package/dist/runner/runCollection.d.ts.map +1 -1
  37. package/dist/runner/runCollection.js +9 -2
  38. package/dist/runner/runCollection.js.map +1 -1
  39. package/dist/scenario-runner/adapters/helpers/request-helpers.d.ts +2 -1
  40. package/dist/scenario-runner/adapters/helpers/request-helpers.d.ts.map +1 -1
  41. package/dist/scenario-runner/adapters/helpers/request-helpers.js +8 -40
  42. package/dist/scenario-runner/adapters/helpers/request-helpers.js.map +1 -1
  43. package/dist/scenario-runner/adapters/request-executor.d.ts.map +1 -1
  44. package/dist/scenario-runner/adapters/request-executor.js +2 -29
  45. package/dist/scenario-runner/adapters/request-executor.js.map +1 -1
  46. package/dist/scenario-runner/index.d.ts +1 -0
  47. package/dist/scenario-runner/index.d.ts.map +1 -1
  48. package/dist/scenario-runner/index.js +1 -0
  49. package/dist/scenario-runner/index.js.map +1 -1
  50. package/dist/scenario-runner/labels.d.ts +3 -0
  51. package/dist/scenario-runner/labels.d.ts.map +1 -0
  52. package/dist/scenario-runner/labels.js +20 -0
  53. package/dist/scenario-runner/labels.js.map +1 -0
  54. package/dist/scenario-runner/runScenario.d.ts.map +1 -1
  55. package/dist/scenario-runner/runScenario.js +4 -11
  56. package/dist/scenario-runner/runScenario.js.map +1 -1
  57. package/dist/script/legacy.d.ts.map +1 -1
  58. package/dist/script/legacy.js +24 -9
  59. package/dist/script/legacy.js.map +1 -1
  60. package/dist/types/index.d.ts +18 -1
  61. package/dist/types/index.d.ts.map +1 -1
  62. package/dist/variables/resolver.d.ts.map +1 -1
  63. package/dist/variables/resolver.js +27 -5
  64. package/dist/variables/resolver.js.map +1 -1
  65. package/dist-cjs/ai/index.js +4 -1
  66. package/dist-cjs/ai/index.js.map +1 -1
  67. package/dist-cjs/ai/prompts/scenario.js +9 -8
  68. package/dist-cjs/ai/prompts/scenario.js.map +1 -1
  69. package/dist-cjs/ai/prompts/scenarioNodeReference.js +886 -0
  70. package/dist-cjs/ai/prompts/scenarioNodeReference.js.map +1 -0
  71. package/dist-cjs/http-file/flatImport.js.map +1 -1
  72. package/dist-cjs/http-file/index.js +2 -1
  73. package/dist-cjs/http-file/index.js.map +1 -1
  74. package/dist-cjs/http-file/parseHttpFile.js +42 -9
  75. package/dist-cjs/http-file/parseHttpFile.js.map +1 -1
  76. package/dist-cjs/index.js +9 -1
  77. package/dist-cjs/index.js.map +1 -1
  78. package/dist-cjs/request/requestBody.js +206 -0
  79. package/dist-cjs/request/requestBody.js.map +1 -0
  80. package/dist-cjs/runner/requestRunner.js +127 -43
  81. package/dist-cjs/runner/requestRunner.js.map +1 -1
  82. package/dist-cjs/runner/runCollection.js +9 -2
  83. package/dist-cjs/runner/runCollection.js.map +1 -1
  84. package/dist-cjs/scenario-runner/adapters/helpers/request-helpers.js +7 -42
  85. package/dist-cjs/scenario-runner/adapters/helpers/request-helpers.js.map +1 -1
  86. package/dist-cjs/scenario-runner/adapters/request-executor.js +3 -30
  87. package/dist-cjs/scenario-runner/adapters/request-executor.js.map +1 -1
  88. package/dist-cjs/scenario-runner/index.js +4 -1
  89. package/dist-cjs/scenario-runner/index.js.map +1 -1
  90. package/dist-cjs/scenario-runner/labels.js +24 -0
  91. package/dist-cjs/scenario-runner/labels.js.map +1 -0
  92. package/dist-cjs/scenario-runner/runScenario.js +4 -11
  93. package/dist-cjs/scenario-runner/runScenario.js.map +1 -1
  94. package/dist-cjs/script/legacy.js +24 -9
  95. package/dist-cjs/script/legacy.js.map +1 -1
  96. package/dist-cjs/variables/resolver.js +27 -5
  97. package/dist-cjs/variables/resolver.js.map +1 -1
  98. package/package.json +1 -1
@@ -0,0 +1,451 @@
1
+ <!-- GENERATED FILE — do not edit by hand. Source: callman_core (npm run ai:packs). -->
2
+
3
+ # Scenario node reference
4
+
5
+ A scenario is a directed graph: nodes do the work, edges decide what runs next. This reference is for clients that write scenarios through the API or an MCP tool; every rule below is what the server enforces on save or what the run engine does.
6
+
7
+ ## Scenario shape
8
+
9
+ Compact form (what the MCP scenario tools take):
10
+
11
+ ```json
12
+ {
13
+ "name": "Order flow",
14
+ "description": "optional",
15
+ "priority": "high",
16
+ "nodes": [
17
+ {
18
+ "id": "login",
19
+ "type": "request",
20
+ "label": "Login",
21
+ "config": {
22
+ "method": "POST",
23
+ "url": "{{env.baseUrl}}/login"
24
+ }
25
+ },
26
+ {
27
+ "id": "done",
28
+ "type": "end",
29
+ "label": "Done"
30
+ }
31
+ ],
32
+ "edges": [
33
+ {
34
+ "source": "login",
35
+ "target": "done"
36
+ }
37
+ ],
38
+ "environments": [
39
+ {
40
+ "name": "Default",
41
+ "variables": [
42
+ {
43
+ "key": "baseUrl",
44
+ "value": "https://api.example.com"
45
+ }
46
+ ]
47
+ }
48
+ ]
49
+ }
50
+ ```
51
+
52
+ - Node `{ id?, type, label?, config?, position? }`. `id` defaults to n1, n2, …; `position` is laid out when omitted.
53
+ - `config` is deep-merged over the type's defaults (the Default column): objects merge key by key, arrays and scalars replace the default whole. Send only what you change — but an array you send (headers, checks, steps, rules, assignments) must be complete.
54
+ - Edge `{ id?, source, target, type? }`, `type` = `default` (or omitted) | `yes` | `no` | `error`. Edges have no label.
55
+ - `priority`: critical | high | medium | low. `environments[].variables`: `{ key, value, enabled? }[]`.
56
+ - Stored form (the REST API, and the body of `foreach` / `subscenario` / `scenario-ref`): node `{ id, type, position: { x, y }, data: { label, config } }` with the COMPLETE config — nothing is merged — and edge `{ id, source, target, type? }` with a required `id`.
57
+
58
+ Req column: **yes** = rejected on save without a real value; **run** = saved, but the run fails without it. Default "(engine)" = applied at run time when the field is absent.
59
+
60
+ ## Connections
61
+
62
+ db, redis, kafka, notification and ai nodes run on a workspace connection: `config.connectionId` is the id of a connection of type `database`, `redis`, `kafka`, `notification` (Slack) or `ai` (managed). Use a real connection id from the workspace — never invent one. Only the ai node rejects an empty id on save; the others save with `""` and fail when run.
63
+
64
+ ## Labels
65
+
66
+ - `label` names a node's output: later nodes read `{{Label.path}}`. It is optional on save, but an unlabelled node's output cannot be referenced.
67
+ - Labels must be unique across the whole scenario, including foreach / subscenario bodies: a repeated label is overwritten by whichever node ran last.
68
+ - Reserved labels — the engine drops the output of a node labelled `workflow`, `__meta`, `loop`, `loops`, `item`, `each`, `eaches`, `ws`, so references to it resolve to empty without any error.
69
+ - Avoid labels that are built-in roots — `response`, `lastResponse`, `data`, `env`, `global`, `globals`, `db`, `redis`, `kafkaEvent`, `kafkaevent` — the node and the root shadow each other.
70
+ - Prefer identifier labels (`Login`, `CreateOrder`, `check_db`). Script nodes get a label as a global variable only when it is an identifier and not a sandbox name (`pm`, `env`, `console`, `request`, `response`, `test`, `expect`, `workflow`, `db`, `kafka`, `redis`, …).
71
+
72
+ ## Templates and outputs
73
+
74
+ - `{{env.KEY}}` / `{{global.KEY}}` read one scope; a bare `{{KEY}}` reads both (in scenario runs a global wins when both define KEY). `{{data.column}}` is the current dataset row.
75
+ - `{{Label.path}}` (or `{Label.path}`) reads an earlier node's output; arrays by index (`items[0].id`), no wildcards. `{{response.*}}` is the most recent request's response. Generators: `{{$randomUUID}}`, `{{$timestamp}}`, `{{random.email}}`, `{{counter}}`.
76
+ - Substitution is plain text — quote SQL strings yourself (`WHERE id = '{{userId}}'`). A missing value resolves to an empty string.
77
+ - A request's output: `<Label>.status` is the HTTP status (number). Read body fields through `<Label>.body.<path>`: top-level body keys are also spread onto the output, but `status`, `statusText`, `data`, `body`, `rawBody`, `text`, `headers`, `cookies`, `durationMs` are HTTP metadata and win over same-named body keys. `<Label>.data.<path>` reads a body's top-level `data`.
78
+ - Operand paths (rules, `foreach.itemsPath`, set-vars `source`) are BARE dotted paths without braces: `CreateOrder.body.total`, `CheckOrder.rows[0].status`.
79
+
80
+ ## Rules and operands
81
+
82
+ Shared by condition, assertion, poll, websocket expect steps and `end.loopExitRule`.
83
+
84
+ - Rule `{ id, type: "rule", left, operator, right? }` — `id` and `type: "rule"` are required; `right` is required unless the operator is unary.
85
+ - Group `{ id, type: "group", operator: "AND" | "OR", children: [Rule | Group, …] }` with at least one child.
86
+ - Operand `{ mode: "runtime" | "literal", valueType: "string" | "number" | "boolean" | "null" | "array", value, extract? }`. runtime: `value` is a bare path. literal: a JSON number for number, true/false for boolean, null for null, a JSON array for array.
87
+ - Binary operators: equals, not_equals, strict_equals, strict_not_equals, greater_than, less_than, greater_or_equal, less_or_equal, between, contains, not_contains, starts_with, ends_with, regex, in, not_in, contains_row, set_equals_unordered. `between` takes [min, max]; `in` / `not_in` an array; `regex` a JS regex source; `contains_row` checks that an array of rows has one matching every key of an object (a JSON-object string literal or a runtime path); `set_equals_unordered` compares two arrays as multisets.
88
+ - Unary operators (no `right`): exists, not_exists, is_empty, not_empty, is_null, not_null.
89
+ - `extract` `{ type: "jsonpath" | "regex", expression, flags?, group?, select?: "first" | "all" }` is applied to the resolved value first; a failed extraction behaves as not-exists.
90
+
91
+ Example: `{ "id": "r1", "type": "rule", "left": { "mode": "runtime", "valueType": "number", "value": "CreateOrder.status" }, "operator": "equals", "right": { "mode": "literal", "valueType": "number", "value": 201 } }`
92
+
93
+ ## Contract rules
94
+
95
+ Each rule's `rules` object may use ONLY these keys (omit the rest):
96
+ - common: required(bool), type(string|number|boolean|object|array|null), equals(string|number|bool), notEmpty(bool)
97
+ - number: min,max,greaterThan,lessThan(number); integer,positive,negative,nonZero(bool)
98
+ - string: minLength,maxLength(int); pattern,contains,notContains,startsWith,endsWith(string); caseSensitive(bool); enumValues(array); format(enum)
99
+ - array: minItems,maxItems(int); sorted({order:asc|desc,field?}); unique({mode:whole|byField,fields?})
100
+ - object: requiredKeys,forbiddenKeys(string[]); minProperties,maxProperties(int); strictSchema(bool)
101
+ - format values: email, url, uuid, uuidV1, uuidV4, uuidV7, jwt, base64, base64url, base64Pdf, base64Png, base64Jpeg, base64Gif, base64Webp, base64Image, base64Zip, base64Office, datetime, date, time, ipv4, ipv6, hostname, json, numeric, integer, alpha, alphanumeric, hex, hexColor, slug, semver, objectId, creditCard, phone
102
+
103
+ ## Execution policy
104
+
105
+ Every node except condition takes `executionPolicy: { onFailure: "stop" | "continue", retry: { enabled, maxAttempts (0..100), delayMs (0..3600000), backoffMultiplier? (1..10), maxDelayMs? (0..3600000) } }` — onFailure and retry.enabled / maxAttempts / delayMs are required when you send the stored form.
106
+ - `maxAttempts` counts every attempt (an enabled retry makes at least 2). Delay before retry n = min(maxDelayMs, delayMs × backoffMultiplier^(n−1)). No policy = stop, no retry.
107
+ - stop: a failure ends the run; continue: the run goes on along the normal edges.
108
+ - `error` edges from the failing node win over both: the run follows them instead of the normal edges (after the retries).
109
+
110
+ ## Node types
111
+
112
+ ### request
113
+ One HTTP call.
114
+
115
+ | Field | Type | Default | Req | Notes |
116
+ | --- | --- | --- | --- | --- |
117
+ | `method` | string | `"GET"` | | HTTP verb. |
118
+ | `url` | string (≤10000) | `""` | run | Absolute URL; `{{…}}` allowed. Its own `?query` is used only when `query` has no enabled rows. |
119
+ | `headers` | {key, value, enabled?}[] | `[]` | | Disabled rows are not sent. A Content-Type row beats the automatic one (formdata always uses the driver's multipart type). |
120
+ | `query` | {key, value, enabled?}[] | `[]` | | |
121
+ | `body.mode` | none \| raw \| formdata \| urlencoded | `"none"` | | |
122
+ | `body.raw` | string | `""` | | mode raw. JSON text that still parses after templating is sent as JSON. |
123
+ | `body.rawLanguage` | json \| xml \| text \| html | — | | With no Content-Type header, sets application/json, application/xml, text/plain or text/html (json when absent). |
124
+ | `body.formEntries` | {key, value, enabled?, type?, fixtureId?, fileName?}[] | `[]` | | formdata / urlencoded rows. A `type:"file"` row needs `fixtureId` (an uploaded workspace fixture file) — server runs fail it otherwise. |
125
+ | `auth.type` | none \| bearer \| basic \| apikey \| oauth2 | `"none"` | | |
126
+ | `auth.bearerToken` | string | `""` | | bearer → `Authorization: Bearer <token>`. |
127
+ | `auth.basicUsername / auth.basicPassword` | string | `""` | | basic → base64 `user:password`. |
128
+ | `auth.apiKeyKey / auth.apiKeyValue` | string | `""` | | apikey → sends `key: value`; skipped when the key is blank. |
129
+ | `auth.apiKeyLocation` | header \| query | `"header"` | | |
130
+ | `auth.oauth2` | {grantType, tokenUrl, clientId, clientSecret, scope, username, password, refreshToken, clientAuth, audience} | — | | oauth2: when present ALL ten keys are required (send "" for unused ones); grantType client_credentials \| password \| refresh_token; clientAuth basic \| body. The token is fetched (and cached) before the call and sent as a Bearer header. Without it, type oauth2 sends no Authorization. |
131
+ | `preRequestScript / postResponseScript / testsScript` | string | `""` | | `pm.*` scripts: before the call / after the response / assertions (`pm.test`). |
132
+ | `contractAssertions` | {id, path, enabled, rules, engine?, namespaces?}[] (≤200) | `[]` | | id, path, enabled and rules are required; `rules` needs ≥1 key (see Contract rules). `path` is a dot-path over the parsed body (`data.items[0].id`, `items[].id` = every element); with engine "xpath" it is an XPath over the raw XML and every prefix must be in `namespaces` {prefix: uri}. |
133
+ | `expectedStatus` | string (≤200) | — | | Negative testing: `"201"`, `"4xx"`, `"200-299"`, `"200,204"`, templates allowed. When set the node passes iff the status matches (instead of 2xx/3xx); contract assertions and test scripts can still fail it. |
134
+ | `responseSchema` | JSON Schema object | — | | Validated against the response body; a mismatch fails the node. |
135
+ | `clientCertificate` | {enabled, format, pfxBase64?, certPem?, keyPem?, passphrase?, caPem?, rejectUnauthorized?} | — | | mTLS. enabled and format ("pfx" \| "pem") are required; pfx uses pfxBase64, pem uses certPem + keyPem. Server runs present the certificate whenever this object is set — omit it to send none. |
136
+ | `soap` | {enabled, version, action?, wsSecurity?} | — | | version "1.1" \| "1.2". Keep the full envelope in body.raw (rawLanguage "xml"); Content-Type/SOAPAction come from the version (a Content-Type header wins). wsSecurity {enabled, username, password, passwordType: text \| digest} injects a UsernameToken at send time. |
137
+ | `executionPolicy` | ExecutionPolicy | stop, no retry | | See Execution policy. |
138
+
139
+ Output: `<Label>.status` (number), `<Label>.body.<path>`, `<Label>.headers`, `<Label>.text`, `<Label>.durationMs`. The most recent request is also `response.*`.
140
+
141
+ ```json
142
+ {"id":"login","type":"request","label":"Login","config":{"method":"POST","url":"{{env.baseUrl}}/login","body":{"mode":"raw","raw":"{\"user\":\"{{env.user}}\",\"password\":\"{{env.password}}\"}","rawLanguage":"json"},"expectedStatus":"200"}}
143
+ ```
144
+
145
+ ### db
146
+ One query on a workspace connection of type `database`.
147
+
148
+ | Field | Type | Default | Req | Notes |
149
+ | --- | --- | --- | --- | --- |
150
+ | `connectionId` | string | `""` | run | `""` = not chosen yet: saved, but the run fails. |
151
+ | `query` | string (1..100000) | `"SELECT *\nFROM users\nWHERE id = {{env.userId}}"` | yes | Mongo: a JSON command-object string (`{"collection":"orders","operation":"findOne","filter":{…}}`); SQL: plain SQL. Per-engine details: the DB query reference. The default is a placeholder — always send your own. |
152
+ | `params` | string[] (≤200) | — | | Positional binds, template-resolved: `$1` (Postgres), `?` (MySQL), `@p1…` (SQL Server). |
153
+ | `typedParams` | {value, type?}[] (≤200) | — | | Wins over params. type auto \| text \| int \| numeric \| boolean \| date \| timestamp \| json \| null: null binds SQL NULL, boolean a real boolean, the rest stay strings (cast in SQL). |
154
+ | `useSession` | boolean | — | | Postgres only: join the run's shared session (scenario-level `dbSettings.transactionMode`: none \| rollback \| commit). |
155
+ | `expectError` | {sqlState?, messagePattern?} | — | | Negative test: the node passes only if the query FAILS with that SQLSTATE and/or a message matching the regex. |
156
+ | `executionPolicy` | ExecutionPolicy | stop, no retry | | See Execution policy. |
157
+
158
+ Output: `<Label>.rows`, `<Label>.rowCount`; the rows are also `db.result`.
159
+
160
+ ```json
161
+ {"id":"check","type":"db","label":"CheckOrder","config":{"connectionId":"<database connection id>","query":"SELECT status FROM orders WHERE id = $1","params":["{{CreateOrder.body.id}}"]}}
162
+ ```
163
+
164
+ ### redis
165
+ Redis commands on a workspace connection of type `redis`.
166
+
167
+ | Field | Type | Default | Req | Notes |
168
+ | --- | --- | --- | --- | --- |
169
+ | `connectionId` | string | `""` | run | |
170
+ | `commands` | string[] (≤1000, each non-empty) | `[]` | run | One command per entry, template-resolved. Supported: GET, SET, DEL, EXISTS, TTL, HGET, HSET, HGETALL, HDEL, LPUSH, RPUSH, LRANGE, LLEN, SADD, SMEMBERS, SISMEMBER, INCR, DECR, INCRBY, EXPIRE, PERSIST, TYPE, ZADD, ZRANGE, ZSCORE, SCAN. `SCAN pattern [count]` returns {keys, count, truncated}. An empty list fails the run. |
171
+ | `executionPolicy` | ExecutionPolicy | continue, retry ×2 every 1000 ms | | See Execution policy. |
172
+
173
+ Output: The reply (one command) or an array of replies, as `<Label>` and `redis.result`.
174
+
175
+ ```json
176
+ {"id":"cache","type":"redis","label":"Cache","config":{"connectionId":"<redis connection id>","commands":["GET order:{{CreateOrder.body.id}}"]}}
177
+ ```
178
+
179
+ ### kafka
180
+ Consume (wait for a matching message) or publish, on a connection of type `kafka`.
181
+
182
+ | Field | Type | Default | Req | Notes |
183
+ | --- | --- | --- | --- | --- |
184
+ | `connectionId` | string | `""` | run | |
185
+ | `topic` | string (1..500) | `""` | yes | |
186
+ | `mode` | consume \| publish | `"consume"` | | |
187
+ | `matchMode` | regex \| rules | `"regex"` | | consume. |
188
+ | `rules` | string[] | `[]` | | consume. regex: rules[0] is a regex tested against the whole message. rules: every entry is ONE comparison `left op right` (op ==, !=, ===, !==, >, <, >=, <=, contains) and all must hold, e.g. `kafkaEvent.orderId == '{{CreateOrder.body.id}}'`. Empty = the first message captured. |
189
+ | `publishValueFormat` | json \| raw | `"json"` | | publish. json fails the node when messageValue is not valid JSON after templating. |
190
+ | `messageKey` | string | `""` | | publish. |
191
+ | `messageValue` | string (≤1000000) | `""` | | publish payload, template-resolved. |
192
+ | `messageHeaders` | {key, value, enabled?}[] | `[]` | | publish. |
193
+ | `executionPolicy` | ExecutionPolicy | continue, retry ×3 every 2000 ms | | See Execution policy. |
194
+
195
+ Output: consume: the matched message — a JSON message's keys at the top level plus `meta` {value, text, key, partition, offset, timestamp, headers}; also `kafkaEvent.*`.
196
+
197
+ ```json
198
+ {"id":"event","type":"kafka","label":"OrderCreated","config":{"connectionId":"<kafka connection id>","topic":"orders","mode":"consume","matchMode":"rules","rules":["kafkaEvent.orderId == '{{CreateOrder.body.id}}'"]}}
199
+ ```
200
+
201
+ ### condition
202
+ The only branching node and the only node without `executionPolicy`. Needs exactly two outgoing edges: one `yes`, one `no`.
203
+
204
+ | Field | Type | Default | Req | Notes |
205
+ | --- | --- | --- | --- | --- |
206
+ | `mode` | builder \| expert | `"builder"` | | |
207
+ | `rootGroup` | Group | one rule: `response.status` equals `200` | | Evaluated in builder mode (see Rules and operands). Stored in both modes. |
208
+ | `expertExpression` | string \| null | `"{{response.status}} == 200"` | | Used ONLY with `mode: "expert"` (ignored otherwise). Syntax below. |
209
+
210
+ Output: Takes the `yes` or `no` edge.
211
+
212
+ Expert syntax: operands are `{{path}}` tokens (a bare path is a parse error), 'single'- or "double"-quoted strings, numbers, true / false / null and [arrays]; operators ==, !=, ===, !==, >, <, >=, <=, contains, not contains, starts with, ends with, regex, in, not in, between, exists, not exists, is empty, not empty, is null, not null, contains row, set equals; combine with && / AND, || / OR and parentheses. Example: `{{Login.status}} == 200 && {{Login.body.token}} != ''`.
213
+
214
+ ```json
215
+ {"id":"ok","type":"condition","label":"LoggedIn","config":{"mode":"builder","rootGroup":{"id":"g1","type":"group","operator":"AND","children":[{"id":"r1","type":"rule","left":{"mode":"runtime","valueType":"number","value":"Login.status"},"operator":"equals","right":{"mode":"literal","valueType":"number","value":200}}]}}}
216
+ ```
217
+
218
+ ### assertion
219
+ Pass/fail checkpoint; does not branch (on failure the execution policy decides).
220
+
221
+ | Field | Type | Default | Req | Notes |
222
+ | --- | --- | --- | --- | --- |
223
+ | `matchMode` | all \| any | `"all"` | | |
224
+ | `checks` | {id, name, enabled, rule}[] (≤1000) | one blank check | run | id, name (may be ""), enabled and rule are required; `rule` is a full Rule. With no enabled check the node passes without testing anything — send at least one. |
225
+ | `executionPolicy` | ExecutionPolicy | stop, no retry | | See Execution policy. |
226
+
227
+ Output: `<Label>.passed`, `.passedCount`, `.failedCount`, `.checks[i]` {name, passed, message}.
228
+
229
+ ```json
230
+ {"id":"verify","type":"assertion","label":"VerifyOrder","config":{"checks":[{"id":"c1","name":"total is 40","enabled":true,"rule":{"id":"c1r","type":"rule","left":{"mode":"runtime","valueType":"number","value":"CreateOrder.body.total"},"operator":"equals","right":{"mode":"literal","valueType":"number","value":40}}}]}}
231
+ ```
232
+
233
+ ### script
234
+ JavaScript in the `pm.*` sandbox.
235
+
236
+ | Field | Type | Default | Req | Notes |
237
+ | --- | --- | --- | --- | --- |
238
+ | `script` | string (≤1000000) | `"return {\n ok: true,\n};"` | run | Its `return` value is the node's output. Can `pm.environment.set`, `pm.test`, `await pm.db.query(…)` / `pm.redis.command(…)`. Empty or invalid code fails the run. |
239
+ | `timeoutMs` | integer 1..60000 | `3000` | | Also capped by the host's per-node timeout. |
240
+ | `executionPolicy` | ExecutionPolicy | stop, no retry | | See Execution policy. |
241
+
242
+ Output: The returned value (`<Label>.<key>` for an object).
243
+
244
+ ```json
245
+ {"id":"calc","type":"script","label":"Totals","config":{"script":"const body = CreateOrder.body;\nreturn { total: body.total * 2 };"}}
246
+ ```
247
+
248
+ ### set-vars
249
+ Write environment/global variables without a script. Rows apply top to bottom (a row sees earlier rows' writes).
250
+
251
+ | Field | Type | Default | Req | Notes |
252
+ | --- | --- | --- | --- | --- |
253
+ | `assignments` | Assignment[] (≤200) | one blank row | | |
254
+ | `assignments[].id / .key / .value` | string | — | yes | key and value are template-resolved; value may be "". |
255
+ | `assignments[].scope` | environment \| global | — | yes | |
256
+ | `assignments[].enabled` | boolean | — | yes | |
257
+ | `assignments[].extractorType` | template \| jsonpath \| regex | — | | jsonpath / regex: resolve `source` (a bare runtime path such as `CreateOrder.body`), then apply `expression` (JSONPath like `$.items[0].id`, or a JS regex source); `value` is ignored. Regex rows take `flags` (subset of gimsuy) and `group`; `select` first \| all (all writes a JSON array). A failed extraction skips that write. |
258
+ | `executionPolicy` | ExecutionPolicy | stop, no retry | | See Execution policy. |
259
+
260
+ Output: `<Label>.environment` / `<Label>.globals` (what was written), `<Label>.extraction` for extractor rows.
261
+
262
+ ```json
263
+ {"id":"save","type":"set-vars","label":"SaveOrderId","config":{"assignments":[{"id":"a1","scope":"environment","key":"orderId","value":"{{CreateOrder.body.id}}","enabled":true}]}}
264
+ ```
265
+
266
+ ### poll
267
+ Repeat ONE embedded action until a condition passes or the budget runs out. Retry is forced off (the loop is the retry); a failing tick is retried, not fatal.
268
+
269
+ | Field | Type | Default | Req | Notes |
270
+ | --- | --- | --- | --- | --- |
271
+ | `actionType` | request \| db \| redis \| script | `"request"` | | |
272
+ | `request / db / redis / script` | that node type's config | request: the request defaults | run | The one matching actionType. Same fields as the standalone node. |
273
+ | `successCondition` | {mode, rootGroup, expertExpression?} | `response.status` equals `200` | | Evaluated after every successful tick. A tick publishes like the real node: request → `response.*`, db → `db.result` (rows), redis → `redis.result`; a script tick exposes only its variable writes (`env.*`, `global.*`). |
274
+ | `intervalMs` | integer 0..3600000 | `2000` | | |
275
+ | `maxAttempts` | integer 1..1000 | `30` | | |
276
+ | `timeoutMs` | integer 1..86400000 | — | | Wall-clock cap. |
277
+ | `backoffMultiplier` | number 1..10 | — | | Exponential backoff on the interval. |
278
+ | `maxDelayMs` | integer 0..3600000 | — | | Backoff cap. |
279
+ | `onTimeout` | fail \| continue | `"fail"` | | continue marks the node degraded and goes on. |
280
+ | `executionPolicy` | ExecutionPolicy | stop, no retry | | See Execution policy. |
281
+
282
+ Output: `<Label>.attempts`, `.elapsedMs`, `.timedOut`, `.conditionResult`, `.lastTickError`; the last tick's result as listed above.
283
+
284
+ ```json
285
+ {"id":"wait-ready","type":"poll","label":"WaitReady","config":{"actionType":"request","request":{"url":"{{env.baseUrl}}/orders/{{CreateOrder.body.id}}"},"successCondition":{"mode":"expert","expertExpression":"{{response.body.status}} == 'READY'"},"intervalMs":2000,"maxAttempts":15}}
286
+ ```
287
+
288
+ ### foreach
289
+ Run an embedded body graph once per item of an array.
290
+
291
+ | Field | Type | Default | Req | Notes |
292
+ | --- | --- | --- | --- | --- |
293
+ | `nodes / edges` | stored node[] / stored edge[] | `[]` | | The body graph in the STORED form with complete configs (see Scenario shape) — no defaults are merged inside. Same graph rules; labels unique across the whole scenario. |
294
+ | `sourceMode` | path \| inline | `"path"` | | |
295
+ | `itemsPath` | string (≤2000) | — | run | path mode: a bare runtime path to an array, e.g. `Users.body.items`. |
296
+ | `itemsInline` | string | — | run | inline mode: JSON array text; templates resolve first. |
297
+ | `itemAlias` | string (≤100) | — | | Extra root mirroring `{{item}}` (e.g. `user` → `{{user.id}}`). Not a reserved label. |
298
+ | `maxIterations` | integer 1..1000 | 100 (engine) | | |
299
+ | `delayMs` | integer 0..3600000 | — | | Pause between items. |
300
+ | `onItemFailure` | stop \| continue | `"stop"` | | continue: failed items degrade the run, the loop goes on. |
301
+ | `collectResults` | boolean | `true` | | |
302
+ | `executionPolicy` | ExecutionPolicy | stop, no retry | | See Execution policy. |
303
+
304
+ Output: `<Label>.results[i].<ChildLabel>…`, `.itemCount`, `.processedCount`, `.truncated`, `.failedItems`. Inside the body: `{{item}}`, `{{each.index}}` (0-based), `{{each.iteration}}` (1-based), `{{each.total}}`, `{{each.remaining}}`, `{{eaches.<ForeachLabel>.iteration}}` for an outer loop.
305
+
306
+ ```json
307
+ {"id":"each-user","type":"foreach","label":"EachUser","config":{"sourceMode":"path","itemsPath":"Users.body.items","itemAlias":"user","nodes":[{"id":"get-user","type":"request","position":{"x":0,"y":0},"data":{"label":"GetUser","config":{"method":"GET","url":"{{env.baseUrl}}/users/{{user.id}}","headers":[],"query":[],"body":{"mode":"none","raw":"","formEntries":[]}}}}],"edges":[]}}
308
+ ```
309
+
310
+ ### websocket
311
+ One WebSocket conversation: connect, run the steps in order, close. Retry re-runs the whole conversation.
312
+
313
+ | Field | Type | Default | Req | Notes |
314
+ | --- | --- | --- | --- | --- |
315
+ | `url` | string (≤2000) | `""` | run | ws:// or wss://, template-resolved. |
316
+ | `headers` | {key, value, enabled?}[] (≤100) | `[]` | | |
317
+ | `subprotocols` | string[] (≤20) | `[]` | | |
318
+ | `connectTimeoutMs` | integer 100..120000 | 10000 (engine) | | |
319
+ | `steps` | Step[] (≤200) | `[]` | | {id, kind:"send", payload} sends one text frame; {id, kind:"expect", rules (1..50 Rules), timeoutMs? (100..300000, default 10000), matchMode? all \| any} waits for a matching frame — rule paths use `ws.text`, `ws.json.<path>`, `ws.direction`, `ws.index`; {id, kind:"wait", durationMs (0..300000)}. A timed-out expect fails the node. |
320
+ | `closeCode` | integer 1000..4999 | 1000 (engine) | | |
321
+ | `rejectUnauthorized` | boolean | — | | false accepts self-signed certificates. |
322
+ | `executionPolicy` | ExecutionPolicy | stop, no retry | | See Execution policy. |
323
+
324
+ Output: `<Label>.connected`, `.messages[i].text`, `.messageCount`, `.failedSteps`, `.closeCode`.
325
+
326
+ ```json
327
+ {"id":"ws","type":"websocket","label":"Subscribe","config":{"url":"wss://stream.example.com/orders","steps":[{"id":"s1","kind":"send","payload":"{\"subscribe\":\"orders\"}"},{"id":"s2","kind":"expect","rules":[{"id":"s2r","type":"rule","left":{"mode":"runtime","valueType":"string","value":"ws.json.event"},"operator":"equals","right":{"mode":"literal","valueType":"string","value":"subscribed"}}]}]}}
328
+ ```
329
+
330
+ ### ai
331
+ One LLM call on a managed workspace connection of type `ai`.
332
+
333
+ | Field | Type | Default | Req | Notes |
334
+ | --- | --- | --- | --- | --- |
335
+ | `connectionId` | string (1..200) | `""` | yes | The default `""` is rejected on save. |
336
+ | `prompt` | string (≤200000) | `""` | run | Template-resolved; empty fails the run. |
337
+ | `responseExample` | string (≤20000) | `""` | run | A JSON OBJECT as text; its top-level keys are required in the reply (extra keys allowed). |
338
+ | `maxTokens` | integer 1..32000 | 2000 (engine) | | |
339
+ | `timeoutMs` | integer 1000..300000 | 60000 (engine) | | |
340
+ | `executionPolicy` | ExecutionPolicy | stop, no retry | | See Execution policy. |
341
+
342
+ Output: The parsed JSON reply: `<Label>.<exampleKey>`.
343
+
344
+ ```json
345
+ {"id":"classify","type":"ai","label":"Classify","config":{"connectionId":"<ai connection id>","prompt":"Classify the sentiment of: {{GetReview.body.text}}","responseExample":"{\"sentiment\":\"positive\",\"score\":0.9}"}}
346
+ ```
347
+
348
+ ### wait
349
+ Fixed delay.
350
+
351
+ | Field | Type | Default | Req | Notes |
352
+ | --- | --- | --- | --- | --- |
353
+ | `durationMs` | integer 1..2147483647 | `5000` | | |
354
+ | `executionPolicy` | ExecutionPolicy | stop, no retry | | See Execution policy. |
355
+
356
+ Output: `<Label>.configuredDurationMs`, `.actualDurationMs`, `.status`.
357
+
358
+ ```json
359
+ {"id":"pause","type":"wait","label":"Pause","config":{"durationMs":1000}}
360
+ ```
361
+
362
+ ### notification
363
+ Slack message through a workspace connection of type `notification`.
364
+
365
+ | Field | Type | Default | Req | Notes |
366
+ | --- | --- | --- | --- | --- |
367
+ | `provider` | "slack" | `"slack"` | | |
368
+ | `connectionId` | string | `""` | run | |
369
+ | `severity` | info \| success \| warning \| error | `"info"` | | |
370
+ | `messageTemplate` | string (≤100000) | a run-status line | | Template-resolved (node outputs, `{{workflow.name}}`, `{{workflow.__meta.status}}` …). |
371
+ | `channelOverride` | string (≤500) | `""` | | |
372
+ | `continueOnFailure` | boolean | `true` | | Overrides executionPolicy.onFailure (true = continue). |
373
+ | `advanced.useRichBlocks` | boolean | `true` | | |
374
+ | `executionPolicy` | ExecutionPolicy | continue, no retry | | See Execution policy. |
375
+
376
+ Output: The delivery result.
377
+
378
+ ```json
379
+ {"id":"notify","type":"notification","label":"Notify","config":{"connectionId":"<notification connection id>","severity":"warning","messageTemplate":"Order {{CreateOrder.body.id}} is not ready"}}
380
+ ```
381
+
382
+ ### aggregator
383
+ Build one JSON object from earlier outputs.
384
+
385
+ | Field | Type | Default | Req | Notes |
386
+ | --- | --- | --- | --- | --- |
387
+ | `template` | string (≤1000000) | `"{\n \"key\": \"{Label.field}\"\n}"` | run | Must be valid JSON after templating (`{{Label.path}}` or `{Label.path}` tokens), else the run fails. |
388
+ | `executionPolicy` | ExecutionPolicy | stop, no retry | | See Execution policy. |
389
+
390
+ Output: The parsed object: `<Label>.<key>`.
391
+
392
+ ```json
393
+ {"id":"summary","type":"aggregator","label":"Summary","config":{"template":"{\"orderId\":\"{{CreateOrder.body.id}}\",\"status\":\"{{CheckOrder.rows[0].status}}\"}"}}
394
+ ```
395
+
396
+ ### end
397
+ Terminates a path; optionally loops back to an earlier node.
398
+
399
+ | Field | Type | Default | Req | Notes |
400
+ | --- | --- | --- | --- | --- |
401
+ | `loop` | boolean | `false` | | |
402
+ | `loopTargetNodeId` | string \| null | `null` | run | loop: the id of an earlier node to jump back to. |
403
+ | `loopIterations` | integer 1..1000 | `1` | | Re-entries: the looped section runs loopIterations + 1 times. |
404
+ | `loopDelayMs` | integer 0..600000 | `1000` | | |
405
+ | `loopExitRule` | Rule \| null | — | | Checked after each pass; TRUE stops the loop early and continues along the end node's outgoing edges. Loop roots: `loop.iteration` (1-based), `loop.index`, `loop.total`, `loop.remaining`. |
406
+ | `executionPolicy` | ExecutionPolicy | stop, no retry | | See Execution policy. |
407
+
408
+ Output: A snapshot of the run's outputs so far.
409
+
410
+ ```json
411
+ {"id":"again","type":"end","label":"Repeat","config":{"loop":true,"loopTargetNodeId":"login","loopIterations":2,"loopDelayMs":500}}
412
+ ```
413
+
414
+ ### subscenario
415
+ A group of nodes collapsed into one node (the builder's Group).
416
+
417
+ | Field | Type | Default | Req | Notes |
418
+ | --- | --- | --- | --- | --- |
419
+ | `nodes / edges` | stored node[] / stored edge[] | none | yes | Stored form, complete configs; no defaults are merged for this type. Same graph rules. |
420
+ | `reusableGroupId / reusableSourceScenarioId / reusableSourceNodeId / ungroupSnapshot` | app-managed | — | | Written by the builder; omit them. |
421
+ | `executionPolicy` | ExecutionPolicy | stop, no retry (engine) | | See Execution policy. |
422
+
423
+ Output: Its inner nodes publish under their own labels.
424
+
425
+ ```json
426
+ {"id":"setup","type":"subscenario","label":"Setup","config":{"nodes":[{"id":"seed","type":"wait","position":{"x":0,"y":0},"data":{"label":"Settle","config":{"durationMs":500}}}],"edges":[]}}
427
+ ```
428
+
429
+ ### scenario-ref
430
+ A reference to another scenario, embedded as a synced snapshot. Created by the app when a scenario is linked; the compact form cannot create or re-send one (in the stored form, send it back exactly as read).
431
+
432
+ | Field | Type | Default | Req | Notes |
433
+ | --- | --- | --- | --- | --- |
434
+ | `referencedScenarioId` | string | — | yes | |
435
+ | `referencedScenarioVersion` | integer \| null | — | yes | |
436
+ | `referencedScenarioName / lastSyncedAt` | string | — | yes | |
437
+ | `nodes / edges` | stored node[] / stored edge[] | — | yes | The referenced scenario's graph snapshot. |
438
+ | `executionPolicy` | ExecutionPolicy | stop, no retry (engine) | | See Execution policy. |
439
+
440
+ Output: Its inner nodes publish under their own labels.
441
+
442
+ ## Graph rules
443
+
444
+ Rejected on save:
445
+ - Node ids unique; edge ids unique; every edge's source and target is an existing node id.
446
+ - `yes` / `no` edges only leave a condition node; `error` edges only leave a non-condition node; omit `type` (or `default`) for normal flow.
447
+ - A condition node has exactly two outgoing edges: one `yes`, one `no`.
448
+ - At least one start node (a node with no incoming edge) and no cycles — loop with an end node's `loop` settings, never with a back edge.
449
+ - foreach / subscenario / scenario-ref bodies are checked with the same rules.
450
+
451
+ Saved with a warning: more than one start node; nodes no start node reaches.
@@ -6,6 +6,7 @@ export { buildUnifiedSystemPrompt, buildUnifiedUserPrompt } from "./prompts/unif
6
6
  export { buildDiagramSystemPrompt, buildDiagramUserPrompt } from "./prompts/diagram.js";
7
7
  export { buildScenarioSystemPrompt, buildScenarioUserPrompt, SCENARIO_AI_REFERENCE_TYPES, type BuildScenarioSystemPromptOptions, } from "./prompts/scenario.js";
8
8
  export { defaultScenarioNodeConfig, SCENARIO_NODE_DEFAULT_CONFIGS, } from "./prompts/scenarioNodeDefaults.js";
9
+ export { renderScenarioNodeReference, SCENARIO_NODE_REFERENCE_TYPES, type RenderScenarioNodeReferenceOptions, } from "./prompts/scenarioNodeReference.js";
9
10
  export { isRecord as isAiRecord, parseEnvelope, scriptHasSyntaxError } from "./parse/shared.js";
10
11
  export { parseAiUnifiedOutput, type ParseAiUnifiedOptions } from "./parse/unified.js";
11
12
  export { parseAiDiagramOutput } from "./parse/diagram.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ai/index.ts"],"names":[],"mappings":"AAOA,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACrB,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,wBAAwB,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AACxF,OAAO,EAAE,wBAAwB,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AACxF,OAAO,EACL,yBAAyB,EACzB,uBAAuB,EACvB,2BAA2B,EAC3B,KAAK,gCAAgC,GACtC,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,yBAAyB,EACzB,6BAA6B,GAC9B,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,QAAQ,IAAI,UAAU,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAChG,OAAO,EAAE,oBAAoB,EAAE,KAAK,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AACtF,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EACL,0BAA0B,EAC1B,wBAAwB,GACzB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ai/index.ts"],"names":[],"mappings":"AAOA,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACrB,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,wBAAwB,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AACxF,OAAO,EAAE,wBAAwB,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AACxF,OAAO,EACL,yBAAyB,EACzB,uBAAuB,EACvB,2BAA2B,EAC3B,KAAK,gCAAgC,GACtC,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,yBAAyB,EACzB,6BAA6B,GAC9B,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EACL,2BAA2B,EAC3B,6BAA6B,EAC7B,KAAK,kCAAkC,GACxC,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,QAAQ,IAAI,UAAU,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAChG,OAAO,EAAE,oBAAoB,EAAE,KAAK,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AACtF,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EACL,0BAA0B,EAC1B,wBAAwB,GACzB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC"}
package/dist/ai/index.js CHANGED
@@ -12,6 +12,7 @@ export { buildUnifiedSystemPrompt, buildUnifiedUserPrompt } from "./prompts/unif
12
12
  export { buildDiagramSystemPrompt, buildDiagramUserPrompt } from "./prompts/diagram.js";
13
13
  export { buildScenarioSystemPrompt, buildScenarioUserPrompt, SCENARIO_AI_REFERENCE_TYPES, } from "./prompts/scenario.js";
14
14
  export { defaultScenarioNodeConfig, SCENARIO_NODE_DEFAULT_CONFIGS, } from "./prompts/scenarioNodeDefaults.js";
15
+ export { renderScenarioNodeReference, SCENARIO_NODE_REFERENCE_TYPES, } from "./prompts/scenarioNodeReference.js";
15
16
  export { isRecord as isAiRecord, parseEnvelope, scriptHasSyntaxError } from "./parse/shared.js";
16
17
  export { parseAiUnifiedOutput } from "./parse/unified.js";
17
18
  export { parseAiDiagramOutput } from "./parse/diagram.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ai/index.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,0EAA0E;AAC1E,8EAA8E;AAC9E,2EAA2E;AAC3E,wEAAwE;AACxE,wEAAwE;AAExE,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACrB,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,wBAAwB,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AACxF,OAAO,EAAE,wBAAwB,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AACxF,OAAO,EACL,yBAAyB,EACzB,uBAAuB,EACvB,2BAA2B,GAE5B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,yBAAyB,EACzB,6BAA6B,GAC9B,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,QAAQ,IAAI,UAAU,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAChG,OAAO,EAAE,oBAAoB,EAA8B,MAAM,oBAAoB,CAAC;AACtF,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EACL,0BAA0B,EAC1B,wBAAwB,GACzB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ai/index.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,0EAA0E;AAC1E,8EAA8E;AAC9E,2EAA2E;AAC3E,wEAAwE;AACxE,wEAAwE;AAExE,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EACL,uBAAuB,EACvB,qBAAqB,EACrB,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,wBAAwB,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AACxF,OAAO,EAAE,wBAAwB,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AACxF,OAAO,EACL,yBAAyB,EACzB,uBAAuB,EACvB,2BAA2B,GAE5B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,yBAAyB,EACzB,6BAA6B,GAC9B,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EACL,2BAA2B,EAC3B,6BAA6B,GAE9B,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,QAAQ,IAAI,UAAU,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAChG,OAAO,EAAE,oBAAoB,EAA8B,MAAM,oBAAoB,CAAC;AACtF,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EACL,0BAA0B,EAC1B,wBAAwB,GACzB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"scenario.d.ts","sourceRoot":"","sources":["../../../src/ai/prompts/scenario.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAMvD,eAAO,MAAM,2BAA2B,iLAiB9B,CAAC;AAwCX,MAAM,WAAW,gCAAgC;IAC/C;;;OAGG;IACH,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;CAC9C;AAqBD,eAAO,MAAM,yBAAyB,GACpC,UAAS,gCAAqC,KAC7C,MAwFW,CAAC;AAEf,eAAO,MAAM,uBAAuB,GAAI,OAAO,mBAAmB,KAAG,MA+CpE,CAAC"}
1
+ {"version":3,"file":"scenario.d.ts","sourceRoot":"","sources":["../../../src/ai/prompts/scenario.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAOvD,eAAO,MAAM,2BAA2B,iLAiB9B,CAAC;AAwCX,MAAM,WAAW,gCAAgC;IAC/C;;;OAGG;IACH,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;CAC9C;AAqBD,eAAO,MAAM,yBAAyB,GACpC,UAAS,gCAAqC,KAC7C,MAwFW,CAAC;AAEf,eAAO,MAAM,uBAAuB,GAAI,OAAO,mBAAmB,KAAG,MA+CpE,CAAC"}
@@ -14,6 +14,7 @@
14
14
  import { REDIS_COMMAND_SPECS } from "../../host/redis/redisService.js";
15
15
  import { renderDbQueryReference } from "../../host/db/db-query-reference.js";
16
16
  import { defaultScenarioNodeConfig } from "./scenarioNodeDefaults.js";
17
+ import { RESERVED_SCENARIO_LABELS } from "../../scenario-runner/labels.js";
17
18
  // Types shown in the reference. `subscenario` + `scenario-ref` are intentionally
18
19
  // omitted — they are advanced/nested and `scenario-ref` can't be spawned blank;
19
20
  // the model is told to avoid them.
@@ -46,9 +47,9 @@ const NODE_NOTES = {
46
47
  // Supported command list is derived from the runtime specs so it can
47
48
  // never drift from what the runtime actually accepts.
48
49
  `Run Redis commands on a stored connection. REQUIRED: connectionId (type=redis) + ≥1 non-empty entry in \`commands\`. Each entry is ONE command string; supported commands: ${Object.keys(REDIS_COMMAND_SPECS).join(", ")} — e.g. "GET order:{{CreateOrder.orderId}}", "HGETALL user:{{env.userId}}" or "SET key {{env.value}}". SCAN is Callman-managed: \`SCAN pattern [count]\` returns {keys,count,truncated}. Output exposed under the label + as redis.result.`,
49
- kafka: "Consume OR publish (config.mode). CONSUME (mode:\"consume\"): REQUIRED connectionId (type=kafka) + topic + a matcher with ≥1 non-empty rule. TWO matchModes: (a) matchMode:\"regex\" → rules[0] is a single REGEX tested against the whole message, e.g. rules:[\"order.created\"]. (b) matchMode:\"rules\" → rules is a LIST OF EXPRESSIONS (expert-condition syntax), ALL must be true. Reference the captured event as kafkaEvent.<field>: for a JSON message its JSON keys are top-level, e.g. rules:[\"kafkaEvent.event == 'order.created'\", \"kafkaEvent.orderId == '{{CreateOrder.orderId}}'\"]. NEVER leave rules empty. PUBLISH (mode:\"publish\"): REQUIRED connectionId + topic + messageValue; optional messageKey, publishValueFormat \"json\"|\"raw\" (json validates the payload as JSON), messageHeaders:[{key,value,enabled:true}].",
50
- condition: "The ONLY branching node and the ONLY node WITHOUT executionPolicy. Must have EXACTLY one outgoing edge type \"yes\" and one \"no\". TWO modes: mode:\"builder\" (default) uses rootGroup { operator:\"AND\"|\"OR\", children:[ rule | nested group ] } where each rule is { id, type:\"rule\", left, operator, right } (operands per the OPERANDS section); mode:\"expert\" uses expertExpression, a single string like \"response.status == 200 && {Login.token} != ''\". Prefer builder mode.",
51
- assertion: "Pass/fail checkpoint (does NOT branch; on failure executionPolicy decides stop/continue). config.matchMode:\"all\" (every enabled check passes) | \"any\" (≥1 passes). checks:[{ id, name, enabled:true, rule }] with ≥1 enabled check — each rule is { left, operator, right } (operands per the OPERANDS section).",
50
+ kafka: "Consume OR publish (config.mode). CONSUME (mode:\"consume\"): REQUIRED connectionId (type=kafka) + topic + a matcher with ≥1 non-empty rule. TWO matchModes: (a) matchMode:\"regex\" → rules[0] is a single REGEX tested against the whole message, e.g. rules:[\"order.created\"]. (b) matchMode:\"rules\" → rules is a LIST OF EXPRESSIONS, each ONE comparison `left op right` (op ==, !=, ===, !==, >, <, >=, <=, contains), ALL must be true. Reference the captured event as kafkaEvent.<field>: for a JSON message its JSON keys are top-level, e.g. rules:[\"kafkaEvent.event == 'order.created'\", \"kafkaEvent.orderId == '{{CreateOrder.orderId}}'\"]. NEVER leave rules empty. PUBLISH (mode:\"publish\"): REQUIRED connectionId + topic + messageValue; optional messageKey, publishValueFormat \"json\"|\"raw\" (json validates the payload as JSON), messageHeaders:[{key,value,enabled:true}].",
51
+ condition: "The ONLY branching node and the ONLY node WITHOUT executionPolicy. Must have EXACTLY one outgoing edge type \"yes\" and one \"no\". TWO modes: mode:\"builder\" (default) uses rootGroup { operator:\"AND\"|\"OR\", children:[ rule | nested group ] } where each rule is { id, type:\"rule\", left, operator, right } (operands per the OPERANDS section); mode:\"expert\" uses expertExpression (ONLY read when mode is \"expert\"), a single string whose operands are {{path}} tokens — a bare path is a parse error — like \"{{Login.status}} == 200 && {{Login.body.token}} != ''\". Prefer builder mode.",
52
+ assertion: "Pass/fail checkpoint (does NOT branch; on failure executionPolicy decides stop/continue). config.matchMode:\"all\" (every enabled check passes) | \"any\" (≥1 passes). checks:[{ id, name, enabled:true, rule }] with ≥1 enabled check — each rule is { id, type:\"rule\", left, operator, right } (operands per the OPERANDS section).",
52
53
  script: "JS sandbox (Postman pm.*). REQUIRED: non-empty, syntactically-valid `script`; its `return` value is exposed downstream by the node label. Optional timeoutMs (default 3000). Can pm.environment.set(...), pm.expect(...), pm.test(...), and await pm.db.query / pm.redis.command (same formats as the DB & REDIS section) for logic a plain db/redis node can't express.",
53
54
  "set-vars": "No-code variable capture — prefer this over a script node for plain \"save X into a variable\" steps. config.assignments:[{ id, scope:\"environment\"|\"global\", key, value, enabled:true }] applied top-to-bottom (a later row can use an earlier row's variable). DEFAULT (template) row: `value` is template-resolved, e.g. \"{{CreateOrder.body.id}}\". EXTRACTOR row: add extractorType:\"jsonpath\"|\"regex\" + source + expression (`value` is then ignored). `source` is a BARE runtime dot-path WITHOUT braces (same semantics as condition operands), e.g. \"CreateOrder.body\". `expression` is a JSONPath like \"$.items[0].id\" or a JS regex source like \"ord-(\\\\d+)\". Regex rows may add `flags` (subset of \"gimsuy\") and `group` (capture group index, default: first group, else whole match). Optional select:\"first\" (default, writes one value) | \"all\" (writes a JSON array of every match). A failed extraction SKIPS that write and is reported in the node output — it does not fail the node.",
54
55
  poll: "Wait-until: repeats ONE embedded action until a condition passes or the budget runs out — prefer this over wait+loop chains for \"poll until ready\" steps. REQUIRED: actionType:\"request\"|\"db\"|\"redis\"|\"script\" + the MATCHING embedded config object (`request` | `db` | `redis` | `script`, same shape as the standalone node of that type) + successCondition (a full condition config: { mode:\"builder\", rootGroup } — same shape as the condition node, evaluated after EVERY tick against the tick's result, e.g. left { mode:\"runtime\", valueType:\"number\", value:\"response.status\" } for a request action) + intervalMs (delay between ticks, ≤ 3600000). OPTIONAL: maxAttempts (default 30, max 1000), timeoutMs (wall-clock cap, ≤ 86400000), backoffMultiplier (1..10, exponential backoff on the interval), maxDelayMs (backoff cap), onTimeout:\"fail\" (default — normal failure path, error edges apply) | \"continue\" (mark degraded and continue). Action errors are polled through (a failing tick is retried, not fatal); per-node retry is force-disabled — the loop IS the retry. Output: { attempts, maxAttempts, elapsedMs, timedOut, conditionResult, lastTickError? }; the last tick's action result is ALSO published like the standalone node would (response.*, rows, redis.result).",
@@ -111,20 +112,20 @@ export const buildScenarioSystemPrompt = (options = {}) => [
111
112
  "",
112
113
  "NODE ENVELOPE — every node is:",
113
114
  '{ "id": string (unique), "type": <one below>, "position": { "x": number, "y": number }, "data": { "label": string, "config": { ... } } }',
114
- "- `label` is REQUIRED, non-empty, UNIQUE across the scenario, and must NOT be \"workflow\" or \"__meta\". Downstream nodes read a node's output by its label: {{Login.data.token}}.",
115
+ `- \`label\` is REQUIRED, non-empty, UNIQUE across the scenario, and must NOT be a reserved name (${RESERVED_SCENARIO_LABELS.map((label) => `"${label}"`).join(", ")}) — the engine drops such a node's output. Downstream nodes read a node's output by its label: {{Login.data.token}}.`,
115
116
  "- Every config EXCEPT `condition` carries an `executionPolicy` object (see defaults below).",
116
117
  "- position: the app AUTO-ARRANGES the whole graph (top-to-bottom flow, branches fanned out side-by-side, centered, never overlapping), so layout is NOT your concern — just give each node any distinct {x,y} (e.g. step y by 150). Focus on correct edges + config, not coordinates. Model the flow by EDGES (branches, merges), not by stacking every node in one long line.",
117
118
  "",
118
- "EDGES — { \"id\": string, \"source\": <node id>, \"target\": <node id>, \"type\"?: \"default\" | \"yes\" | \"no\" }.",
119
+ "EDGES — { \"id\": string, \"source\": <node id>, \"target\": <node id>, \"type\"?: \"default\" | \"yes\" | \"no\" | \"error\" }.",
119
120
  "- Omit `type` (or use \"default\") for normal flow.",
120
121
  "- \"yes\"/\"no\" are ONLY used on the two edges leaving a `condition` node.",
122
+ "- \"error\" (any node except `condition`) is followed INSTEAD of the normal edges when that node fails.",
121
123
  "",
122
124
  "GRAPH RULES (a scenario that breaks these is rejected):",
123
- "- Exactly ONE start node (a node with no incoming edge).",
124
- "- No cycles (except an `end` node's explicit loop).",
125
+ "- No cycles an `end` node's loop settings express a loop, never a back edge.",
125
126
  "- A `condition` node needs exactly one \"yes\" and one \"no\" outgoing edge.",
126
- "- An `end` node needs ≥1 incoming edge.",
127
127
  "- Fill each node's REQUIRED fields (see notes per type).",
128
+ "ALSO: use exactly ONE start node (a node with no incoming edge) and give every `end` node ≥1 incoming edge.",
128
129
  "",
129
130
  "TEMPLATING — chain data between nodes:",
130
131
  "- {{env.KEY}} / {{KEY}} — environment/global variables.",
@@ -1 +1 @@
1
- {"version":3,"file":"scenario.js","sourceRoot":"","sources":["../../../src/ai/prompts/scenario.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"scenario.js","sourceRoot":"","sources":["../../../src/ai/prompts/scenario.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { ScenarioNodeType } from "../../scenario-runner/types.js";
2
+ export interface RenderScenarioNodeReferenceOptions {
3
+ /**
4
+ * The per-type defaults the compact form merges configs over. Default =
5
+ * core's `SCENARIO_NODE_DEFAULT_CONFIGS` (what callman-mcp merges over).
6
+ */
7
+ defaultConfigFor?: (type: string) => unknown;
8
+ }
9
+ /**
10
+ * The scenario node reference for API / MCP clients: the scenario shape, every
11
+ * node type's config fields (type, default, requirement, notes) with a minimal
12
+ * example, and the graph rules the server enforces.
13
+ */
14
+ export declare const renderScenarioNodeReference: (options?: RenderScenarioNodeReferenceOptions) => string;
15
+ export declare const SCENARIO_NODE_REFERENCE_TYPES: readonly ScenarioNodeType[];
16
+ //# sourceMappingURL=scenarioNodeReference.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scenarioNodeReference.d.ts","sourceRoot":"","sources":["../../../src/ai/prompts/scenarioNodeReference.ts"],"names":[],"mappings":"AAmCA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAMvE,MAAM,WAAW,kCAAkC;IACjD;;;OAGG;IACH,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;CAC9C;AAm0BD;;;;GAIG;AACH,eAAO,MAAM,2BAA2B,GACtC,UAAS,kCAAuC,KAC/C,MAsGF,CAAC;AAGF,eAAO,MAAM,6BAA6B,EAAE,SAAS,gBAAgB,EAAoB,CAAC"}