@lotics/cli 0.305.0 → 0.305.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.
- package/AGENTS.md +1 -1
- package/README.md +1 -1
- package/dist/src/cli.js +9 -36
- package/dist/src/client.d.ts +1 -1
- package/docs/data_model.md +1 -2
- package/docs/workflows.md +14 -55
- package/package.json +1 -1
package/dist/src/client.d.ts
CHANGED
|
@@ -119,7 +119,7 @@ export interface ToolExecuteResult {
|
|
|
119
119
|
* failure was not a typed error, and from any server older than it. */
|
|
120
120
|
error_code?: string;
|
|
121
121
|
/** A refused input addressed per field: one sentence from a typed alias, a
|
|
122
|
-
* list from a
|
|
122
|
+
* list from a refusing table check. */
|
|
123
123
|
field_errors?: Record<string, string> | Record<string, string[]>;
|
|
124
124
|
breaking_changes?: readonly ToolBreakingChange[];
|
|
125
125
|
}
|
package/docs/data_model.md
CHANGED
|
@@ -94,8 +94,7 @@ it — and a date column per state holds until something re-enters a state it al
|
|
|
94
94
|
|
|
95
95
|
Measuring time-in-state or conversion needs one ROW per move: a link to the subject, the state left,
|
|
96
96
|
the state entered, when. Hold those states as the source field's own `opt_` keys so the log carries
|
|
97
|
-
no second vocabulary, and write the
|
|
98
|
-
every writer rather than one app's.
|
|
97
|
+
no second vocabulary, and write the row in the workflow that makes the move.
|
|
99
98
|
|
|
100
99
|
## Keep derived chains shallow
|
|
101
100
|
|
package/docs/workflows.md
CHANGED
|
@@ -6,16 +6,13 @@ Only the forms below are accepted; anything else is refused at save with the lin
|
|
|
6
6
|
what to write instead. A save that succeeds may still return `warnings` — advisory hints such as a
|
|
7
7
|
loop that may never end. Read them.
|
|
8
8
|
|
|
9
|
-
The same grammar serves an automation
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
it.
|
|
9
|
+
The same grammar serves an automation and an app's workflow, and the expressions of a table check.
|
|
10
|
+
Only an automation's source opens with a trigger declaration; an app workflow takes its trigger from
|
|
11
|
+
the app that calls it.
|
|
13
12
|
|
|
14
13
|
## Triggers
|
|
15
14
|
|
|
16
|
-
An automation answers an event outside the records: a schedule, a webhook, an inbound email.
|
|
17
|
-
reaction to a record being created, updated or deleted is a table lifecycle workflow (see
|
|
18
|
-
**Table lifecycle workflows**).
|
|
15
|
+
An automation answers an event outside the records: a schedule, a webhook, an inbound email.
|
|
19
16
|
|
|
20
17
|
```
|
|
21
18
|
on({ type: "recurring_schedule", cron_expression: "0 9 * * MON" });
|
|
@@ -70,8 +67,8 @@ connections and the steps each opens.
|
|
|
70
67
|
|
|
71
68
|
`return` is a call, not a JavaScript `return` statement. `validate` ends the workflow with an error
|
|
72
69
|
when a check's `fail_when` is truthy; the check's `field_key` names the control its message lands on —
|
|
73
|
-
in an app workflow a declared input, or the `fld_` key of a field on a table the body names;
|
|
74
|
-
|
|
70
|
+
in an app workflow a declared input, or the `fld_` key of a field on a table the body names; in an
|
|
71
|
+
automation it is not checked.
|
|
75
72
|
|
|
76
73
|
The name in `const x = await tool({...})` is the step's id; later expressions read its output as
|
|
77
74
|
`x.records`, `x.id` and so on. A `// id: my_step` comment directly above a statement sets an explicit
|
|
@@ -95,8 +92,8 @@ Bind it to branch on the decision:
|
|
|
95
92
|
|
|
96
93
|
```
|
|
97
94
|
const approval = await wait_for_approval({
|
|
98
|
-
approvers:
|
|
99
|
-
prompt: `Approve
|
|
95
|
+
approvers: trigger.app_workflow.inputs.approvers,
|
|
96
|
+
prompt: `Approve this quote?`,
|
|
100
97
|
});
|
|
101
98
|
|
|
102
99
|
if (approval.status == "approved") {
|
|
@@ -120,7 +117,7 @@ step — summarize a record, classify, draft text.
|
|
|
120
117
|
|
|
121
118
|
- `instructions` — a fixed string.
|
|
122
119
|
- `input` — an object literal; its fields are expressions, evaluated and handed to the model (`{}` for
|
|
123
|
-
none). It is the ONLY workflow data the agent sees: read
|
|
120
|
+
none). It is the ONLY workflow data the agent sees: read the trigger, prior steps, `runtime` or the loop
|
|
124
121
|
item here, never inside `instructions` or `tools`, which are fixed literals and read no binding.
|
|
125
122
|
- `tools` — the names of the tools it may call.
|
|
126
123
|
- `model` — optional; omit it to follow the platform's default model.
|
|
@@ -141,13 +138,9 @@ Only `x` comes back: in text mode `x` is the string itself, in object mode `x.fi
|
|
|
141
138
|
|
|
142
139
|
## What an expression reads
|
|
143
140
|
|
|
144
|
-
- `record` —
|
|
145
|
-
|
|
146
|
-
- `
|
|
147
|
-
`?.prev_value`, the `?.` required (updates only).
|
|
148
|
-
- `trigger` — what a non-record trigger carries (see **Triggers**). `trigger.data`,
|
|
149
|
-
`trigger.prev_data` and `trigger.changes` are the same three roots spelled long; a saved body reads
|
|
150
|
-
back in the short form.
|
|
141
|
+
- `record`, `prev_record`, `changes` — in a table check, the write it checks (see **Table checks**).
|
|
142
|
+
`changes` is a PARTIAL map: `changes["fld_x"]?.next_value` and `?.prev_value`, the `?.` required.
|
|
143
|
+
- `trigger` — what the trigger carries (see **Triggers**).
|
|
151
144
|
- a loop's item name, and `index`, the iteration's 0-based index.
|
|
152
145
|
- `<step id>` — an earlier step's output (`dup.records`).
|
|
153
146
|
- `runtime.timezone`, `runtime.workflow_id`, `runtime.execution_id`, `runtime.workspace_id`,
|
|
@@ -277,8 +270,9 @@ const found = await query_records({
|
|
|
277
270
|
filters: { node_type: "condition", field_key: "fld_name", operator: "equals", value: "ACME Corp" },
|
|
278
271
|
});
|
|
279
272
|
const customer = first(found.records);
|
|
273
|
+
const order = await get_record({ table_id: "tbl_orders", record_id: trigger.app_workflow.inputs.order_id });
|
|
280
274
|
|
|
281
|
-
if (customer && includes(
|
|
275
|
+
if (customer && includes(order.data["fld_customer"], customer.id)) {
|
|
282
276
|
// …
|
|
283
277
|
}
|
|
284
278
|
```
|
|
@@ -323,41 +317,6 @@ for (let start = 0; start < sheet.row_count; start += 50) {
|
|
|
323
317
|
}
|
|
324
318
|
```
|
|
325
319
|
|
|
326
|
-
## Table lifecycle workflows
|
|
327
|
-
|
|
328
|
-
A lifecycle workflow is bound to one table and one event, and its source has no `on({...})` line:
|
|
329
|
-
|
|
330
|
-
- `after_create` — a create, and a draft's submit (the moment it becomes a record).
|
|
331
|
-
- `after_update` — every field edit, a draft's included.
|
|
332
|
-
- `after_delete`.
|
|
333
|
-
|
|
334
|
-
A lifecycle workflow runs after the write commits, with every step; its errors are logged and never
|
|
335
|
-
fail the write. What refuses a write before it lands is a table check (see **Table
|
|
336
|
-
checks**). An `after_update` workflow that writes its own table saves with a `loop_potential`
|
|
337
|
-
warning: its write fires it again.
|
|
338
|
-
|
|
339
|
-
| reads | on |
|
|
340
|
-
|---|---|
|
|
341
|
-
| `record` | every event — the new record on create, the record as it now stands on update, the deleted record on delete |
|
|
342
|
-
| `prev_record` | updates and deletes — the record before |
|
|
343
|
-
| `changes["fld_x"]?.next_value` / `?.prev_value` | updates — the fields that changed |
|
|
344
|
-
|
|
345
|
-
### Gating with `if_source`
|
|
346
|
-
|
|
347
|
-
`if_source` is one JavaScript expression, reading what the body reads, tested before the workflow
|
|
348
|
-
runs. When it is falsy the workflow does not run at all — no execution, no log. Use it so a workflow
|
|
349
|
-
that cares about some events only skips the rest:
|
|
350
|
-
|
|
351
|
-
- a status reaching an option: `changes["fld_status"]?.next_value == "opt_done"`
|
|
352
|
-
- a field cleared: `isNull(record["fld_assignee"])`
|
|
353
|
-
- a direct write, not a workflow's cascade:
|
|
354
|
-
`includes(["member", "chat_agent", "api_client"], runtime.change_origin.type)` — name every
|
|
355
|
-
direct-write origin rather than testing for one: `member` is a person in the browser, and the same
|
|
356
|
-
edit over MCP, the CLI or the API arrives as `api_client`.
|
|
357
|
-
|
|
358
|
-
In `if_source`, `runtime.change_origin` is the origin of the write that fired it; in the body, it is
|
|
359
|
-
the workflow's own.
|
|
360
|
-
|
|
361
320
|
## Table checks
|
|
362
321
|
|
|
363
322
|
A table check is one condition its table's record writes must not meet, declared beside the table's
|