@octaviaflow/flow-rules 0.12.0 → 0.13.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.
@@ -39,6 +39,12 @@ export interface AiAgentConfigType {
39
39
  */
40
40
  input?: string;
41
41
  overrides?: AiAgentOverrides;
42
+ /**
43
+ * Per-row mode only: the most model calls the step may make (one per
44
+ * upstream row). Default 50, at most 1000 — a run with more rows stops
45
+ * before any call (DEV-428).
46
+ */
47
+ maxRows?: number;
42
48
  }
43
49
  export declare const AiAgentConfig: {
44
50
  defaults: AiAgentConfigType;
@@ -58,6 +64,12 @@ export declare const AiAgentConfig: {
58
64
  required: boolean;
59
65
  description: string;
60
66
  };
67
+ maxRows: {
68
+ type: string;
69
+ required: boolean;
70
+ min: number;
71
+ description: string;
72
+ };
61
73
  };
62
74
  validate: (config: Partial<AiAgentConfigType>) => {
63
75
  valid: boolean;
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Aggregate Action — Config Contract
3
+ *
4
+ * Fold the upstream records into ONE row — or one row per group — of computed
5
+ * values. It exists because nothing else could total a column (DEV-422): a
6
+ * Transform maps one record at a time and cannot see the others, and the only
7
+ * built-in sum was ForEach's `collect: 'reduce'`, which reduces loop-body
8
+ * results and is reachable from nowhere an author, or an agent reading
9
+ * `describe_action_type`, would look.
10
+ *
11
+ * Output: `{ data: [ { ...groupKeys, ...metrics } ], _meta }` — the same
12
+ * `data: row[]` envelope Query, Transform and Variables emit, so the Transform
13
+ * after it maps `{{totals[].TotalAmount}}` exactly as it maps a Query's rows.
14
+ *
15
+ * The Engine's `aggregateExecutor.ts` reads this shape; the two stay in step.
16
+ */
17
+ /** The functions a metric can apply. `describe_action_type` lists them. */
18
+ export declare const AGGREGATE_FUNCTIONS: readonly ["sum", "count", "avg", "min", "max", "count_distinct", "first", "last"];
19
+ export type AggregateFn = (typeof AGGREGATE_FUNCTIONS)[number];
20
+ /** What each function computes — the panel's help text and the contract's description. */
21
+ export declare const AGGREGATE_FUNCTION_DESCRIPTIONS: Readonly<Record<AggregateFn, string>>;
22
+ export interface AggregateMetric {
23
+ /** One of `AGGREGATE_FUNCTIONS`. */
24
+ fn: AggregateFn;
25
+ /**
26
+ * The record field it reads — a dot-path such as "Balance" or
27
+ * "CustomerRef.name". `count` may omit it to count records.
28
+ */
29
+ field?: string;
30
+ /** The key the value lands under on the output row. An identifier, unique within the step. */
31
+ as: string;
32
+ /** Round a sum or avg to this many decimal places (0–10). Omit to keep the value as computed. */
33
+ decimals?: number;
34
+ }
35
+ export interface AggregateConfigType {
36
+ /**
37
+ * Which upstream records: a path to an array in the upstream step's output.
38
+ * Empty means the records the previous step produced (its `data`). Resolved
39
+ * exactly as ForEach's `arrayPath`.
40
+ */
41
+ arrayPath?: string;
42
+ /**
43
+ * Record fields (dot-paths) to group by. Empty: one row for all records.
44
+ * Each key lands on the output row under its last segment
45
+ * ("CustomerRef.name" → "name").
46
+ */
47
+ groupBy?: string[];
48
+ /** The values to compute. At least one. */
49
+ metrics: AggregateMetric[];
50
+ /**
51
+ * The name later steps use for this result, e.g. `totals` →
52
+ * `{{totals[].TotalAmount}}`. Defaults to the step's name.
53
+ */
54
+ outputAs?: string;
55
+ /**
56
+ * The output ROW's schema, written by the panel at save time so the picker
57
+ * shows the keys before a run. The Backend contributor derives the same
58
+ * thing from the config with `computeOutputSchema`.
59
+ */
60
+ _outputSchema?: {
61
+ type: 'object';
62
+ properties: Record<string, unknown>;
63
+ };
64
+ }
65
+ /** A JSON-schema-like node, as the DataStream and `_outputSchema` carry it. */
66
+ export interface AggregateSchemaNode {
67
+ type?: string;
68
+ properties?: Record<string, AggregateSchemaNode>;
69
+ items?: AggregateSchemaNode;
70
+ description?: string;
71
+ }
72
+ /**
73
+ * The output key a group-by field lands under: its last path segment, with a
74
+ * trailing `[]` removed. "CustomerRef.name" → "name"; "Region" → "Region".
75
+ * The Engine names the group keys the same way.
76
+ */
77
+ export declare function groupKeyName(path: string): string;
78
+ export declare const AggregateConfig: {
79
+ schema: {
80
+ arrayPath: {
81
+ type: string;
82
+ required: boolean;
83
+ dynamic: boolean;
84
+ description: string;
85
+ };
86
+ groupBy: {
87
+ type: string;
88
+ required: boolean;
89
+ description: string;
90
+ };
91
+ metrics: {
92
+ type: string;
93
+ required: boolean;
94
+ description: string;
95
+ };
96
+ outputAs: {
97
+ type: string;
98
+ required: boolean;
99
+ description: string;
100
+ };
101
+ };
102
+ defaults: AggregateConfigType;
103
+ /**
104
+ * What blocks execution, refused before the run (a 409 on an active flow
105
+ * over MCP, a warning on a draft): no metrics, an unknown function, a
106
+ * function with nothing to read, an output key that is not an identifier or
107
+ * is taken, decimals outside 0–10, an outputAs that is not a single name.
108
+ */
109
+ validate(config: Partial<AggregateConfigType>): {
110
+ valid: boolean;
111
+ errors: string[];
112
+ };
113
+ /**
114
+ * The schema of ONE output row: the group keys (typed from the source record
115
+ * when `source` is known) and each metric under its `as`. The panel writes
116
+ * it to `_outputSchema`; the Backend contributor wraps it as `array<row>` at
117
+ * the step's output path. One implementation, two callers.
118
+ */
119
+ computeOutputSchema(config: Partial<AggregateConfigType>, source?: AggregateSchemaNode): {
120
+ type: "object";
121
+ properties: Record<string, unknown>;
122
+ };
123
+ merge(userConfig: Partial<AggregateConfigType>): AggregateConfigType;
124
+ /** "sum(Balance), count by name" — the node's auto label. */
125
+ getLabel(config: Partial<AggregateConfigType>): string;
126
+ };
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Aggregate Action
3
+ *
4
+ * Totals, counts, averages, min/max, distinct counts and first/last over the
5
+ * upstream records — one output row, or one per group. Sits after the step
6
+ * that produces the rows and before the step that writes the result (the
7
+ * "TOTAL row" case: Query → Transform (insert rows) → Aggregate → Transform
8
+ * (insert one row)). The config contract is `./config.ts` (DEV-422).
9
+ */
10
+ import { ActionDefinition } from '../../types';
11
+ export declare const aggregateDefinition: ActionDefinition;
@@ -16,6 +16,7 @@ import { forEachDefinition } from './logic/for-each';
16
16
  import { groupDefinition } from './logic/group';
17
17
  import { queryDefinition } from './general/query';
18
18
  import { transformDefinition } from './general/transform';
19
+ import { aggregateDefinition } from './general/aggregate';
19
20
  import { csvActionDefinition } from './storage/csv-action';
20
21
  import { jsonActionDefinition } from './storage/json-action';
21
22
  import { xmlActionDefinition } from './storage/xml-action';
@@ -54,4 +55,4 @@ export declare const getActionById: (id: string) => ActionDefinition | undefined
54
55
  * Get actions by category
55
56
  */
56
57
  export declare const getActionsByCategory: (category: ActionCategory) => ActionDefinition[];
57
- export { csvActionDefinition, jsonActionDefinition, xmlActionDefinition, excelActionDefinition, s3ActionDefinition, ftpActionDefinition, googleDriveActionDefinition, dropboxActionDefinition, onedriveActionDefinition, manualTriggerDefinition, scheduleTriggerDefinition, webhookTriggerDefinition, httpRequestDefinition, consoleLogDefinition, delayDefinition, conditionDefinition, forEachDefinition, groupDefinition, queryDefinition, transformDefinition, debugDefinition, errorDefinition, variablesDefinition, graphqlQueryDefinition, emailDefinition, slackMessageDefinition, whatsappSendDefinition, teamsMessageDefinition, googleChatDefinition, webhookCallDefinition, aiAgentDefinition, idpExtractDefinition, };
58
+ export { csvActionDefinition, jsonActionDefinition, xmlActionDefinition, excelActionDefinition, s3ActionDefinition, ftpActionDefinition, googleDriveActionDefinition, dropboxActionDefinition, onedriveActionDefinition, manualTriggerDefinition, scheduleTriggerDefinition, webhookTriggerDefinition, httpRequestDefinition, consoleLogDefinition, delayDefinition, conditionDefinition, forEachDefinition, groupDefinition, queryDefinition, transformDefinition, aggregateDefinition, debugDefinition, errorDefinition, variablesDefinition, graphqlQueryDefinition, emailDefinition, slackMessageDefinition, whatsappSendDefinition, teamsMessageDefinition, googleChatDefinition, webhookCallDefinition, aiAgentDefinition, idpExtractDefinition, };
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Membership test for a readonly string tuple, narrowing the value to the
3
+ * tuple's union. Shared by the contracts that refuse a value outside a fixed
4
+ * set (Transform's mode/operation, Aggregate's function) so each names the
5
+ * allowed values in its message instead of failing at run time.
6
+ */
7
+ export declare const isOneOf: <T extends string>(set: readonly T[], value: unknown) => value is T;
@@ -0,0 +1,26 @@
1
+ /**
2
+ * The shape of ONE record at a path in an upstream step's output — what a
3
+ * step that reads those records sees per row — and the field names it
4
+ * carries. Pure and framework-free, so a panel that picks a record field
5
+ * (Aggregate's group-by and metric fields, DEV-422) offers the fields the
6
+ * Engine's `resolveArrayPath` will actually hand the step.
7
+ *
8
+ * Resolution order mirrors the ForEach panel's source resolution: the
9
+ * upstream node's static schema (`outputSchema`, else the editor's
10
+ * `config._outputSchema`) walked along the path; then the last run's sample
11
+ * output; then the static schema as a whole. Only the first upstream node is
12
+ * consulted — it is the one the step is wired from.
13
+ */
14
+ import { type UpstreamNodeRef } from './pathOptions';
15
+ export interface RecordSchemaLike {
16
+ type?: string;
17
+ properties?: Record<string, any>;
18
+ items?: any;
19
+ }
20
+ export declare function resolveRecordSchema(upstreamNodes: UpstreamNodeRef[] | undefined, arrayPath: string): RecordSchemaLike | undefined;
21
+ /**
22
+ * The field names a record at `arrayPath` carries: the resolved schema's
23
+ * keys, unioned with the ACTUAL keys of the last run's records — live rows
24
+ * can be sparse or carry system fields a describe-derived schema omits.
25
+ */
26
+ export declare function detectRecordFields(upstreamNodes: UpstreamNodeRef[] | undefined, arrayPath: string): string[];
@@ -47,6 +47,7 @@ export declare enum ActionType {
47
47
  SpeechToText = "speech_to_text",
48
48
  TextToSpeech = "text_to_speech",
49
49
  Transform = "transform",
50
+ Aggregate = "aggregate",
50
51
  FileOperation = "file_operation",
51
52
  FileAction = "file_action",
52
53
  CsvAction = "csv_action",