nardial 0.3.2__tar.gz → 0.4.1__tar.gz
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.
- {nardial-0.3.2 → nardial-0.4.1}/PKG-INFO +265 -33
- {nardial-0.3.2 → nardial-0.4.1}/README.md +263 -31
- {nardial-0.3.2 → nardial-0.4.1}/pyproject.toml +3 -2
- nardial-0.4.1/src/nardial/agenda/__init__.py +0 -0
- nardial-0.4.1/src/nardial/agenda/items.py +239 -0
- nardial-0.4.1/src/nardial/agenda/resolver.py +59 -0
- nardial-0.4.1/src/nardial/agenda/session_plan.py +95 -0
- nardial-0.4.1/src/nardial/agenda/slot_bounds.py +48 -0
- nardial-0.4.1/src/nardial/authoring/__init__.py +1 -0
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial/authoring/factory.py +146 -116
- nardial-0.4.1/src/nardial/authoring/loader.py +138 -0
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial/conversation_agent.py +1 -1
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial/conversation_state.py +91 -0
- nardial-0.4.1/src/nardial/dialog_registry.py +63 -0
- nardial-0.4.1/src/nardial/dialog_types.py +50 -0
- nardial-0.4.1/src/nardial/eligibility.py +205 -0
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial/interaction_orchestrator.py +2 -0
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial/mini_dialogs.py +454 -33
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial/moves.py +159 -5
- nardial-0.4.1/src/nardial/providers/device/reachy_mini.py +52 -0
- nardial-0.4.1/src/nardial/providers/nlu/whisper.py +54 -0
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial/providers/screen/pepper_tablet.py +0 -4
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial/providers/screen/web/static/screen.js +1 -1
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial/providers/tts/elevenlabs.py +1 -1
- nardial-0.4.1/src/nardial/session_manager.py +365 -0
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial.egg-info/PKG-INFO +265 -33
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial.egg-info/SOURCES.txt +20 -2
- nardial-0.4.1/tests/test_agenda_items.py +327 -0
- nardial-0.4.1/tests/test_agenda_resolver.py +73 -0
- {nardial-0.3.2 → nardial-0.4.1}/tests/test_authoring_factory.py +46 -0
- nardial-0.4.1/tests/test_conversation_state.py +156 -0
- nardial-0.4.1/tests/test_dialog_registry.py +89 -0
- nardial-0.4.1/tests/test_dialog_types.py +150 -0
- nardial-0.4.1/tests/test_eligibility_rules.py +240 -0
- {nardial-0.3.2 → nardial-0.4.1}/tests/test_moves.py +17 -1
- nardial-0.4.1/tests/test_session_manager.py +411 -0
- nardial-0.4.1/tests/test_session_plan.py +113 -0
- nardial-0.4.1/tests/test_slot_bounds.py +58 -0
- nardial-0.4.1/tests/test_type_definitions.py +302 -0
- nardial-0.3.2/src/nardial/authoring/__init__.py +0 -1
- nardial-0.3.2/src/nardial/authoring/loader.py +0 -70
- nardial-0.3.2/src/nardial/dialog_logic.py +0 -391
- nardial-0.3.2/src/nardial/session_manager.py +0 -219
- nardial-0.3.2/tests/test_conversation_state.py +0 -57
- {nardial-0.3.2 → nardial-0.4.1}/LICENSE +0 -0
- {nardial-0.3.2 → nardial-0.4.1}/setup.cfg +0 -0
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial/__init__.py +0 -0
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial/authoring/export_html.py +0 -0
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial/events/__init__.py +0 -0
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial/events/bus.py +0 -0
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial/events/types.py +0 -0
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial/providers/__init__.py +0 -0
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial/providers/device/__init__.py +0 -0
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial/providers/device/alphamini.py +0 -0
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial/providers/device/desktop.py +0 -0
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial/providers/device/nao.py +0 -0
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial/providers/device/pepper.py +0 -0
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial/providers/llm/__init__.py +0 -0
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial/providers/llm/echo.py +0 -0
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial/providers/llm/openai_gpt.py +0 -0
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial/providers/nlu/__init__.py +0 -0
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial/providers/nlu/dialogflow.py +0 -0
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial/providers/nlu/written_keyword.py +0 -0
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial/providers/screen/__init__.py +0 -0
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial/providers/screen/null.py +0 -0
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial/providers/screen/sic_adapter.py +0 -0
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial/providers/screen/web/static/screen.css +0 -0
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial/providers/screen/web/static/socket.io.min.js +0 -0
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial/providers/screen/web/templates/index.html +0 -0
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial/providers/tts/__init__.py +0 -0
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial/providers/tts/cacher.py +0 -0
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial/providers/tts/google.py +0 -0
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial/providers/tts/naoqi.py +0 -0
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial/providers/tts/null.py +0 -0
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial/providers/vector_store/__init__.py +0 -0
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial/providers/vector_store/null.py +0 -0
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial/providers/vector_store/redis_store.py +0 -0
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial/user_model.py +0 -0
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial.egg-info/dependency_links.txt +0 -0
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial.egg-info/requires.txt +0 -0
- {nardial-0.3.2 → nardial-0.4.1}/src/nardial.egg-info/top_level.txt +0 -0
- {nardial-0.3.2 → nardial-0.4.1}/tests/test_conversation_agent.py +0 -0
- {nardial-0.3.2 → nardial-0.4.1}/tests/test_event_bus.py +0 -0
- {nardial-0.3.2 → nardial-0.4.1}/tests/test_llm.py +0 -0
- {nardial-0.3.2 → nardial-0.4.1}/tests/test_mini_dialogs_extra.py +0 -0
- {nardial-0.3.2 → nardial-0.4.1}/tests/test_providers.py +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nardial
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.1
|
|
4
4
|
Summary: Nardial Dialog System
|
|
5
5
|
Author-email: Mike Ligthart <m.e.u.ligthart@vu.nl>
|
|
6
|
-
Maintainer: Clara Fayyad, Landon Brown, Evelyne Prodescu
|
|
6
|
+
Maintainer: Clara Fayyad, Landon Brown, Evelyne Prodescu, Eva Biesot
|
|
7
7
|
License-Expression: AGPL-3.0-only
|
|
8
8
|
Requires-Python: >=3.12
|
|
9
9
|
Description-Content-Type: text/markdown
|
|
@@ -42,6 +42,7 @@ It lets you author complete conversations declaratively in JSON, then drive them
|
|
|
42
42
|
4. [Defining Dialogs in JSON](#defining-dialogs-in-json)
|
|
43
43
|
- [Dialog Structure](#dialog-structure)
|
|
44
44
|
- [Dialog Types](#dialog-types)
|
|
45
|
+
- [Custom dialog types](#custom-dialog-types)
|
|
45
46
|
- [Move Types](#move-types)
|
|
46
47
|
- [Key JSON Attributes](#key-json-attributes)
|
|
47
48
|
5. [Demos / Creating a Session](#demos--creating-a-session)
|
|
@@ -157,23 +158,24 @@ NarDialPy is built around a set of provider protocols. Each protocol defines a r
|
|
|
157
158
|
|
|
158
159
|
### Available Providers
|
|
159
160
|
|
|
160
|
-
| Role | Provider | Import path
|
|
161
|
-
|
|
162
|
-
| **Device** | `DesktopAdapter` | `nardial.providers.device.desktop`
|
|
163
|
-
| | `PepperAdapter` | `nardial.providers.device.pepper`
|
|
164
|
-
| | `NaoAdapter` | `nardial.providers.device.nao`
|
|
165
|
-
| | `AlphaminiAdapter` | `nardial.providers.device.alphamini`
|
|
166
|
-
|
|
|
167
|
-
| | `
|
|
168
|
-
| | `
|
|
169
|
-
| | `
|
|
170
|
-
|
|
|
171
|
-
| | `
|
|
172
|
-
|
|
|
173
|
-
| | `
|
|
174
|
-
|
|
|
161
|
+
| Role | Provider | Import path | Requires |
|
|
162
|
+
|---|---|----------------------------------------------|---|
|
|
163
|
+
| **Device** | `DesktopAdapter` | `nardial.providers.device.desktop` | base |
|
|
164
|
+
| | `PepperAdapter` | `nardial.providers.device.pepper` | base |
|
|
165
|
+
| | `NaoAdapter` | `nardial.providers.device.nao` | base |
|
|
166
|
+
| | `AlphaminiAdapter` | `nardial.providers.device.alphamini` | `social-interaction-cloud[alphamini]` |
|
|
167
|
+
| | `ReachyMiniAdapter` | `nardial.providers.reachy_mini` | `social-interaction-cloud[reachy-mini]` |
|
|
168
|
+
| **TTS** | `GoogleTTSProvider` | `nardial.providers.tts.google` | `nardial[google-tts]` |
|
|
169
|
+
| | `ElevenLabsTTSProvider` | `nardial.providers.tts.elevenlabs` | `nardial[elevenlabs]` |
|
|
170
|
+
| | `NaoqiTTSProvider` | `nardial.providers.tts.naoqi` | base (uses device's built-in TTS) |
|
|
171
|
+
| | `NullTTSProvider` | `nardial.providers.tts.null` | base (prints to terminal) |
|
|
172
|
+
| **NLU** | `DialogflowNLUProvider` | `nardial.providers.nlu.dialogflow` | `nardial[dialogflow]` |
|
|
173
|
+
| | `WrittenKeywordNLUProvider` | `nardial.providers.nlu.written_keyword` | base (keyboard input) |
|
|
174
|
+
| **LLM** | `OpenAIGPTProvider` | `nardial.providers.llm.openai_gpt` | `nardial[openai]` |
|
|
175
|
+
| | `EchoLLMProvider` | `nardial.providers.llm.echo` | base (echoes user input) |
|
|
176
|
+
| **Screen** | `ScreenProvider` / `SICScreenAdapter` / `PepperTabletScreenAdapter` | `nardial.providers.screen` | browser display via SIC webserver |
|
|
175
177
|
| **Vector store** | `RedisVectorStoreProvider` | `nardial.providers.vector_store.redis_store` | base + running Redis |
|
|
176
|
-
| | `NullVectorStoreProvider` | `nardial.providers.vector_store.null`
|
|
178
|
+
| | `NullVectorStoreProvider` | `nardial.providers.vector_store.null` | base |
|
|
177
179
|
|
|
178
180
|
---
|
|
179
181
|
|
|
@@ -282,6 +284,20 @@ manager = SessionManager(
|
|
|
282
284
|
manager.run()
|
|
283
285
|
```
|
|
284
286
|
|
|
287
|
+
If a previous run crashed mid-session, pass `resume=True` to continue that same incomplete session (one whose `ended_at` is still `None`) instead of starting a new one — dialogs already completed in it are skipped:
|
|
288
|
+
|
|
289
|
+
```python
|
|
290
|
+
manager = SessionManager(
|
|
291
|
+
agent=agent,
|
|
292
|
+
dialog_file="dialogs/my_dialogs.json",
|
|
293
|
+
participant_id="user_42",
|
|
294
|
+
resume=True,
|
|
295
|
+
)
|
|
296
|
+
manager.run()
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
See [Developer Flow](docs/DEVELOPER_README.md) for more on session/state handling.
|
|
300
|
+
|
|
285
301
|
---
|
|
286
302
|
|
|
287
303
|
## Defining Dialogs in JSON
|
|
@@ -295,10 +311,11 @@ Every dialog has the following shared fields:
|
|
|
295
311
|
| Field | Type | Required | Description |
|
|
296
312
|
|---|---|---|---|
|
|
297
313
|
| `id` | string | ✅ | Unique identifier referenced in `session_agenda` and `dependencies` |
|
|
298
|
-
| `type` | string | ✅ | Dialog type: `"functional"`, `"chitchat"`, `"narrative"`,
|
|
314
|
+
| `type` | string | ✅ | Dialog type: `"functional"`, `"chitchat"`, `"narrative"`, `"llm_based"`, or a [custom type](#custom-dialog-types) |
|
|
299
315
|
| `moves` | array | ✅ | Ordered list of move objects the robot will perform |
|
|
300
316
|
| `dependencies` | array of strings | | Dialog IDs that must have been completed before this dialog may run |
|
|
301
317
|
| `variable_dependencies` | array | | Variables that must exist in the user model before this dialog may run |
|
|
318
|
+
| `prerequisites` | array | | Actions run just before the dialog's first move: call a registered Python function, or set user-model variables (see [below](#optional-top-level-prerequisites)) |
|
|
302
319
|
|
|
303
320
|
Example:
|
|
304
321
|
```json
|
|
@@ -338,6 +355,51 @@ Dialogs can define reusable character voices:
|
|
|
338
355
|
- Each value must contain a `voice_settings` object.
|
|
339
356
|
- `voice_settings` is validated at runtime against the active TTS provider.
|
|
340
357
|
|
|
358
|
+
#### Optional Top-Level `prerequisites`
|
|
359
|
+
|
|
360
|
+
Dialogs can list actions to run just before their first move, each time the dialog runs:
|
|
361
|
+
|
|
362
|
+
```json
|
|
363
|
+
{
|
|
364
|
+
"id": "multiplication",
|
|
365
|
+
"type": "chitchat",
|
|
366
|
+
"prerequisites": [
|
|
367
|
+
{ "execute": "choose_math_level", "args": [true, false] , "skip_dialog": true},
|
|
368
|
+
{ "set_variable": { "math_left": 4, "math_right": 3 } }
|
|
369
|
+
],
|
|
370
|
+
"moves": [
|
|
371
|
+
{ "type": "say", "text": "What is %math_left% times %math_right%?" }
|
|
372
|
+
]
|
|
373
|
+
}
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
Each entry does one of two things:
|
|
377
|
+
|
|
378
|
+
| Key | Value | What happens |
|
|
379
|
+
|---|---|---|
|
|
380
|
+
| `execute` | name of a registered function | Calls that Python function. Optional `args`: a list is passed as separate arguments (`[3, 4]` calls `f(3, 4)`), any other value as a single argument, and without `args` the function is called with none. |
|
|
381
|
+
| `set_variable` | object | Merges the object into the user model, so its values can be used in `%variable%` placeholders and later dialogs. |
|
|
382
|
+
|
|
383
|
+
In every prerequisite, `"skip_dialog` can be set to `true` of `false`, based on whether the dialog needs to be skipped if the prerequisite cannot be completed. `"skip_dialog:true` means that the dialog will be skipped if the prerequisite is not completed. If `"skip_dialog: false` is chosen, the dialog will still run, even if the prerequisite could not be completed. The default is `false`.
|
|
384
|
+
Functions are registered in Python under the name used in `execute`, before the session runs:
|
|
385
|
+
|
|
386
|
+
```python
|
|
387
|
+
from nardial.mini_dialogs import MiniDialog
|
|
388
|
+
|
|
389
|
+
@MiniDialog.register("choose_math_level")
|
|
390
|
+
def choose_math_level(last_correct, needed_help):
|
|
391
|
+
if last_correct and not needed_help:
|
|
392
|
+
level = 2
|
|
393
|
+
else:
|
|
394
|
+
level = 1
|
|
395
|
+
return level
|
|
396
|
+
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
- Prerequisites run in the order listed, after the dialog has been picked. They can't change whether the dialog itself is eligible, only what happens once it runs.
|
|
400
|
+
- Registered functions must be regular (not `async`) functions. They get only the `args` from the JSON, not the dialog or the user model.
|
|
401
|
+
- If a function isn't registered or raises an error, the error is printed and the remaining prerequisites and the dialog still run.
|
|
402
|
+
|
|
341
403
|
---
|
|
342
404
|
|
|
343
405
|
#### 1.`functional`
|
|
@@ -465,6 +527,95 @@ A fully LLM-driven dialog where the robot and user engage in a free-form multi-t
|
|
|
465
527
|
}
|
|
466
528
|
```
|
|
467
529
|
|
|
530
|
+
#### Custom dialog types
|
|
531
|
+
|
|
532
|
+
You can define your own dialog type in JSON. A custom type is based on an existing type and changes the rules that decide when its dialogs may run.
|
|
533
|
+
|
|
534
|
+
Type definitions go in their own JSON file (or a directory of them), separate from your dialogs. Mixing them is an error: a type definition in a dialog file, or a dialog in a types file, is reported and skipped. Pass the types file to `SessionManager` as `dialog_types_path`. It is loaded before the dialogs, so dialogs can use the new types:
|
|
535
|
+
|
|
536
|
+
```python
|
|
537
|
+
manager = SessionManager(
|
|
538
|
+
session_agenda=[...],
|
|
539
|
+
agent=agent,
|
|
540
|
+
dialog_types_path="dialog_types/my_types.json",
|
|
541
|
+
dialog_json_path="dialog_json/my_dialogs.json",
|
|
542
|
+
)
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
Without `SessionManager`, call `load_dialog_types(path)` (from `nardial.authoring`) before loading the dialogs. Within the types file(s), the order of definitions doesn't matter, even when one type extends another.
|
|
546
|
+
|
|
547
|
+
A type definition looks like this:
|
|
548
|
+
|
|
549
|
+
```json
|
|
550
|
+
{
|
|
551
|
+
"define_type": "repeatable_chitchat",
|
|
552
|
+
"extends": "chitchat",
|
|
553
|
+
"description": "Chitchat that may come back in later sessions, but runs at most once per session.",
|
|
554
|
+
"remove_rules": ["exclude_if_seen"],
|
|
555
|
+
"add_rules": [{ "rule": "exclude_if_seen", "scope": "session" }]
|
|
556
|
+
}
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
| Field | Type | Required | Description |
|
|
560
|
+
|---|---|---|---|
|
|
561
|
+
| `define_type` | string | ✅ | Name of the new type, used as `type` in dialogs |
|
|
562
|
+
| `extends` | string | ✅ | Type it is based on: a built-in type or another custom type |
|
|
563
|
+
| `description` | string | | Free-text description |
|
|
564
|
+
| `remove_rules` | array of strings | | Names of the base type's rules to drop |
|
|
565
|
+
| `add_rules` | array | | Rules to add: a rule name, or an object with `"rule"` plus that rule's settings |
|
|
566
|
+
|
|
567
|
+
Dialogs of the new type use the same fields as dialogs of the type it extends:
|
|
568
|
+
|
|
569
|
+
```json
|
|
570
|
+
{
|
|
571
|
+
"id": "music_lately",
|
|
572
|
+
"type": "repeatable_chitchat",
|
|
573
|
+
"topics": ["music"],
|
|
574
|
+
"moves": [{ "type": "say", "text": "What music have you been listening to lately?" }]
|
|
575
|
+
}
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
They are also picked by the same agenda slots. For example, a `chitchat_slot` can choose a `repeatable_chitchat` dialog.
|
|
579
|
+
|
|
580
|
+
**Built-in types and their rules:**
|
|
581
|
+
|
|
582
|
+
| Type | Rules |
|
|
583
|
+
|---|---|
|
|
584
|
+
| `functional` | `dependency_met` |
|
|
585
|
+
| `narrative` | `exclude_if_seen`, `dependency_met`, `variable_dependency_met`, `narrative_ordering` |
|
|
586
|
+
| `chitchat` | `exclude_if_seen`, `dependency_met`, `variable_dependency_met` |
|
|
587
|
+
| `llm_based` | `exclude_if_seen`, `dependency_met`, `variable_dependency_met` |
|
|
588
|
+
|
|
589
|
+
**Available rules.** A dialog may run only when all of its type's rules allow it.
|
|
590
|
+
|
|
591
|
+
| Rule | Settings | Allows the dialog to run when |
|
|
592
|
+
|---|---|---|
|
|
593
|
+
| `exclude_if_seen` | `scope`: `"participant"` (default) or `"session"` | it hasn't been completed before (by this participant, or in this session) |
|
|
594
|
+
| `dependency_met` | | every dialog in its `dependencies` has been completed |
|
|
595
|
+
| `variable_dependency_met` | | every required variable in its `variable_dependencies` is set in the user model |
|
|
596
|
+
| `narrative_ordering` | | every earlier `position` in its `thread` has been completed |
|
|
597
|
+
|
|
598
|
+
**Your own rules.** Any other rule is written in Python and registered under a name, which `add_rules` can then use. Settings from the JSON are passed to the constructor:
|
|
599
|
+
|
|
600
|
+
```python
|
|
601
|
+
from nardial.eligibility import EligibilityRule, register_rule
|
|
602
|
+
|
|
603
|
+
@register_rule("from_session")
|
|
604
|
+
class FromSessionRule(EligibilityRule):
|
|
605
|
+
def __init__(self, min):
|
|
606
|
+
self.min = min
|
|
607
|
+
|
|
608
|
+
def is_eligible(self, dialog, context):
|
|
609
|
+
# context.session_index: session number starting at 1, or None when unknown
|
|
610
|
+
return context.session_index is not None and context.session_index >= self.min
|
|
611
|
+
```
|
|
612
|
+
|
|
613
|
+
```json
|
|
614
|
+
{ "define_type": "returning_chitchat", "extends": "chitchat", "add_rules": [{ "rule": "from_session", "min": 2 }] }
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
Import the module that registers the rule before loading your dialogs. A rule can read `context.user_model`, `context.completed_ids`, `context.session_completed_ids`, `context.session_index` and `context.registry`. See `docs/DEVELOPER_README.md` for more, including defining types directly in Python.
|
|
618
|
+
|
|
468
619
|
---
|
|
469
620
|
|
|
470
621
|
### Move Types
|
|
@@ -489,6 +640,22 @@ Speaks a piece of text. Variable placeholders (`%variable_name%`) are replaced a
|
|
|
489
640
|
|
|
490
641
|
---
|
|
491
642
|
|
|
643
|
+
#### `say_options`
|
|
644
|
+
|
|
645
|
+
Speaks one randomly chosen response from a predefined list.
|
|
646
|
+
|
|
647
|
+
| Field | Type | Required | Description |
|
|
648
|
+
|---|---|---|---|
|
|
649
|
+
| `type` | string | ✅ | `"say_options"` |
|
|
650
|
+
| `options` | array of strings | ✅ | Candidate utterances to choose from at runtime |
|
|
651
|
+
| `character` | string | | Optional character name from top-level `characters` |
|
|
652
|
+
|
|
653
|
+
```json
|
|
654
|
+
{ "type": "say_options", "options": ["Hi!", "Hello!", "Hey there!"] }
|
|
655
|
+
```
|
|
656
|
+
|
|
657
|
+
---
|
|
658
|
+
|
|
492
659
|
#### `ask_open`
|
|
493
660
|
|
|
494
661
|
Asks a free-text question and listens for any spoken reply. The answer can be stored in a variable and used to drive branching.
|
|
@@ -502,6 +669,7 @@ Asks a free-text question and listens for any spoken reply. The answer can be st
|
|
|
502
669
|
| `default_outcome` | string | | Outcome label when no answer or no match is found |
|
|
503
670
|
| `add_interest_from_answer` | boolean | | If `true`, adds the answer to the user's topics of interest |
|
|
504
671
|
| `llm_followup` | string | | System prompt for an LLM-generated follow-up sentence after the user replies |
|
|
672
|
+
| `llm_extract_entity` | boolean | | If `true`, the LLM extracts the key entity from the answer (e.g. `"dog"` from `"my favorite animal is a dog"`) before it is stored; unrelated answers store nothing. Default `false` |
|
|
505
673
|
|
|
506
674
|
```json
|
|
507
675
|
{
|
|
@@ -601,11 +769,12 @@ Starts a multi-turn LLM-driven exchange *within* an otherwise scripted dialog. U
|
|
|
601
769
|
|
|
602
770
|
Selects and executes a list of sub-moves based on the current outcome or the value of a user model variable.
|
|
603
771
|
|
|
604
|
-
| Field
|
|
605
|
-
|
|
606
|
-
| `type`
|
|
607
|
-
| `on`
|
|
608
|
-
| `cases`
|
|
772
|
+
| Field | Type | Required | Description |
|
|
773
|
+
|-------------|---|---|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
774
|
+
| `type` | string | ✅ | `"branch"` |
|
|
775
|
+
| `on` | string | ✅ | `"outcome"` to branch on the last question's result, `"variables"` to branch based on whether to variabels in the user model have the same value, or a variable name to branch on its stored value |
|
|
776
|
+
| `cases` | object | ✅ | Maps condition values to arrays of sub-moves |
|
|
777
|
+
| `variables` | list | | In case of branching on `"variables"`, a list of the variables that need to be compared |
|
|
609
778
|
|
|
610
779
|
```json
|
|
611
780
|
{
|
|
@@ -635,6 +804,20 @@ Branching on a stored variable (e.g. to react to an answer from an earlier dialo
|
|
|
635
804
|
}
|
|
636
805
|
```
|
|
637
806
|
|
|
807
|
+
Branching on comparison of two stored variables (e.g. to check whether a given answer is correct). Chooses branch "true" if the values of the variables are the same, branch "false" if not.
|
|
808
|
+
|
|
809
|
+
```json
|
|
810
|
+
{
|
|
811
|
+
"type": "branch",
|
|
812
|
+
"on": "variables",
|
|
813
|
+
"variables": ["given_answer", "correct_answer"],
|
|
814
|
+
"cases": {
|
|
815
|
+
"true": [{ "type": "say", "text": "That's correct!"}],
|
|
816
|
+
"false": [{ "type": "say", "text": "That's incorrect. Let's try again."}]
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
```
|
|
820
|
+
|
|
638
821
|
---
|
|
639
822
|
|
|
640
823
|
#### `play`
|
|
@@ -701,14 +884,15 @@ Pause execution for a fixed duration before proceeding to the next move. Useful
|
|
|
701
884
|
|
|
702
885
|
Suspend dialog execution until a matching web input event arrives or until a timeout elapses. The web UI can present buttons or a short input and emit `web_input` events which this move listens for.
|
|
703
886
|
|
|
704
|
-
| Field | Type | Required | Description
|
|
705
|
-
|
|
706
|
-
| `type` | string | ✅ | `"wait_for_web_input"`
|
|
707
|
-
| `prompt` | string | | Hint text shown in the web UI (not spoken)
|
|
887
|
+
| Field | Type | Required | Description |
|
|
888
|
+
|---|---|---|---------------------------------------------------------------------------------|
|
|
889
|
+
| `type` | string | ✅ | `"wait_for_web_input"` |
|
|
890
|
+
| `prompt` | string | | Hint text shown in the web UI (not spoken) |
|
|
708
891
|
| `options` | array of strings | | Accepted `value` strings from the web event (if omitted, any value is accepted) |
|
|
709
|
-
| `timeout` | number | | Seconds to wait before falling back (omit for indefinite wait)
|
|
710
|
-
| `outcomes` | object | | Maps option value → outcome label for branching
|
|
711
|
-
| `default_outcome` | string | | Outcome used on timeout or when no event matches
|
|
892
|
+
| `timeout` | number | | Seconds to wait before falling back (omit for indefinite wait) |
|
|
893
|
+
| `outcomes` | object | | Maps option value → outcome label for branching |
|
|
894
|
+
| `default_outcome` | string | | Outcome used on timeout or when no event matches |
|
|
895
|
+
| `set_variable` | string | | Stores the user's choice in the user model |
|
|
712
896
|
|
|
713
897
|
```json
|
|
714
898
|
{
|
|
@@ -717,7 +901,8 @@ Suspend dialog execution until a matching web input event arrives or until a tim
|
|
|
717
901
|
"options": ["smile","thumbs","surprised"],
|
|
718
902
|
"timeout": 15,
|
|
719
903
|
"outcomes": {"smile": "picked_smile"},
|
|
720
|
-
"default_outcome": "no_choice"
|
|
904
|
+
"default_outcome": "no_choice",
|
|
905
|
+
"set_variable": "sticker"
|
|
721
906
|
}
|
|
722
907
|
```
|
|
723
908
|
|
|
@@ -797,6 +982,49 @@ Clear the display (show a blank/black screen). No parameters — the next displa
|
|
|
797
982
|
|
|
798
983
|
---
|
|
799
984
|
|
|
985
|
+
#### `keyboard_input`
|
|
986
|
+
|
|
987
|
+
Display keyboard input on screen. Suspend dialog execution until keyboard input is given or until a timeout elapses.
|
|
988
|
+
|
|
989
|
+
| Field | Type | Required | Description |
|
|
990
|
+
|---|---|---|----------------------------------------------------------------|
|
|
991
|
+
| `type` | string | ✅ | `"keyboard_input"` |
|
|
992
|
+
| `prompt` | string | | Hint text shown in the web UI (not spoken) |
|
|
993
|
+
| `timeout` | number | | Seconds to wait before falling back (omit for indefinite wait) |
|
|
994
|
+
| `outcomes` | object | | Maps option value → outcome label for branching |
|
|
995
|
+
| `default_outcome` | string | | Outcome used on timeout or when no event matches |
|
|
996
|
+
| `set_variable` | string | | Stores the user's choice in the user model |
|
|
997
|
+
|
|
998
|
+
```json
|
|
999
|
+
{
|
|
1000
|
+
"type": "keyboard_input",
|
|
1001
|
+
"prompt": "How old are you?",
|
|
1002
|
+
"timeout": 15,
|
|
1003
|
+
"default_outcome": "no_age_given",
|
|
1004
|
+
"set_variable": "age"
|
|
1005
|
+
}
|
|
1006
|
+
```
|
|
1007
|
+
|
|
1008
|
+
---
|
|
1009
|
+
|
|
1010
|
+
#### `go_to_dialog`
|
|
1011
|
+
|
|
1012
|
+
Move to a specified new minidialog.
|
|
1013
|
+
|
|
1014
|
+
| Field | Type | Required | Description |
|
|
1015
|
+
|-------------------|---|----------|----------------------------------------------------------------|
|
|
1016
|
+
| `type` | string | ✅ | `"go_to_dialog"` |
|
|
1017
|
+
| `dialog_id` | string |✅ | ID of the dialog to go to |
|
|
1018
|
+
|
|
1019
|
+
```json
|
|
1020
|
+
{
|
|
1021
|
+
"type": "go_to_dialog",
|
|
1022
|
+
"dialog_id": "favorite_animal"
|
|
1023
|
+
}
|
|
1024
|
+
```
|
|
1025
|
+
|
|
1026
|
+
---
|
|
1027
|
+
|
|
800
1028
|
### Key JSON Attributes
|
|
801
1029
|
|
|
802
1030
|
| Attribute | Where used | Description |
|
|
@@ -808,11 +1036,13 @@ Clear the display (show a blank/black screen). No parameters — the next displa
|
|
|
808
1036
|
|
|
809
1037
|
All you need is a minimal Python script that wires up the device, loads the dialog JSON, and runs the session. You can follow the included demos to get started quickly.
|
|
810
1038
|
|
|
811
|
-
|
|
1039
|
+
Ready-to-run demos are included in the `examples/` directory:
|
|
812
1040
|
* Demo 1 — General Conversation (`demo_general_conversation.py`): A simple four-step conversation using a mix of narrative and functional dialogs
|
|
813
1041
|
* Demo 2 — Structured Conversation (`demo_structured_conversation.py`): A more complete example that demonstrates all dialog types and move types, including `ask_llm`, `play`, `motion_sequence`, and `animation`
|
|
814
1042
|
* Demo 3 — Screen Display (`demo_screen_provider.py`): Shows the browser-based screen UI with transcripts, images, iframes, HTML snippets, buttons, and text input
|
|
815
1043
|
* Demo 4 — Pepper Tablet (`demo_pepper_tablet.py`): Uses the same screen UI on Pepper's tablet through the SIC webserver
|
|
1044
|
+
* Demo 5 — Agenda System (`demo_agenda_system.py`): Uses every agenda-item type (`narrative_slot`, `chitchat_slot`, `functional_slot`, `llm_dialog_ref`, plain dialog ids) so `SessionManager` picks the next dialog dynamically instead of following a fixed list — see the [Agenda System Guide](docs/AGENDA_SYSTEM_GUIDE.md) for a plain-language walkthrough
|
|
1045
|
+
* Demo 6 — Custom Dialog Type (`demo_custom_dialog_type.py`): Writes a custom eligibility rule in Python and defines two new dialog types in JSON (see [Custom dialog types](#custom-dialog-types)): a chitchat that comes back every session, and one that only runs for participants who said they have a pet
|
|
816
1046
|
|
|
817
1047
|
You can find additional demos in the [SIC Applications repository](https://github.com/Social-AI-VU/sic_applications/tree/main/demos/nardial)
|
|
818
1048
|
|
|
@@ -820,6 +1050,8 @@ You can find additional demos in the [SIC Applications repository](https://githu
|
|
|
820
1050
|
|
|
821
1051
|
## Development
|
|
822
1052
|
|
|
1053
|
+
For an architecture-level explanation of how JSON dialogs become running conversations, see [Developer Flow](docs/DEVELOPER_README.md). If you're building an application and want to understand dynamic session agendas rather than runtime internals, see the [Agenda System Guide](docs/AGENDA_SYSTEM_GUIDE.md) instead.
|
|
1054
|
+
|
|
823
1055
|
Run tests from the repository root:
|
|
824
1056
|
|
|
825
1057
|
```bash
|