@flowapt/flowiq-cli 0.9.3 → 0.9.4

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/README.md CHANGED
@@ -1713,7 +1713,7 @@ flowiq agent config <organization_id> --enable-base-tool get_product_info
1713
1713
 
1714
1714
  Settable: `settings.use_settings_prompt`, `settings.model`,
1715
1715
  `settings.reasoning_effort` (`--reasoning-effort low|medium|high|xhigh|max`, `""` clears it —
1716
- pairs with reasoning models like `gpt-5.6-luna`; `max` is Claude only), agent `--rename`,
1716
+ pairs with reasoning models like `gpt-5.6-luna`; `max` is GPT-6 and Claude only), agent `--rename`,
1717
1717
  the tool-flag columns (`woo_order_build`, `woo_tip_field`, `woo_order_note_field`,
1718
1718
  `view_cart_tool`, `restock_tool`, `block_tool_status`, `postal_code_tool_status`,
1719
1719
  `shopify_products_web_chat`, `ticket_tool_status`, `product_lookup`,
@@ -1865,6 +1865,15 @@ flowiq export chats <organization_id> # → ./.flowiq/expor
1865
1865
  flowiq export chats <organization_id> --out ./phyto-chats.txt
1866
1866
  ```
1867
1867
 
1868
+ Pages are 1,000 messages; the server resolves each page's contacts in chunks
1869
+ of 250 ids (fixed 23 Sep 2026: a page of broadcast sends can hold 700+ distinct
1870
+ contacts, and one `in.(…)` list that long was refused by the gateway, which
1871
+ surfaced as `Export failed on page N: contacts resolve failed: Bad Request`).
1872
+ A 502/503/504 on a page is retried twice (v0.9.4); any other failure names the
1873
+ page, how many messages were fetched before it, and that nothing was written,
1874
+ because the file is only opened once every page is in. Re-run it; there is no
1875
+ partial file to clean up.
1876
+
1868
1877
  ### Agent testing — `flowiq test <subcommand>`
1869
1878
 
1870
1879
  Drive an org's **live** agent through the web/test channel and read the reply
package/TEAM-GUIDE.md CHANGED
@@ -193,7 +193,7 @@ several.
193
193
  | See exactly what a change looked like (before → after) | `flowiq audit show <audit_id> --content` (or `--out entry.json`) |
194
194
  | Know what the log does and doesn't keep | Anything that CHANGES something is logged — including `flowiq test` (it creates the test contact and clears conversations) and `flowiq auth refresh`. Reads and dry-runs are not. The log never stores the content itself: chats, store data and agent replies are recorded as "who read what", never copied. |
195
195
  | Read a contact's chat | `flowiq m pull <contact_id>` then open the JSON. Ask for more than exists (`--count 100`) and you get the entire history — it says "that is ALL of them" when there is nothing older |
196
- | Export an org's full chat history | `flowiq export chats <org_id>` |
196
+ | Export an org's full chat history | `flowiq export chats <org_id>`. If it stops mid-way it says which page failed and nothing is written, so just re-run it (a 502/503/504 page retries on its own) |
197
197
  | Check / create WhatsApp templates | `flowiq tpl pull <org_id>` / `flowiq tpl create <org_id> --request-file req.json` |
198
198
  | **Read a template you have not submitted yet (a DRAFT)** | `flowiq tpl show <org_id> <template_name>` — the ONLY way to see a draft from the terminal (`pull` reads Meta, and a draft never gets there). Renders the message as the customer will read it, every carousel card, and a **Checks** list of the things Meta would bounce it for |
199
199
  | Check a carousel before submitting it | `flowiq tpl show <org_id> <name>` and read **Checks**. It catches a card link using the wrong `{{n}}`, a missing greeting example, a bold/italic marker against a space (WhatsApp shows the literal `_`), wrong card counts and over-length text. It cannot know a card names a product you do not stock — read the card text against the shop yourself |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flowapt/flowiq-cli",
3
- "version": "0.9.3",
3
+ "version": "0.9.4",
4
4
  "description": "Command-line tool for FlowIQ staff: round-trip agent prompts, questionnaires, fine-tuning, pin-board tasks, webhooks, templates, agent-updates, chat exports, and live agent testing without ever touching service-role credentials.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -31,6 +31,24 @@ function getSenderLabel(senderType) {
31
31
  return senderType;
32
32
  }
33
33
 
34
+ // A full export is dozens of requests, and one transient 502/503/504 used to
35
+ // throw away every page fetched before it. Those are retried twice; any other
36
+ // failure (a 400, a 500 carrying a real message) fails at once.
37
+ const RETRYABLE = new Set([502, 503, 504]);
38
+ const RETRIES = 2;
39
+
40
+ async function fetchPage(query, pageNo) {
41
+ for (let attempt = 1; ; attempt++) {
42
+ try {
43
+ return await http.get("export-chats", query);
44
+ } catch (e) {
45
+ if (!RETRYABLE.has(e.status) || attempt > RETRIES) throw e;
46
+ console.log(` page ${pageNo}: ${e.message}; retrying (${attempt}/${RETRIES})`);
47
+ await new Promise((resolve) => setTimeout(resolve, 1500 * attempt));
48
+ }
49
+ }
50
+ }
51
+
34
52
  export async function chats(orgId, opts = {}) {
35
53
  if (!UUID_RE.test(orgId)) {
36
54
  console.error(`Error: "${orgId}" is not a valid organization UUID.`);
@@ -52,9 +70,15 @@ export async function chats(orgId, opts = {}) {
52
70
  }
53
71
  let resp;
54
72
  try {
55
- resp = await http.get("export-chats", query);
73
+ resp = await fetchPage(query, pages + 1);
56
74
  } catch (e) {
57
- console.error(`Export failed on page ${pages + 1}: ${e.message}`);
75
+ // The file is only opened once every page is in, so a mid-run failure
76
+ // leaves nothing on disk; say so, and how far it got, in the one line
77
+ // the person will paste into a bug report.
78
+ console.error(
79
+ `Export failed on page ${pages + 1} (${messages.length.toLocaleString("en-US")} messages fetched in ` +
80
+ `${pages} page${pages === 1 ? "" : "s"} before it; nothing written): ${e.message}`,
81
+ );
58
82
  process.exit(1);
59
83
  }
60
84
  if (resp.organization_name != null) organizationName = resp.organization_name;
package/src/index.js CHANGED
@@ -493,7 +493,7 @@ export function run(argv) {
493
493
  .option("--agent <id>", "target a specific agent instead of the org's active one")
494
494
  .option("--use-settings-prompt [bool]", "settings.use_settings_prompt (true if bare)")
495
495
  .option("--model <model>", "settings.model (e.g. gpt-5.4-mini)")
496
- .option("--reasoning-effort <level>", "settings.reasoning_effort — low|medium|high|xhigh|max (\"\" clears it; max = Claude only); pairs with reasoning models (e.g. gpt-5.6-luna + high, claude-sonnet-5 + medium)")
496
+ .option("--reasoning-effort <level>", "settings.reasoning_effort — low|medium|high|xhigh|max (\"\" clears it; max = GPT-6 and Claude only); pairs with reasoning models (e.g. gpt-5.6-luna + high, gpt-6-luna + high, claude-sonnet-5 + medium)")
497
497
  .option("--rename <name>", "rename the agent")
498
498
  .option("--tool <flag=bool>", "toggle a tool flag (repeatable): woo_order_build/woo_tip_field/woo_order_note_field/view_cart_tool/restock_tool/block_tool_status/postal_code_tool_status/shopify_products_web_chat/ticket_tool_status/product_lookup/email_request_tool/collapse_product_variants", agentConfigCmd.collectTool, [])
499
499
  .option("--discount [bool]", "agent.discount.enabled (true if bare)")