@botpress/adk-cli 1.19.0-beta.3 → 1.19.0-beta.5

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 (81) hide show
  1. package/assets/ui-dist/assets/{index-CSTz-oTK.js → index-B3b7PPgV.js} +4 -4
  2. package/{dist/index-DNqXHLNi-27nvpkee.js → assets/ui-dist/assets/index-BESZeTO5.js} +2 -2
  3. package/{dist/index-DAztRXeA-vr85xnxs.css → assets/ui-dist/assets/index-DIFGtVmI.css} +1 -1
  4. package/{dist/index-DfjXY3Oo-szsanhnt.js → assets/ui-dist/assets/index-a3ZL0_Jr.js} +2 -2
  5. package/assets/ui-dist/index.html +2 -2
  6. package/dist/{README-wjb7z7f0.md → README-824wa4jj.md} +1 -1
  7. package/dist/SKILL-75ym6tcj.md +257 -0
  8. package/dist/SKILL-chnwzmt1.md +548 -0
  9. package/dist/SKILL-d4bs53y3.md +244 -0
  10. package/dist/SKILL-h4b2f1n9.md +114 -0
  11. package/dist/SKILL-hbw5nt95.md +111 -0
  12. package/dist/actions-h7hxxvxr.md +823 -0
  13. package/dist/adk-build-emhwd0tg.md +39 -0
  14. package/dist/adk-debug-yrrdtpmb.md +23 -0
  15. package/dist/adk-dev-console-7z9rtjpy.md +17 -0
  16. package/dist/adk-document-ras6zzzh.md +68 -0
  17. package/dist/adk-eval-vx76dwq0.md +17 -0
  18. package/dist/adk-explain-fcsaw852.md +22 -0
  19. package/dist/adk-init-9kmxmbbe.md +30 -0
  20. package/dist/adk-ship-dybzn884.md +29 -0
  21. package/dist/adk-test-xq67savs.md +27 -0
  22. package/dist/adk-validate-1p4skv4m.md +31 -0
  23. package/dist/advanced-patterns-z86m9h1a.md +669 -0
  24. package/dist/agent-config-1aqvkrgf.md +450 -0
  25. package/dist/agent-steps-zj4c1n9t.md +115 -0
  26. package/dist/agent0-assets/skills/adk/SKILL.md +5 -5
  27. package/dist/agent0-assets/skills/adk/references/cli.md +265 -24
  28. package/dist/agent0-assets/skills/adk-debugger/SKILL.md +5 -5
  29. package/dist/agent0-assets/skills/adk-debugger/references/common-failures.md +1 -1
  30. package/dist/agent0-assets/skills/adk-debugger/references/debug-workflow.md +3 -3
  31. package/dist/agent0-assets/skills/adk-debugger/references/traces-and-logs.md +15 -7
  32. package/dist/assets-q7jt8r2q.md +237 -0
  33. package/dist/autonomous-execution-fymc12e5.md +747 -0
  34. package/dist/cli-c31e06yr.md +1334 -0
  35. package/dist/cli.js +963 -548
  36. package/dist/commands.json +24 -3
  37. package/dist/common-failures-ht29w2db.md +231 -0
  38. package/dist/component-registry-bbpw0see.md +43 -0
  39. package/dist/context-api-760cvh0h.md +461 -0
  40. package/dist/conversation-analysis-8ka4nrm4.md +420 -0
  41. package/dist/conversation-lifecycle-4seqqjc1.md +311 -0
  42. package/dist/conversations-gwfvxaee.md +1111 -0
  43. package/dist/custom-components-y5wdgpey.md +167 -0
  44. package/dist/debug-workflow-vz84q80v.md +239 -0
  45. package/dist/desk-k54ktvsd.md +852 -0
  46. package/dist/doc-standards-ck6ax2jd.md +124 -0
  47. package/dist/eval-format-7n9brja4.md +354 -0
  48. package/dist/evals-y1zcr1mc.md +11 -0
  49. package/dist/explain-config-1yaq3zzd.md +424 -0
  50. package/dist/files-dzt0wxn3.md +918 -0
  51. package/dist/{index-gqxgqnyz.html → index-3t354nbw.html} +2 -2
  52. package/dist/{index-CSTz-oTK-mdfh47r8.js → index-B3b7PPgV-zetkb01w.js} +4 -4
  53. package/{assets/ui-dist/assets/index-DNqXHLNi.js → dist/index-BESZeTO5-2rpmcefa.js} +2 -2
  54. package/{assets/ui-dist/assets/index-DAztRXeA.css → dist/index-DIFGtVmI-d4dhjg97.css} +1 -1
  55. package/{assets/ui-dist/assets/index-DfjXY3Oo.js → dist/index-a3ZL0_Jr-q145h35p.js} +2 -2
  56. package/dist/integration-actions-xang7tma.md +659 -0
  57. package/dist/integrations-k5ss07f4.md +266 -0
  58. package/dist/interfaces-6t0bpxs4.md +97 -0
  59. package/dist/knowledge-bases-20rg8p5c.md +456 -0
  60. package/dist/llm-debugging-76ng8rzm.md +209 -0
  61. package/dist/mcp-server-n1asyzhv.md +112 -0
  62. package/dist/messages-gkkg0b54.md +769 -0
  63. package/dist/model-configuration-f273kgd0.md +201 -0
  64. package/dist/multi-agent-dashboard-1mdfjdts.md +70 -0
  65. package/dist/pages-xn18xn73.md +273 -0
  66. package/dist/patterns-mistakes-5vb99dhf.md +469 -0
  67. package/dist/plugins-ttnx8f49.md +280 -0
  68. package/dist/tables-x45t36dd.md +1136 -0
  69. package/dist/tags-46td3qrg.md +516 -0
  70. package/dist/test-patterns-hj47w4nc.md +355 -0
  71. package/dist/testing-workflow-2vkp932f.md +225 -0
  72. package/dist/tools-wk7bq24z.md +581 -0
  73. package/dist/trace-summarization-hdyx1c2e.md +313 -0
  74. package/dist/traces-and-logs-f2kjfh19.md +203 -0
  75. package/dist/triggers-4j2cc86x.md +719 -0
  76. package/dist/ui-server-entry.js +977 -162
  77. package/dist/workflow-steps-mrdrf1c5.md +851 -0
  78. package/dist/workflows-gadx3s69.md +1408 -0
  79. package/dist/zai-agent-reference-e6644aad.md +454 -0
  80. package/dist/zai-complete-guide-mnna5d6f.md +1408 -0
  81. package/package.json +4 -4
@@ -0,0 +1,311 @@
1
+ # Conversation Lifecycle (Nudge / Expiration)
2
+
3
+ The lifecycle system lets conversations re-engage idle users (nudge) and clean up stale sessions (expiration). It is an opt-in feature configured per conversation via the `lifecycle` property.
4
+
5
+ For basic conversation setup, channel routing, and handler parameters, see **[conversations.md](./conversations.md)**.
6
+
7
+ ## Enabling Lifecycle
8
+
9
+ Add a `lifecycle` object to any Conversation definition. Durations use `ms`-compatible strings (`"30s"`, `"5m"`, `"1h"`, `"1d"`).
10
+
11
+ ```typescript
12
+ import { Conversation, z } from "@botpress/runtime";
13
+
14
+ export const Chat = new Conversation({
15
+ channel: "webchat.channel",
16
+
17
+ lifecycle: {
18
+ nudge: {
19
+ after: "5m", // First nudge fires 5 min after last user message
20
+ interval: "10m", // Subsequent nudges fire every 10 min
21
+ max: 3, // Stop after 3 nudges (omit for unlimited)
22
+ },
23
+ expire: {
24
+ after: "1h", // Session expires 1 hour after last user message
25
+ },
26
+ },
27
+
28
+ state: z.object({
29
+ topic: z.string().optional(),
30
+ }),
31
+
32
+ handler: async (props) => {
33
+ // handler receives nudge and expire events alongside regular messages
34
+ },
35
+ });
36
+ ```
37
+
38
+ ### Configuration Fields
39
+
40
+ | Field | Type | Required | Description |
41
+ |-------|------|----------|-------------|
42
+ | `nudge.after` | `string` | Yes (if nudge) | Duration of silence before the first nudge fires |
43
+ | `nudge.interval` | `string` | No | Duration between subsequent nudges. Defaults to `nudge.after` |
44
+ | `nudge.max` | `number` | No | Max nudges per session. Must be a positive integer. Omit for unlimited |
45
+ | `expire.after` | `string` | Yes (if expire) | Duration of silence before the session expires |
46
+
47
+ Nudge and expire are independent -- you can configure either or both.
48
+
49
+ ## Handler Types
50
+
51
+ When lifecycle is enabled, the conversation handler receives two additional event types: `"nudge"` and `"expire"`. Discriminate using the `type` parameter.
52
+
53
+ ```typescript
54
+ handler: async ({ type, conversation, state, execute }) => {
55
+ if (type === "nudge") {
56
+ // User has been silent -- send a re-engagement message
57
+ await conversation.send({
58
+ type: "text",
59
+ payload: { text: "Still there? Let me know if you need anything." },
60
+ });
61
+ return;
62
+ }
63
+
64
+ if (type === "expire") {
65
+ // Session is about to be torn down -- send a farewell
66
+ await conversation.send({
67
+ type: "text",
68
+ payload: { text: "This session has expired. Send a new message to start fresh." },
69
+ });
70
+ // After the handler returns, the runtime automatically:
71
+ // 1. Cancels all active workflows on the conversation
72
+ // 2. Tags the conversation with sessionExpired = "true"
73
+ // 3. Resets conversation state to defaults
74
+ // 4. Clears the transcript
75
+ // 5. Sets lifecycle status to "expired"
76
+ return;
77
+ }
78
+
79
+ if (type === "message") {
80
+ // Normal message handling
81
+ await execute({
82
+ instructions: "You are a helpful assistant",
83
+ });
84
+ }
85
+ }
86
+ ```
87
+
88
+ ### Handler Props by Type
89
+
90
+ When `type === "nudge"`:
91
+ - `event` is typed as `LifecycleNudgeEventType` with payload `{ conversationId, sessionId, scheduledAt }`
92
+ - `message` is `undefined`
93
+
94
+ When `type === "expire"`:
95
+ - `event` is typed as `LifecycleExpireEventType` with payload `{ conversationId, sessionId, scheduledAt }`
96
+ - `message` is `undefined`
97
+
98
+ All other handler props (`conversation`, `state`, `execute`, `client`, `chat`) are available as normal. The `chat` prop provides access to transcript and message operations within the conversation (e.g., `chat.fetchTranscript()`, `chat.clearTranscript()`, `chat.saveTranscript()`).
99
+
100
+ ## Session Object
101
+
102
+ Lifecycle-enabled conversations expose a read-only `conversation.session` property:
103
+
104
+ ```typescript
105
+ handler: async ({ type, conversation }) => {
106
+ const session = conversation.session;
107
+ if (!session) return; // undefined when lifecycle is not configured
108
+
109
+ console.log(session.id); // ULID identifying the current session
110
+ console.log(session.number); // Monotonically increasing (1, 2, 3...)
111
+ console.log(session.status); // "active" or "expired"
112
+ console.log(session.startedAt); // ISO timestamp
113
+ console.log(session.lastActivityAt); // ISO timestamp of last user message
114
+ console.log(session.nudgeCount); // Number of nudges fired this session
115
+ }
116
+ ```
117
+
118
+ ### Session Fields
119
+
120
+ | Field | Type | Description |
121
+ |-------|------|-------------|
122
+ | `id` | `string` | ULID unique to the current session |
123
+ | `number` | `number` | Session counter, increments on each expiration (starts at 1) |
124
+ | `status` | `"active" \| "expired"` | Current session status |
125
+ | `startedAt` | `string` | ISO timestamp when this session began |
126
+ | `lastActivityAt` | `string` | ISO timestamp of the last user message |
127
+ | `nudgeCount` | `number` | Number of nudges delivered in this session |
128
+
129
+ ## How Timers Work
130
+
131
+ Understanding the timer lifecycle is important for building correct nudge/expire logic.
132
+
133
+ ### On Every User Message
134
+
135
+ 1. `lastActivityAt` is updated to now
136
+ 2. `nudgeCount` resets to 0
137
+ 3. Any pending nudge and expire scheduled events are cancelled
138
+ 4. New nudge and expire events are scheduled based on the configured delays
139
+
140
+ This means every user message resets the clock. Timers always measure silence from the most recent message.
141
+
142
+ ### On Nudge Event
143
+
144
+ 1. **Race guard**: If `lastActivityAt > scheduledAt`, the nudge is silently dropped (a message arrived after the nudge was scheduled)
145
+ 2. **Workflow suppression**: If any active workflows exist on the conversation (`pending`, `in_progress`, `listening`, `paused`), the nudge is silently rescheduled at `intervalMs` and skipped
146
+ 3. `nudgeCount` increments
147
+ 4. The user's handler runs
148
+ 5. If `nudgeCount < max` (or no max), the next nudge is scheduled at `intervalMs`
149
+
150
+ ### On Expire Event
151
+
152
+ 1. **Race guard**: If `lastActivityAt > scheduledAt`, the expire is silently dropped
153
+ 2. The user's handler runs (errors are caught -- expiration cleanup always proceeds)
154
+ 3. **Hard-kill expiration sequence** (strict ordering):
155
+ - Cancel all active workflows on the conversation
156
+ - Tag conversation with `sessionExpired = "true"`
157
+ - Reset conversation state to defaults (empty object)
158
+ - Clear the transcript
159
+ - Set lifecycle status to `"expired"`
160
+
161
+ ### Session Renewal
162
+
163
+ When a message arrives on an expired session:
164
+ 1. A new `sessionId` (ULID) is generated
165
+ 2. `sessionNumber` increments
166
+ 3. `nudgeCount` resets to 0
167
+ 4. `status` becomes `"active"`
168
+ 5. `startedAt` and `lastActivityAt` update to now
169
+ 6. The `sessionExpired` conversation tag is cleared
170
+ 7. New timers are scheduled
171
+
172
+ ## Built-in Tags
173
+
174
+ Lifecycle automatically manages these tags without any user configuration:
175
+
176
+ ### Conversation Tags
177
+
178
+ | Tag | Description |
179
+ |-----|-------------|
180
+ | `sessionExpired` | Set to `"true"` when a session expires. Cleared on renewal |
181
+
182
+ ### Message Tags
183
+
184
+ | Tag | Description |
185
+ |-----|-------------|
186
+ | `sessionId` | ULID of the session this message belongs to |
187
+ | `sessionNumber` | Session sequence number at the time the message was sent |
188
+
189
+ Message tags are applied automatically to both incoming user messages and outgoing bot messages. They enable grouping messages by session.
190
+
191
+ ## Internal State Namespace
192
+
193
+ Lifecycle state is managed by the runtime in a separate internal state namespace, not in the user-facing conversation state. This means:
194
+
195
+ - Lifecycle state survives conversation state resets (which happen on expiration)
196
+ - You cannot accidentally overwrite lifecycle fields by mutating `state`
197
+ - The `conversation.session` property is the intended read-only interface for accessing lifecycle data -- use it instead of attempting to access internal state directly
198
+
199
+ ## Common Patterns
200
+
201
+ ### Escalating Nudge Messages
202
+
203
+ Use `conversation.session.nudgeCount` to vary the message urgency:
204
+
205
+ ```typescript
206
+ handler: async ({ type, conversation }) => {
207
+ if (type === "nudge") {
208
+ const count = conversation.session?.nudgeCount ?? 0;
209
+
210
+ if (count === 1) {
211
+ await conversation.send({
212
+ type: "text",
213
+ payload: { text: "Just checking in -- do you still need help?" },
214
+ });
215
+ } else if (count === 2) {
216
+ await conversation.send({
217
+ type: "text",
218
+ payload: { text: "I'm still here if you need me." },
219
+ });
220
+ } else {
221
+ await conversation.send({
222
+ type: "text",
223
+ payload: { text: "This conversation will expire soon if there's no activity." },
224
+ });
225
+ }
226
+ return;
227
+ }
228
+ // ... handle messages
229
+ }
230
+ ```
231
+
232
+ ### Expire with Summary
233
+
234
+ Send a session summary before the session is torn down:
235
+
236
+ ```typescript
237
+ handler: async ({ type, conversation, state, execute }) => {
238
+ if (type === "expire") {
239
+ if (state.topic) {
240
+ await conversation.send({
241
+ type: "text",
242
+ payload: {
243
+ text: `Session expired. You were working on: ${state.topic}. Send a message to start a new session.`,
244
+ },
245
+ });
246
+ }
247
+ // State will be reset after this handler returns
248
+ return;
249
+ }
250
+ // ... handle messages
251
+ }
252
+ ```
253
+
254
+ ### Nudge-Only (No Expiration)
255
+
256
+ You can configure nudges without expiration:
257
+
258
+ ```typescript
259
+ lifecycle: {
260
+ nudge: {
261
+ after: "3m",
262
+ max: 2,
263
+ },
264
+ // no expire -- sessions stay active indefinitely
265
+ },
266
+ ```
267
+
268
+ ### Expire-Only (No Nudges)
269
+
270
+ You can configure expiration without nudges:
271
+
272
+ ```typescript
273
+ lifecycle: {
274
+ // no nudge -- no re-engagement messages
275
+ expire: {
276
+ after: "30m",
277
+ },
278
+ },
279
+ ```
280
+
281
+ ## Pitfalls
282
+
283
+ ### Nudges Do Not Fire During Active Workflows
284
+
285
+ If a workflow is running on the conversation (status `pending`, `in_progress`, `listening`, or `paused`), nudges are silently suppressed and rescheduled. This prevents the bot from sending "Are you still there?" while a workflow is actively processing. The check is fail-closed: if the workflow status query fails, the nudge is suppressed. See [workflow-steps.md](./workflow-steps.md) for the step methods that put workflows into these statuses.
286
+
287
+ ### Expire Handler Errors Do Not Block Cleanup
288
+
289
+ If the expire handler throws, the error is caught and the expiration sequence still runs (workflow cancellation, state reset, transcript clear). The error is re-thrown after cleanup completes. Do not rely on throwing in the expire handler to prevent expiration.
290
+
291
+ ### State Is Reset on Expiration
292
+
293
+ After expiration, conversation state is reset to defaults (the empty object triggers schema defaults on the next load). Any data you need to survive across sessions must be stored elsewhere (user state, bot state, or tables).
294
+
295
+ ### Typing Indicators Are Suppressed for Lifecycle Events
296
+
297
+ The runtime does not show typing indicators for nudge or expire events. This is intentional -- lifecycle events should feel automatic, not like the bot is "thinking."
298
+
299
+ ### Timer Scheduling Failures Are Non-Fatal
300
+
301
+ If the runtime fails to schedule a nudge or expire event (e.g., API error), it logs a warning but does not crash the handler. The next user message will attempt to schedule new timers.
302
+
303
+ ### Race Guards Prevent Stale Events
304
+
305
+ Both nudge and expire events carry a `scheduledAt` timestamp. If a user message arrived after the event was scheduled (i.e., `lastActivityAt > scheduledAt`), the event is silently dropped. This prevents stale timers from firing after the user has already re-engaged.
306
+
307
+ ## See Also
308
+
309
+ - [Conversations](./conversations.md) — Conversation setup, channel routing, and handler parameters
310
+ - [Workflows](./workflows.md) — Workflow basics and how workflows interact with conversations
311
+ - [Workflow Steps](./workflow-steps.md) — Step methods whose statuses affect nudge suppression