import { ExecutionType } from './rules.type'; export type ConditionValueType = 'float' | 'integer' | 'string'; /** ClickHouse metric tables the CMS evaluator resolves condition fields from. * Mirrors the L1–L3a tables in `eaera_mt5/models` + the `deal` table. */ export type ConditionTable = 'account_state' | 'account_metric_by_deal' | 'account_symbol_metric_by_deal' | 'account_metric_daily' | 'position_metric_by_deal' | 'deal'; export interface ConditionField { /** Backend key, e.g. `account_state.equity`. */ key: string; /** Human label, e.g. `Account Equity`. */ label: string; table: ConditionTable; column: string; valueType: ConditionValueType; description: string; unit: string; } export declare const CONDITION_FIELDS: readonly ConditionField[]; /** Comparison operators the condition builder emits into `trigger.conditions[]`. * * These are the **word forms** the CMS condition evaluator expects on the wire * (`eaera_cms/core/rules/conditions.py:_apply_operator`). The evaluator also * accepts the JSON-Logic symbol aliases (`==`, `!=`, `>`, `>=`, `<`, `<=`), * but the canonical contract uses the word forms — see the FEAT-006 testing * guide and `risk-rules-api-guide.md` §4.E.a. * * Operator kind, per the backend `value` semantics: * - `gt`, `gte`, `lt`, `lte` — numeric (`account_state.*`, * `account_metric_by_deal.*`) * - `eq`, `ne` — any (string / number / boolean) * - `in`, `not_in` — value MUST be a JSON list * - `contains`, `startswith`, `endswith` — string substring/affix; * backend coerces entity via `str()` * - `is_null`, `is_not_null` — `value` is IGNORED by the backend; * UI should hide the value input * - `sum_within_days` — CH-windowed SUM; carries a sibling * `days` window (defaults to 30). * Special — see {@link SUM_WITHIN_DAYS} * constant; not in {@link CONDITION_OPERATORS}. * * The UI renders the friendlier symbol for the 6 numeric word-forms via * {@link CONDITION_OPERATOR_LABELS}; the others have explicit text labels * (see {@link CONDITION_OPERATOR_LABELS} + {@link CONDITION_OPERATOR_LABELS_TEXT}). */ export declare const CONDITION_OPERATORS: readonly ["gt", "gte", "lt", "lte", "eq", "ne", "in", "not_in", "contains", "startswith", "endswith", "is_null", "is_not_null"]; export type ConditionOperator = (typeof CONDITION_OPERATORS)[number]; /** The CH-windowed SUM operator — special, NOT a member of * {@link CONDITION_OPERATORS} because it carries a sibling `days` key. * Authored through the rule YAML/expression path or directly via the API. * The dashboard does not surface this in the standard operator dropdown. */ export declare const SUM_WITHIN_DAYS: "sum_within_days"; export type SumWithinDaysOperator = typeof SUM_WITHIN_DAYS; /** Symbol label shown in the UI for each numeric word-form operator. */ export declare const CONDITION_OPERATOR_LABELS: Record; /** Per-operator value-type metadata. Drives the dashboard's value-input widget: * - `number` → numeric input * - `string` → single-line text input (substrings/affixes) * - `list` → JSON-array editor (CSV/JSON toggle recommended) * - `none` → value is ignored by the backend; UI should hide the input */ export type ConditionOperatorValueKind = 'number' | 'string' | 'list' | 'none'; export declare const CONDITION_OPERATOR_VALUE_KINDS: Record; /** Symbol form → word form. The backend accepts both on the wire; the dashboard * canonicalises to the word form on save and on load (`useRuleBuilder` * `_normalizeOperator`). */ export declare const CONDITION_OPERATOR_SYMBOL_TO_WORD: Record; /** Normalise any operator string (symbol, word, or unknown) to a word form. * Unknown inputs are returned as-is so the backend's `eq`-fallback semantics * remain the source of truth. */ export declare const normalizeConditionOperator: (raw: unknown) => string; /** * Allowed MT5 leverage values for the `change_leverage` action. MT5 accepts a * constrained integer set; the rule builder offers these as a select rather * than a free-text input. The MT5 worker coerces the value to a positive int * (`worker/tasks/dispatcher.py:_change_leverage`); this list mirrors the * common broker-configured leverages. */ export declare const LEVERAGE_OPTIONS: readonly [1, 5, 10, 20, 25, 30, 40, 50, 100, 200, 300, 400, 500, 1000]; export type LeverageOption = (typeof LEVERAGE_OPTIONS)[number]; /** * Builder action kinds → CMS action wiring. The fixed-rule action chain maps * a UI `kind` to its `actionName` + nested `params` key. Kept here so the FE * serializer (and the docs) stay in sync with the worker dispatcher contract. * * Specialized kinds (`move`, `leverage`, `tag`, `setField`) have dedicated UI * inputs. The `custom` kind is a fallback for any action not in this list — it * renders the `actionName` as read-only and exposes raw `params` as JSON. */ /** Value-level constants for action kinds — single source of truth. */ export declare const ACTION_KIND: { readonly MOVE: "move"; readonly LEVERAGE: "leverage"; readonly TAG: "tag"; readonly SET_FIELD: "setField"; readonly DISABLE_TRADE: "disableTrade"; readonly ENABLE_TRADE: "enableTrade"; readonly GENERATE_REPORT: "generateReport"; readonly GENERATE_AI_SUMMARY: "generateAiSummary"; readonly PROVISION_USER: "provisionUser"; readonly CUSTOM: "custom"; }; /** Action kind type — derived from {@link ACTION_KIND}. */ export type RuleActionKind = (typeof ACTION_KIND)[keyof typeof ACTION_KIND]; export interface ActionKindDef { kind: RuleActionKind; actionName: string; /** Nested `params` key the worker dispatcher reads (camelCase; the CMS * casing middleware converts to snake_case before the worker sees it). */ paramKey?: string; /** Default codeRef (pack handler path) for actions that require one. */ defaultCodeRef?: string; /** Human label shown in the UI kind selector. */ label: string; } export declare const ACTION_KINDS: readonly ActionKindDef[]; /** Lookup an ActionKindDef by backend actionName. Returns undefined for unknown names. */ export declare const actionDefByActionName: (actionName: string) => ActionKindDef | undefined; /** Per-action `result.output` field shapes — the authoritative reference for * what the CMS completion handler stores at `execution.result.output` after a * successful action. * * When the history/detection feeds fetch with `?exclude_params=true`, the * `params` JSONB is dropped entirely. The dashboard reads action details from * `result.output` (and `operationName`) instead. This map tells the dashboard * which keys to expect per action. * * Source: `eaera-mt5/worker/tasks/dispatcher.py` (worker return shape) + * `eaera-mt5/eaera_mt5/handlers/*.py` (handler ActionResult.output) + * `eaera-cms/eaera_cms/core/content/completion.py:427` * (`execution.result = {"success": True, "output": res.output}`). * * Each entry lists the keys the output dict carries. The values are always * primitives (string / number / boolean / string[]). */ export interface ActionResultField { /** Key in `result.output`. */ key: string; /** Human label. */ label: string; /** Value type. */ type: 'string' | 'number' | 'boolean' | 'string[]'; } export declare const ACTION_RESULT_FIELDS: Record; /** Extract a flat `{key: value}` dict from `result.output` for a given action. * Returns `{}` when output is missing or not an object. */ export declare const resultOutputOf: (result: Record | null | undefined, actionName: string) => Record; /** Lookup an ActionKindDef by UI kind. Returns undefined for 'custom'. */ export declare const actionDefByKind: (kind: RuleActionKind) => ActionKindDef | undefined; /** FE-only action step view-model. The single canonical shape used by both * the Fixed Rules editor and the LLM-rule (skill) editor. The dashboard * imports this from the SDK so the two editors serialize identically and * never diverge on what an action looks like. */ export interface RuleActionView { /** Local UI key — never sent to the backend. */ id: string; /** FE-only action kind; maps 1:1 to {@link RuleActionKind}. */ kind: RuleActionKind; /** Target group for `kind === 'move'`. */ targetGroup?: string; /** Tags array for `kind === 'tag'`. */ tags?: string[]; /** Tag mode for `kind === 'tag'`. */ tagMode?: 'append' | 'replace' | 'remove'; /** Field name for `kind === 'setField'` / `kind === 'provisionUser'`. */ field?: string; /** Value for `kind === 'leverage'` (numeric) or `kind === 'setField'` * (stringified). */ value?: number | string; /** Report period start (ISO `YYYY-MM-DD`) for `kind === 'generateReport'`. */ dateFrom?: string; /** Report period end (ISO `YYYY-MM-DD`) for `kind === 'generateReport'`. */ dateTo?: string; /** Reason string for `kind === 'disableTrade' | 'enableTrade'`. */ reason?: string; /** Backend actionName — auto-populated for specialized kinds; required for `custom`. */ actionName?: string; /** Backend codeRef (handler path). Preserved on load, emitted on save. */ codeRef?: string; /** Raw params object — used by `custom` and preserved for round-tripping. */ params?: Record; } /** Serialize the per-kind `params` payload for the CMS dispatcher. * Mirrors the historical `useRuleBuilder._serializeActionParams`. * * Critical contract: * - The dispatcher passes `params` through `ctx.data` to the worker handler. * - The MT5 worker reads snake_case keys (`from_time`, `new_group`, * `new_leverage`, …) and the CMS casing middleware converts our * camelCase keys to snake_case on the way in. * - Empty / zero required fields are omitted so the worker doesn't pick * up its default-0 placeholder and silently fail. The rule can be * saved with empty inputs; the action will then fail gracefully at * fire time with a clear error. * - Do NOT emit `login` / `serverName` placeholders — the runtime context * (trigger event or fire payload) carries those. */ export declare const serializeActionParams: (action: RuleActionView) => Record; /** Serialize a single action view into the CMS wire shape * `{ actionName, codeRef?, params }` — used for both single-step and chain * rule executionParams. */ export declare const serializeAction: (action: RuleActionView) => { actionName: string; codeRef?: string; params: Record; }; /** Build the `executionParams` payload from a list of actions. * * - 0 actions → `executionType: 'action'` with empty params. * - 1 action, kind `SET_FIELD` → `executionType: 'set_field'` with * `executionParams: { field, value }`. The CMS dispatcher (`_dispatch_target`'s * `set_field` branch) only takes this dedicated path — emitting it as a * plain `action` would land on the action-executor path, which requires a * `code_ref` that `set_field` does not have. * - 1 action, any other kind → `executionType: 'action'` with the * `serializeAction(...)` shape (actionName + optional codeRef + params). * - 2+ actions → `executionType: 'chain'` with `executionParams.steps[]`. */ export declare const actionsToExecutionParams: (actions: RuleActionView[]) => { executionType: ExecutionType; executionParams: Record; }; /** Read the action list back from a stored `ContentRule.executionParams`. * Supports `set_field`, single-step `action`, and multi-step `chain` * payloads. */ export declare const actionsFromExecution: (rule: { executionType: ExecutionType | string; executionParams?: Record | null; }) => RuleActionView[]; /** * Event-payload fields for `triggerType === 'event'` rules. The CMS * condition evaluator resolves dotted paths from the Kafka event payload * (`event.data.*`) with a fallback to flat fields * (`eaera_cms/core/rules/conditions.py:_resolve_field`). These are NOT * ClickHouse metric fields — they come from the event itself. * * The dashboard tree builder emits these verbatim so the engine can resolve * them at fire time. Source: `eaera-mt5/reference-v0/ch/ddl.py` payload * schemas + `eaera-mt5/worker/tasks/realtime.py` event shapes. */ /** Top-level key of the event payload each field belongs to. */ export declare const EVENT_PAYLOAD_SOURCE: { readonly DEAL: "deal"; readonly POSITION: "position"; readonly ORDER: "order"; }; export type EventPayloadSource = (typeof EVENT_PAYLOAD_SOURCE)[keyof typeof EVENT_PAYLOAD_SOURCE]; export interface EventPayloadField { /** Backend dotted-path key, e.g. `deal.profit`. */ key: string; /** Human label, e.g. `Deal Profit`. */ label: string; /** Which event payload this field is sourced from. */ source: EventPayloadSource; valueType: ConditionValueType; unit: string; } export declare const EVENT_PAYLOAD_FIELDS: readonly EventPayloadField[]; /** * Filter the event-payload catalog to a subset appropriate for an event type. * The dashboard uses this to narrow the metric dropdown so a `deal_close` * rule can only select `deal.*` fields, etc. Returns all fields if the event * type doesn't have a known narrowing (e.g. `statement` falls back to CH * catalog fields). */ export declare const eventPayloadFieldsFor: (_eventType: string | null | undefined) => readonly EventPayloadField[]; //# sourceMappingURL=conditions.d.ts.map