From cb2d1e332246ae3e1259894deb8e10c69a66bf99 Mon Sep 17 00:00:00 2001 From: JarbasAi Date: Wed, 27 May 2026 23:43:14 +0100 Subject: [PATCH 1/6] OVOS-FALLBACK-1: Fallback Pipeline Plugin Specification (v1 draft) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Defines the fallback pipeline plugin that handles otherwise-unmatched utterances. Uses a ping/pong discovery cycle to find willing skills, selects by priority, and dispatches to the chosen skill. Covers skill registration (§3), discovery cycle (§4.1), selection algorithm (§4.2), dispatch to the selected skill (§5), and pipeline positioning after persona and deterministic intents (§6). Co-Authored-By: big-pickle --- fallback.md | 332 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 332 insertions(+) create mode 100644 fallback.md diff --git a/fallback.md b/fallback.md new file mode 100644 index 0000000..48f6705 --- /dev/null +++ b/fallback.md @@ -0,0 +1,332 @@ +# Fallback Pipeline Plugin Specification + +**Spec ID:** OVOS-FALLBACK-1 · **Version:** 1 · **Status:** Draft + +This specification defines the **fallback pipeline plugin** — a +pipeline plugin positioned as the final stage in the utterance +lifecycle, responsible for handling utterances that no earlier +pipeline stage matched. The plugin discovers which skills are +willing to handle the utterance, selects the highest-priority +willing skill, and dispatches to it. + +It builds on four companion specifications: + +- the *Utterance Lifecycle and Pipeline Specification* + (OVOS-PIPELINE-1) — the pipeline-plugin contract, the `Match` + shape, dispatch, the handler-lifecycle trio, and the + `session.active_handlers` stamping rule; +- the *Bus Message Specification* (OVOS-MSG-1) — the envelope, + routing keys, session carrier, and derivations every Message + defined here travels in; +- the *Session Carrier Wire Shape Specification* (OVOS-SESSION-1) — + the session field registry, the omission rule, and + `session.blacklisted_skills`; +- the *Session Lifecycle and State Ownership Specification* + (OVOS-SESSION-2) — the SHOULD-project / MAY-internal state + pathways. + +The key words **MUST**, **MUST NOT**, **SHOULD**, **SHOULD NOT**, +**MAY**, and **RECOMMENDED** are used as in RFC 2119. + +--- + +## 1. Scope + +This specification defines: + +- **the fallback plugin role** (§2) — the behavioural contract for + a pipeline plugin that handles otherwise-unmatched utterances; +- **skill registration** (§3) — how a skill declares itself as a + fallback handler with a priority; +- **the match contract** (§4) — the ping/pong discovery cycle, + priority-ordering, and selection algorithm; +- **the dispatch and handler contract** (§5) — what the selected + skill receives and how it responds; +- **pipeline positioning** (§6) — where fallback stages sit; +- **bus surface** (§7); +- **conformance** (§8). + +It does **not** define: + +- **what a fallback skill does internally** — whether it queries + a language model, returns a canned response, or triggers an + external service is the skill's business; +- **priority ranges or default priorities** — those are deployment + configuration, not normative contract; +- **confidence thresholds, intent files, or matching algorithms** + — the plugin decides which skills to ping through registration + and session policy only. + +--- + +## 2. The fallback plugin role + +A **fallback pipeline plugin** is a pipeline plugin (PIPELINE-1 §3) +that: + +- sits in the final position(s) of `session.pipeline` (§6); +- maintains a registry of skills that have declared themselves + fallback handlers, each with an integer priority (§3); +- when reached in the pipeline, discovers which registered skills + are willing to handle the current utterance (§4.1); +- selects the highest-priority willing skill and returns a `Match` + targeting that skill's `skill_id` (§4.2); +- does **not** handle the utterance itself — it delegates to the + matched skill's handler (§5). + +A deployment **MAY** load multiple fallback stages (for example, +`fallback_high`, `fallback_medium`, `fallback_low`) that each +serve a different priority range. Each is an independent pipeline +stage with its own match method. + +--- + +## 3. Skill registration + +A skill that wants to receive fallback dispatches **MUST** +register itself with the fallback plugin. + +### 3.1 Register + +The skill emits: + +`ovos.skills.fallback.register` + +| Field | Type | Required | Meaning | +|-------|------|----------|---------| +| `skill_id` | string | yes | The skill's identity. | +| `priority` | integer | no | Priority within the fallback ordering. Lower numbers are tried first. When absent, a deployment default is used. | + +The fallback plugin adds the skill to its internal registry keyed +by `skill_id`. If a skill registers again with a new priority, the +old entry is replaced. + +### 3.2 Deregister + +A skill that no longer wishes to receive fallback dispatches emits: + +`ovos.skills.fallback.deregister` + +| Field | Type | Required | Meaning | +|-------|------|----------|---------| +| `skill_id` | string | yes | The skill's identity. | + +The fallback plugin removes the skill from its registry. + +### 3.3 Priority + +Priority is an integer. Lower values are attempted first. The +value space is deployment-defined; this specification places no +constraint on the integer value beyond `0 ≤ priority`. + +A deployment **MAY** divide the priority space into ranges that +map to different fallback pipeline stages. For example, one stage +may serve priorities 0–5, another 5–90, and a final stage 90–101. +Each stage only considers skills in its configured range. + +--- + +## 4. Match contract + +### 4.1 Discovery: ping/pong cycle + +When the fallback plugin's `match` method is called, it broadcasts +a discovery ping to all registered skills within its priority +range: + +`ovos.skills.fallback.ping` + +Payload includes the utterance list, language, and session. Each +registered skill that is willing to handle the current utterance +**MUST** reply within a bounded window: + +`ovos.skills.fallback.pong` + +| Field | Type | Required | Meaning | +|-------|------|----------|---------| +| `skill_id` | string | yes | The responding skill's identity. | +| `can_handle` | bool | no | Whether the skill wants to handle this utterance. Default `true`. | + +The collection window **SHOULD** be short (≈500ms) to avoid +blocking the pipeline. Skills that do not reply within the window +are skipped. + +### 4.2 Selection + +After the collection window closes, the plugin: + +1. **Filters** out skills in `session.blacklisted_skills`. +2. **Sorts** the remaining willing skills by priority (ascending). +3. **Selects** the first (lowest priority number) willing skill. + +If no skills are willing, the plugin returns `None` — the pipeline +continues to the next stage or emits `ovos.intent.unmatched`. + +### 4.3 Match shape + +When a willing skill is selected, the plugin returns a `Match` +(PIPELINE-1 §4.1) with: + +| Field | Value | +|-------|-------| +| `skill_id` | The chosen skill's `skill_id`. | +| `intent_name` | A string identifying the fallback, e.g. `"fallback"`. | +| `lang` | The resolved BCP-47 language tag. | +| `slots` | MAY be empty. | +| `utterance` | The specific candidate string from the input list. | +| `updated_session` | Present when the plugin modifies session state. | + +The `skill_id` in the match targets the chosen skill, **not** the +fallback plugin's own `pipeline_id`. The fallback plugin dispatches +on behalf of the skill. + +### 4.4 Session mutation at match time + +The fallback plugin **MAY** mutate session state via +`Match.updated_session` (PIPELINE-1 §4.2): + +- record the selected skill in a session field for observability; +- remove the utterance from any other pending processing. + +The `updated_session` pathway is **only effective for a claiming +match**: a plugin that returns `None` has any match-phase session +mutations discarded at the plugin boundary. + +--- + +## 5. Dispatch and handler contract + +### 5.1 Dispatch + +The orchestrator dispatches `:` per +PIPELINE-1 §7, using the `skill_id` from the match (§4.3). The +dispatch carries the standard payload: `lang`, `utterance`, `slots`. + +### 5.2 Handler + +The selected skill's handler receives the dispatch and generates a +response. The handler: + +- **MAY** emit `ovos.utterance.speak` to deliver the response + (PIPELINE-1 §9.6); +- **MAY** handle the utterance without speaking (a silent action); +- **MUST** return within the handler lifecycle (PIPELINE-1 §8). + +The handler is a regular dispatched handler — it has no special +fallback-specific behaviour beyond being reachable through this +discovery path. + +--- + +## 6. Pipeline positioning + +A deployment that includes fallback stages **SHOULD** place them +after all deterministic intent-matching stages and after the +persona stage (if present). This ensures: + +1. **Registered intents first** — utterances that match a + registered intent are handled by their dedicated handler. +2. **Converse second** — active-handler follow-ups are handled. +3. **Persona third** — when active, the persona consumes unmatched + utterances before fallback. +4. **Fallback last** — only utterances that no one else handled + reach the fallback stage. + +A typical ordering: + +``` +session.pipeline: [ + "stop_high", + "converse", + "skill_high", + "skill_medium", + "persona", + "fallback_high", + "fallback_medium", + "fallback_low" +] +``` + +Multiple fallback stages at different priority ranges are +conformant. + +--- + +## 7. Bus surface + +| Topic | Direction | Purpose | +|-------|-----------|---------| +| `ovos.skills.fallback.register` | skill → fallback | Register a fallback handler with priority (§3.1). | +| `ovos.skills.fallback.deregister` | skill → fallback | Deregister a fallback handler (§3.2). | +| `ovos.skills.fallback.ping` | fallback → skills | Discovery broadcast: who can handle this utterance? (§4.1). | +| `ovos.skills.fallback.pong` | skill → fallback | Discovery reply: "I can handle this" (§4.1). | +| `:` | orchestrator → skill | Dispatch to the selected fallback skill (§5.1). | + +--- + +## 8. Conformance + +### A fallback pipeline plugin **MUST**: + +- expose a `match(utterances, lang, session) → Match | None` + operation per PIPELINE-1 §4; +- maintain a registry of skills keyed by `skill_id` with integer + priorities (§3); +- subscribe to `ovos.skills.fallback.register` and + `ovos.skills.fallback.deregister` (§3); +- broadcast `ovos.skills.fallback.ping` during `match` to discover + willing skills (§4.1); +- collect `ovos.skills.fallback.pong` replies within a bounded + time window (§4.1); +- filter willing skills against `session.blacklisted_skills` + (§4.2); +- select the willing skill with the lowest priority number (§4.2); +- return a `Match` with `skill_id` set to the selected skill's + identity (§4.3); +- return `None` when no skill is willing (§4.2). + +### A fallback pipeline plugin **SHOULD**: + +- keep the discovery collection window short (≈500ms) to avoid + blocking the pipeline (§4.1); +- support configurable priority ranges per pipeline stage (§3.3). + +### A fallback pipeline plugin **MAY**: + +- mutate session state via `Match.updated_session` during match + (§4.4); +- load as multiple stages serving different priority ranges. + +### A skill that wants fallback dispatch **MUST**: + +- register via `ovos.skills.fallback.register` with its `skill_id` + and priority (§3.1); +- subscribe to `:fallback` (or the `intent_name` + the fallback plugin dispatches on) to receive fallback dispatches + (§5.1); +- reply to `ovos.skills.fallback.ping` with `ovos.skills.fallback.pong` + when willing to handle the utterance (§4.1). + +### A deployment that includes fallback stages **SHOULD**: + +- position fallback stages after deterministic intents and persona + in `session.pipeline` (§6); +- configure priority ranges so each stage covers a non-overlapping + segment of the priority space when multiple stages are present + (§3.3). + +--- + +## See also + +- *Utterance Lifecycle and Pipeline Specification* (OVOS-PIPELINE-1) + — the pipeline-plugin contract, the `Match` shape, dispatch + polymorphism, and the handler-lifecycle trio. +- *Bus Message Specification* (OVOS-MSG-1) — the envelope, + derivations, and routing keys. +- *Session Carrier Wire Shape Specification* (OVOS-SESSION-1) — + the session field registry and `session.blacklisted_skills`. +- *Session Lifecycle and State Ownership Specification* + (OVOS-SESSION-2) — mutation boundaries and state pathways. +- *Persona Pipeline Plugin Specification* (OVOS-PERSONA-1) — + the persona stage that precedes fallback in the pipeline. From 35f2e5a9905f5d180651ea3d9cfaa3c5832235aa Mon Sep 17 00:00:00 2001 From: JarbasAi Date: Thu, 28 May 2026 00:19:56 +0100 Subject: [PATCH 2/6] =?UTF-8?q?FALLBACK-1=20=C2=A73-=C2=A78:=20topic=20ren?= =?UTF-8?q?ame,=20ping=20payload,=20bounded=20window,=20intent=5Fname,=20b?= =?UTF-8?q?us-exchange=20exception?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - All: ovos.skills.fallback.* → ovos.fallback.* (consistent with ovos.stop.*, ovos.persona.*, ovos.audio.*) - §3: priority range examples made abstract (was 0-50, 50-80, 80-100) - §4.1: added ping payload table (utterances, lang, session); bus-exchange exception note; bounded → "bounded to a few hundred milliseconds" - §4.3: intent_name standardised as "fallback" (was e.g."fallback") - §8: conformance bounded window aligned with §4.1; standardised intent_name subscription - Removed ≈500ms from conformance section Co-Authored-By: Claude Code --- fallback.md | 65 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 38 insertions(+), 27 deletions(-) diff --git a/fallback.md b/fallback.md index 48f6705..96e3301 100644 --- a/fallback.md +++ b/fallback.md @@ -90,7 +90,7 @@ register itself with the fallback plugin. The skill emits: -`ovos.skills.fallback.register` +`ovos.fallback.register` | Field | Type | Required | Meaning | |-------|------|----------|---------| @@ -105,7 +105,7 @@ old entry is replaced. A skill that no longer wishes to receive fallback dispatches emits: -`ovos.skills.fallback.deregister` +`ovos.fallback.deregister` | Field | Type | Required | Meaning | |-------|------|----------|---------| @@ -121,7 +121,8 @@ constraint on the integer value beyond `0 ≤ priority`. A deployment **MAY** divide the priority space into ranges that map to different fallback pipeline stages. For example, one stage -may serve priorities 0–5, another 5–90, and a final stage 90–101. +may serve low-priority skills, another mid-range priorities, and a +final stage only the highest-priority skills. Each stage only considers skills in its configured range. --- @@ -134,22 +135,33 @@ When the fallback plugin's `match` method is called, it broadcasts a discovery ping to all registered skills within its priority range: -`ovos.skills.fallback.ping` +`ovos.fallback.ping` -Payload includes the utterance list, language, and session. Each -registered skill that is willing to handle the current utterance -**MUST** reply within a bounded window: +| Field | Type | Required | Meaning | +|-------|------|----------|---------| +| `utterances` | array of string | yes | The candidate utterance list from the pipeline. | +| `lang` | string | yes | The resolved BCP-47 language tag. | +| `session` | object | yes | The full session object (blacklisted_skills, etc.). | -`ovos.skills.fallback.pong` +Each registered skill that is willing to handle the current +utterance **MUST** reply within the collection window: + +`ovos.fallback.pong` | Field | Type | Required | Meaning | |-------|------|----------|---------| | `skill_id` | string | yes | The responding skill's identity. | | `can_handle` | bool | no | Whether the skill wants to handle this utterance. Default `true`. | -The collection window **SHOULD** be short (≈500ms) to avoid -blocking the pipeline. Skills that do not reply within the window -are skipped. +The collection window **SHOULD** be bounded to a few hundred +milliseconds to avoid blocking the pipeline. Skills that do not +reply before the window closes are skipped. + +**Bus-exchange exception.** This ping/pong cycle is a documented +exception to PIPELINE-1 §4.4's low-latency match guidance. The +fallback plugin sits last in the pipeline (§6); no further stages +are blocked during the exchange. Skills respond within the bounded +window, so pipeline iteration resumes promptly. ### 4.2 Selection @@ -170,7 +182,7 @@ When a willing skill is selected, the plugin returns a `Match` | Field | Value | |-------|-------| | `skill_id` | The chosen skill's `skill_id`. | -| `intent_name` | A string identifying the fallback, e.g. `"fallback"`. | +| `intent_name` | `"fallback"` | | `lang` | The resolved BCP-47 language tag. | | `slots` | MAY be empty. | | `utterance` | The specific candidate string from the input list. | @@ -256,10 +268,10 @@ conformant. | Topic | Direction | Purpose | |-------|-----------|---------| -| `ovos.skills.fallback.register` | skill → fallback | Register a fallback handler with priority (§3.1). | -| `ovos.skills.fallback.deregister` | skill → fallback | Deregister a fallback handler (§3.2). | -| `ovos.skills.fallback.ping` | fallback → skills | Discovery broadcast: who can handle this utterance? (§4.1). | -| `ovos.skills.fallback.pong` | skill → fallback | Discovery reply: "I can handle this" (§4.1). | +| `ovos.fallback.register` | skill → fallback | Register a fallback handler with priority (§3.1). | +| `ovos.fallback.deregister` | skill → fallback | Deregister a fallback handler (§3.2). | +| `ovos.fallback.ping` | fallback → skills | Discovery broadcast: who can handle this utterance? (§4.1). | +| `ovos.fallback.pong` | skill → fallback | Discovery reply: "I can handle this" (§4.1). | | `:` | orchestrator → skill | Dispatch to the selected fallback skill (§5.1). | --- @@ -272,11 +284,11 @@ conformant. operation per PIPELINE-1 §4; - maintain a registry of skills keyed by `skill_id` with integer priorities (§3); -- subscribe to `ovos.skills.fallback.register` and - `ovos.skills.fallback.deregister` (§3); -- broadcast `ovos.skills.fallback.ping` during `match` to discover +- subscribe to `ovos.fallback.register` and + `ovos.fallback.deregister` (§3); +- broadcast `ovos.fallback.ping` during `match` to discover willing skills (§4.1); -- collect `ovos.skills.fallback.pong` replies within a bounded +- collect `ovos.fallback.pong` replies within a bounded time window (§4.1); - filter willing skills against `session.blacklisted_skills` (§4.2); @@ -287,8 +299,8 @@ conformant. ### A fallback pipeline plugin **SHOULD**: -- keep the discovery collection window short (≈500ms) to avoid - blocking the pipeline (§4.1); +- keep the discovery collection window bounded to a few hundred + milliseconds (§4.1); - support configurable priority ranges per pipeline stage (§3.3). ### A fallback pipeline plugin **MAY**: @@ -299,12 +311,11 @@ conformant. ### A skill that wants fallback dispatch **MUST**: -- register via `ovos.skills.fallback.register` with its `skill_id` +- register via `ovos.fallback.register` with its `skill_id` and priority (§3.1); -- subscribe to `:fallback` (or the `intent_name` - the fallback plugin dispatches on) to receive fallback dispatches - (§5.1); -- reply to `ovos.skills.fallback.ping` with `ovos.skills.fallback.pong` +- subscribe to `:fallback` to receive fallback + dispatches (§5.1); +- reply to `ovos.fallback.ping` with `ovos.fallback.pong` when willing to handle the utterance (§4.1). ### A deployment that includes fallback stages **SHOULD**: From 59c8385a5ad2c4d2a68316079eb07e671ae53a32 Mon Sep 17 00:00:00 2001 From: JarbasAi Date: Thu, 28 May 2026 09:06:56 +0100 Subject: [PATCH 3/6] FALLBACK-1: rewrite spec from scratch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Design changes from previous draft: - Drop broadcast ping/pong (STOP-1 pattern); adopt sequential unicast per-skill query (CONVERSE-1 pattern): .fallback.request / .fallback.response - Pool ordering follows transformer/pipeline composition model: session.fallback_handlers (preference) → stage range → availability → session.blacklisted_skills (policy). One session field claimed. - No separate blacklisted_fallback_handlers — blacklisted_skills covers per-skill exclusion; blacklisted_pipelines covers stage exclusion - Multi-stage interleaving (fallback_high/medium/low) preserved via per-instance priority range configuration; session ordering works identically within any stage - Session-scoped registration via INTENT-4 §11.1 - skill_id payload MUST equal context.skill_id (anti-spoofing) Companion edits: - ovos-pipeline-1.md §7.3: reserve intent_name "fallback" - ovos-session-1.md §3: register fallback_handlers field; fix response_mode shape owner_id → skill_id Co-Authored-By: Claude Sonnet 4.6 --- fallback.md | 426 +++++++++++++++++++++++---------------------- ovos-pipeline-1.md | 1 + ovos-session-1.md | 3 +- 3 files changed, 223 insertions(+), 207 deletions(-) diff --git a/fallback.md b/fallback.md index 96e3301..d142f2d 100644 --- a/fallback.md +++ b/fallback.md @@ -3,27 +3,25 @@ **Spec ID:** OVOS-FALLBACK-1 · **Version:** 1 · **Status:** Draft This specification defines the **fallback pipeline plugin** — a -pipeline plugin positioned as the final stage in the utterance -lifecycle, responsible for handling utterances that no earlier -pipeline stage matched. The plugin discovers which skills are -willing to handle the utterance, selects the highest-priority -willing skill, and dispatches to it. +pipeline plugin that handles utterances no earlier stage claimed. +It maintains a registry of fallback skills, constructs an ordered +handler pool from that registry and the session's preferences, +queries skills in pool order to find a willing handler, and +dispatches to the first one that claims the utterance. It builds on four companion specifications: - the *Utterance Lifecycle and Pipeline Specification* (OVOS-PIPELINE-1) — the pipeline-plugin contract, the `Match` - shape, dispatch, the handler-lifecycle trio, and the - `session.active_handlers` stamping rule; + shape, dispatch, the handler-lifecycle trio, the pipeline + composition model, and the reserved-intent-name registry; - the *Bus Message Specification* (OVOS-MSG-1) — the envelope, routing keys, session carrier, and derivations every Message defined here travels in; - the *Session Carrier Wire Shape Specification* (OVOS-SESSION-1) — - the session field registry, the omission rule, and - `session.blacklisted_skills`; -- the *Session Lifecycle and State Ownership Specification* - (OVOS-SESSION-2) — the SHOULD-project / MAY-internal state - pathways. + the session field registry and the omission rule; +- the *Intent and Entity Registration Bus Contract* + (OVOS-INTENT-4) — the session-scoped registration model. The key words **MUST**, **MUST NOT**, **SHOULD**, **SHOULD NOT**, **MAY**, and **RECOMMENDED** are used as in RFC 2119. @@ -34,28 +32,32 @@ The key words **MUST**, **MUST NOT**, **SHOULD**, **SHOULD NOT**, This specification defines: -- **the fallback plugin role** (§2) — the behavioural contract for - a pipeline plugin that handles otherwise-unmatched utterances; +- **the fallback plugin role** (§2) — a pipeline plugin that + delegates to registered fallback skills; - **skill registration** (§3) — how a skill declares itself as a - fallback handler with a priority; -- **the match contract** (§4) — the ping/pong discovery cycle, - priority-ordering, and selection algorithm; -- **the dispatch and handler contract** (§5) — what the selected - skill receives and how it responds; -- **pipeline positioning** (§6) — where fallback stages sit; -- **bus surface** (§7); -- **conformance** (§8). + fallback handler with a default ordering priority; +- **session fields** (§4) — the two session-resident fields that + control pool ordering and access control; +- **pool construction** (§5) — how the ordered handler pool is + derived from registration, session preference, and policy; +- **the match contract** (§6) — the sequential per-skill query, + selection algorithm, and Match shape; +- **the dispatch and handler contract** (§7) — what the selected + skill receives; +- **pipeline positioning** (§8) — where fallback stages sit and + how multiple stages interleave with other plugins; +- **bus surface** (§9); +- **conformance** (§10). It does **not** define: -- **what a fallback skill does internally** — whether it queries - a language model, returns a canned response, or triggers an - external service is the skill's business; -- **priority ranges or default priorities** — those are deployment - configuration, not normative contract; -- **confidence thresholds, intent files, or matching algorithms** - — the plugin decides which skills to ping through registration - and session policy only. +- **what a fallback skill does internally** — whether it queries a + language model, returns a canned response, or calls an external + service is the skill's business; +- **priority number ranges or their mapping to stages** — the + integer space and any per-stage range boundaries are deployment + configuration; +- **query timeout values** — these are deployment-defined. --- @@ -64,280 +66,292 @@ It does **not** define: A **fallback pipeline plugin** is a pipeline plugin (PIPELINE-1 §3) that: -- sits in the final position(s) of `session.pipeline` (§6); +- occupies one or more positions in `session.pipeline` (§8); - maintains a registry of skills that have declared themselves - fallback handlers, each with an integer priority (§3); -- when reached in the pipeline, discovers which registered skills - are willing to handle the current utterance (§4.1); -- selects the highest-priority willing skill and returns a `Match` - targeting that skill's `skill_id` (§4.2); -- does **not** handle the utterance itself — it delegates to the - matched skill's handler (§5). - -A deployment **MAY** load multiple fallback stages (for example, -`fallback_high`, `fallback_medium`, `fallback_low`) that each -serve a different priority range. Each is an independent pipeline -stage with its own match method. + fallback handlers, each with a default ordering priority (§3); +- at each match call, constructs an ordered handler pool from the + registry, session preference, and policy (§5); +- queries pool members in order until a willing skill is found (§6); +- returns a `Match` delegating to that skill, or `None` if the + pool is exhausted (§6). + +The fallback plugin does not handle utterances itself. --- ## 3. Skill registration -A skill that wants to receive fallback dispatches **MUST** -register itself with the fallback plugin. - ### 3.1 Register -The skill emits: +A skill that wishes to receive fallback dispatches emits: `ovos.fallback.register` | Field | Type | Required | Meaning | |-------|------|----------|---------| -| `skill_id` | string | yes | The skill's identity. | -| `priority` | integer | no | Priority within the fallback ordering. Lower numbers are tried first. When absent, a deployment default is used. | +| `skill_id` | string | yes | The skill's identity. MUST equal `context.skill_id` of this Message. | +| `priority` | integer | yes | Default ordering hint. Lower values sort earlier when no session preference overrides. | -The fallback plugin adds the skill to its internal registry keyed -by `skill_id`. If a skill registers again with a new priority, the -old entry is replaced. +The plugin adds the skill to its registry. Re-registration with +the same `skill_id` replaces the prior entry. The plugin MUST NOT +index a registration where the payload `skill_id` differs from +`context.skill_id`. ### 3.2 Deregister -A skill that no longer wishes to receive fallback dispatches emits: - `ovos.fallback.deregister` | Field | Type | Required | Meaning | |-------|------|----------|---------| | `skill_id` | string | yes | The skill's identity. | -The fallback plugin removes the skill from its registry. - -### 3.3 Priority +Removes the skill from the registry. Unknown `skill_id` is a no-op. -Priority is an integer. Lower values are attempted first. The -value space is deployment-defined; this specification places no -constraint on the integer value beyond `0 ≤ priority`. +### 3.3 Session-scoped registration -A deployment **MAY** divide the priority space into ranges that -map to different fallback pipeline stages. For example, one stage -may serve low-priority skills, another mid-range priorities, and a -final stage only the highest-priority skills. -Each stage only considers skills in its configured range. +Registration is session-scoped per **OVOS-INTENT-4 §11.1**: the +plugin keys each entry by `context.session.session_id` of the +registration Message. Skills registered under `"default"` are +available to all sessions. Skills registered under a specific +`session_id` extend the pool for that session only. --- -## 4. Match contract +## 4. Session fields -### 4.1 Discovery: ping/pong cycle +This specification claims one optional session field per +**OVOS-SESSION-1 §2.1**. -When the fallback plugin's `match` method is called, it broadcasts -a discovery ping to all registered skills within its priority -range: +| Field | Wire type | Owner | +|-------|-----------|-------| +| `fallback_handlers` | array of string | §4 (this spec) | -`ovos.fallback.ping` +`session.fallback_handlers` is an ordered list of `skill_id`s +expressing a session-level preference for the fallback handler +order. When present, this list is the primary ordering input to +pool construction (§5). When absent, registered priority +determines order. -| Field | Type | Required | Meaning | -|-------|------|----------|---------| -| `utterances` | array of string | yes | The candidate utterance list from the pipeline. | -| `lang` | string | yes | The resolved BCP-47 language tag. | -| `session` | object | yes | The full session object (blacklisted_skills, etc.). | +The list MAY be partial. Skills not listed but registered and +available are appended after the listed skills, sorted by +registered priority ascending. -Each registered skill that is willing to handle the current -utterance **MUST** reply within the collection window: +Per-skill access control uses the existing +`session.blacklisted_skills` field (**OVOS-SESSION-1 §3**) — no +separate fallback-specific denylist is needed. To block all +fallback handling for a session, exclude the fallback stage(s) +from `session.blacklisted_pipelines`. -`ovos.fallback.pong` +--- -| Field | Type | Required | Meaning | -|-------|------|----------|---------| -| `skill_id` | string | yes | The responding skill's identity. | -| `can_handle` | bool | no | Whether the skill wants to handle this utterance. Default `true`. | +## 5. Pool construction + +On each `match` call the plugin constructs the **effective handler +pool**: + +1. **Preference.** If `session.fallback_handlers` is present and + non-empty, use it as the leading order. Append any registered + skills not in the list, sorted by registered priority ascending. + If absent, sort all registered skills by registered priority + ascending. +2. **Stage range.** If this plugin instance is configured with a + priority range (§8.2), retain only skills whose registered + priority falls within that range. +3. **Availability.** Retain only skills present in the registry for + the current `session_id` (including `"default"` registrations + per §3.3). +4. **Policy.** Remove any `skill_id` present in + `session.blacklisted_skills` (**OVOS-SESSION-1 §3**). + +The result is the ordered effective pool. An empty pool causes the +plugin to return `None` immediately. No later stage adds what an +earlier stage removed. -The collection window **SHOULD** be bounded to a few hundred -milliseconds to avoid blocking the pipeline. Skills that do not -reply before the window closes are skipped. +--- -**Bus-exchange exception.** This ping/pong cycle is a documented -exception to PIPELINE-1 §4.4's low-latency match guidance. The -fallback plugin sits last in the pipeline (§6); no further stages -are blocked during the exchange. Skills respond within the bounded -window, so pipeline iteration resumes promptly. +## 6. Match contract -### 4.2 Selection +### 6.1 Per-skill query -After the collection window closes, the plugin: +When the effective pool is non-empty the plugin queries skills one +at a time in pool order. For each skill it sends: -1. **Filters** out skills in `session.blacklisted_skills`. -2. **Sorts** the remaining willing skills by priority (ascending). -3. **Selects** the first (lowest priority number) willing skill. +`.fallback.request` -If no skills are willing, the plugin returns `None` — the pipeline -continues to the next stage or emits `ovos.intent.unmatched`. +using the **dotted addressed** form, derived via `.reply()` from +the inbound utterance Message (**OVOS-MSG-1 §5.2**). The session +and routing metadata propagate automatically through derivation; +no payload fields are required. -### 4.3 Match shape +The queried skill replies with: -When a willing skill is selected, the plugin returns a `Match` -(PIPELINE-1 §4.1) with: +`.fallback.response` -| Field | Value | -|-------|-------| -| `skill_id` | The chosen skill's `skill_id`. | -| `intent_name` | `"fallback"` | -| `lang` | The resolved BCP-47 language tag. | -| `slots` | MAY be empty. | -| `utterance` | The specific candidate string from the input list. | -| `updated_session` | Present when the plugin modifies session state. | +| Field | Type | Required | Meaning | +|-------|------|----------|---------| +| `skill_id` | string | yes | The responding skill's identity. MUST equal the topic prefix. | +| `can_handle` | bool | yes | Whether this skill is willing to handle the current utterance. | -The `skill_id` in the match targets the chosen skill, **not** the -fallback plugin's own `pipeline_id`. The fallback plugin dispatches -on behalf of the skill. +The plugin waits for each skill's reply before advancing to the +next. A skill that does not respond within a deployment-defined +timeout is treated as `can_handle: false` and skipped. -### 4.4 Session mutation at match time +**Bus-exchange exception.** The per-skill query cycle is a +documented exception to PIPELINE-1 §4.4's low-latency guidance, +justified because fallback stage(s) are positioned after all other +intent-matching stages (§8). No further stages are blocked during +the exchange, and the query terminates as soon as a willing skill +is found. This pattern follows the precedent of OVOS-CONVERSE-1's +per-skill converse poll. -The fallback plugin **MAY** mutate session state via -`Match.updated_session` (PIPELINE-1 §4.2): +### 6.2 Selection -- record the selected skill in a session field for observability; -- remove the utterance from any other pending processing. +The plugin selects the first skill in pool order whose +`can_handle` reply is `true`. If the pool is exhausted with no +willing skill the plugin returns `None`, and the pipeline emits +`ovos.intent.unmatched` (**PIPELINE-1 §9.4**). -The `updated_session` pathway is **only effective for a claiming -match**: a plugin that returns `None` has any match-phase session -mutations discarded at the plugin boundary. +### 6.3 Match shape ---- +| Field | Value | +|-------|-------| +| `skill_id` | The selected skill's `skill_id`. | +| `intent_name` | `"fallback"` — reserved per PIPELINE-1 §7.3. | +| `lang` | The resolved BCP-47 language tag. | +| `utterance` | The utterance string passed to `match`. | +| `slots` | Empty. | +| `updated_session` | Present if the plugin mutates session state. | -## 5. Dispatch and handler contract +The `skill_id` targets the selected skill, not the fallback +plugin's own `pipeline_id`. -### 5.1 Dispatch +--- -The orchestrator dispatches `:` per -PIPELINE-1 §7, using the `skill_id` from the match (§4.3). The -dispatch carries the standard payload: `lang`, `utterance`, `slots`. +## 7. Dispatch and handler contract -### 5.2 Handler +The orchestrator dispatches `:fallback` per **PIPELINE-1 +§7**, firing the standard handler-lifecycle trio. The dispatch +payload is the standard shape: `lang`, `utterance`, `slots`. -The selected skill's handler receives the dispatch and generates a -response. The handler: +The selected skill's handler: -- **MAY** emit `ovos.utterance.speak` to deliver the response - (PIPELINE-1 §9.6); -- **MAY** handle the utterance without speaking (a silent action); -- **MUST** return within the handler lifecycle (PIPELINE-1 §8). +- **MAY** emit `ovos.utterance.speak` (**PIPELINE-1 §9.6**); +- **MAY** act silently; +- **MUST** complete within the handler lifecycle (**PIPELINE-1 §8**). -The handler is a regular dispatched handler — it has no special -fallback-specific behaviour beyond being reachable through this -discovery path. +No fallback-specific response protocol is required beyond +subscribing to `:fallback`. --- -## 6. Pipeline positioning +## 8. Pipeline positioning -A deployment that includes fallback stages **SHOULD** place them -after all deterministic intent-matching stages and after the -persona stage (if present). This ensures: +### 8.1 General placement -1. **Registered intents first** — utterances that match a - registered intent are handled by their dedicated handler. -2. **Converse second** — active-handler follow-ups are handled. -3. **Persona third** — when active, the persona consumes unmatched - utterances before fallback. -4. **Fallback last** — only utterances that no one else handled - reach the fallback stage. +Fallback stage(s) **SHOULD** be placed after all deterministic +intent-matching stages and after the persona stage (if present). +Utterances that reach a fallback stage were not claimed by any +earlier stage. -A typical ordering: +### 8.2 Multiple stages and priority interleaving + +A deployment MAY load multiple fallback plugin instances at +different positions in `session.pipeline`. Each instance is +configured with a **priority range** — a `[min, max]` integer +interval — that restricts which registered skills it considers +(§5 step 2). This allows fallback skills to be interleaved with +other pipeline stages. + +Example: ``` session.pipeline: [ "stop_high", "converse", - "skill_high", - "skill_medium", + "padatious_high", + "fallback_high", ← priority range [0, 49] + "adapt", + "fallback_medium", ← priority range [50, 74] "persona", - "fallback_high", - "fallback_medium", - "fallback_low" + "fallback_low" ← priority range [75, 100] ] ``` -Multiple fallback stages at different priority ranges are -conformant. +A skill registered at `priority: 10` is queried by `fallback_high` +before `adapt` runs. A skill registered at `priority: 80` is +queried by `fallback_low` only after both `adapt` and `persona` +have declined. A single-stage deployment sets no range restriction. + +Within any stage, pool construction and session ordering (§5) work +identically regardless of how many stages are present. --- -## 7. Bus surface +## 9. Bus surface -| Topic | Direction | Purpose | -|-------|-----------|---------| -| `ovos.fallback.register` | skill → fallback | Register a fallback handler with priority (§3.1). | -| `ovos.fallback.deregister` | skill → fallback | Deregister a fallback handler (§3.2). | -| `ovos.fallback.ping` | fallback → skills | Discovery broadcast: who can handle this utterance? (§4.1). | -| `ovos.fallback.pong` | skill → fallback | Discovery reply: "I can handle this" (§4.1). | -| `:` | orchestrator → skill | Dispatch to the selected fallback skill (§5.1). | +| Topic | Form | Direction | Purpose | +|-------|------|-----------|---------| +| `ovos.fallback.register` | broadcast | skill → fallback | Register as a fallback handler (§3.1). | +| `ovos.fallback.deregister` | broadcast | skill → fallback | Deregister (§3.2). | +| `.fallback.request` | dotted addressed | fallback → skill | Query: willing to handle this utterance? (§6.1). | +| `.fallback.response` | dotted addressed | skill → fallback | Reply: willing or not (§6.1). | +| `:fallback` | dispatch | orchestrator → skill | Dispatch to the selected skill (§7). | --- -## 8. Conformance +## 10. Conformance ### A fallback pipeline plugin **MUST**: - expose a `match(utterances, lang, session) → Match | None` operation per PIPELINE-1 §4; -- maintain a registry of skills keyed by `skill_id` with integer - priorities (§3); +- maintain a session-scoped registry of skills with integer + priorities per §3.3; - subscribe to `ovos.fallback.register` and `ovos.fallback.deregister` (§3); -- broadcast `ovos.fallback.ping` during `match` to discover - willing skills (§4.1); -- collect `ovos.fallback.pong` replies within a bounded - time window (§4.1); -- filter willing skills against `session.blacklisted_skills` - (§4.2); -- select the willing skill with the lowest priority number (§4.2); -- return a `Match` with `skill_id` set to the selected skill's - identity (§4.3); -- return `None` when no skill is willing (§4.2). +- reject any registration where payload `skill_id` ≠ + `context.skill_id` (§3.1); +- construct the effective handler pool per §5 on each match call; +- query skills sequentially via `.fallback.request` and + await `.fallback.response` before advancing (§6.1); +- select the first willing skill in pool order (§6.2); +- return a `Match` with `intent_name: "fallback"` targeting the + selected skill (§6.3); +- return `None` when no skill in the pool is willing (§6.2). ### A fallback pipeline plugin **SHOULD**: -- keep the discovery collection window bounded to a few hundred - milliseconds (§4.1); -- support configurable priority ranges per pipeline stage (§3.3). +- apply a per-skill query timeout and treat non-response as + `can_handle: false` (§6.1); +- when configured with a priority range, apply it as §5 step 2. ### A fallback pipeline plugin **MAY**: -- mutate session state via `Match.updated_session` during match - (§4.4); -- load as multiple stages serving different priority ranges. +- mutate session state via `Match.updated_session` (§6.3). -### A skill that wants fallback dispatch **MUST**: +### A skill registered as a fallback handler **MUST**: -- register via `ovos.fallback.register` with its `skill_id` - and priority (§3.1); -- subscribe to `:fallback` to receive fallback - dispatches (§5.1); -- reply to `ovos.fallback.ping` with `ovos.fallback.pong` - when willing to handle the utterance (§4.1). +- emit `ovos.fallback.register` with its `skill_id` and `priority` + before receiving fallback dispatches (§3.1); +- subscribe to `.fallback.request` and reply with + `.fallback.response` (§6.1); +- subscribe to `:fallback` to receive dispatches (§7). -### A deployment that includes fallback stages **SHOULD**: +### A deployment **SHOULD**: -- position fallback stages after deterministic intents and persona - in `session.pipeline` (§6); -- configure priority ranges so each stage covers a non-overlapping - segment of the priority space when multiple stages are present - (§3.3). +- position fallback stage(s) after deterministic intent-matching + and persona stages in `session.pipeline` (§8.1). --- ## See also -- *Utterance Lifecycle and Pipeline Specification* (OVOS-PIPELINE-1) - — the pipeline-plugin contract, the `Match` shape, dispatch - polymorphism, and the handler-lifecycle trio. -- *Bus Message Specification* (OVOS-MSG-1) — the envelope, - derivations, and routing keys. -- *Session Carrier Wire Shape Specification* (OVOS-SESSION-1) — - the session field registry and `session.blacklisted_skills`. -- *Session Lifecycle and State Ownership Specification* - (OVOS-SESSION-2) — mutation boundaries and state pathways. -- *Persona Pipeline Plugin Specification* (OVOS-PERSONA-1) — - the persona stage that precedes fallback in the pipeline. +- **OVOS-PIPELINE-1** — pipeline-plugin contract, Match shape, + dispatch, reserved intent-name registry (§7.3). +- **OVOS-MSG-1** — envelope, derivations, and routing keys. +- **OVOS-SESSION-1** — session field registry; + `session.blacklisted_skills`. +- **OVOS-INTENT-4** — session-scoped registration model (§11). +- **OVOS-CONVERSE-1** — the dotted-addressed per-skill query + pattern this specification follows. +- **OVOS-PERSONA-1** — the persona stage that precedes fallback. diff --git a/ovos-pipeline-1.md b/ovos-pipeline-1.md index 16c56e2..b4eb431 100644 --- a/ovos-pipeline-1.md +++ b/ovos-pipeline-1.md @@ -895,6 +895,7 @@ Reservations currently in force: | `converse` | OVOS-CONVERSE-1 §4 | a converse plugin's claim that `` (an active handler) wants this utterance — the orchestrator dispatches `:converse` and the owner's converse handler runs | | `response` | OVOS-CONVERSE-1 §5 | a converse plugin's signal that `` (the response-mode holder) is to receive the awaited utterance — the orchestrator dispatches `:response` and the owner's response handler runs | | `stop` | OVOS-STOP-1 §4 | a stop plugin's claim that `` (an active handler) should cease activity — the orchestrator dispatches `:stop` and the owner's stop handler runs | +| `fallback` | OVOS-FALLBACK-1 §6.3 | a fallback plugin's claim that `` (a registered fallback handler) is willing to handle the utterance — the orchestrator dispatches `:fallback` and the handler runs | This specification fixes only the registry mechanism (reservation listing); the per-name semantics are owned by the reserving diff --git a/ovos-session-1.md b/ovos-session-1.md index 84ef948..768d5eb 100644 --- a/ovos-session-1.md +++ b/ovos-session-1.md @@ -193,7 +193,8 @@ session and persist across utterances. | `pipeline` | array of string | OVOS-PIPELINE-1 §5 | | `intent_context` | object | OVOS-CONTEXT-1 §2 | | `active_handlers` | array of object `{skill_id, activated_at, ...}` | OVOS-PIPELINE-1 §7.1 | -| `response_mode` | object `{owner_id, expires_at}` | OVOS-CONVERSE-1 §2.2 | +| `response_mode` | object `{skill_id, expires_at}` | OVOS-CONVERSE-1 §2.2 | +| `fallback_handlers` | array of string | OVOS-FALLBACK-1 §4 | | `audio_transformers` | array of string | OVOS-TRANSFORM-1 §5 | | `utterance_transformers` | array of string | OVOS-TRANSFORM-1 §5 | | `metadata_transformers` | array of string | OVOS-TRANSFORM-1 §5 | From 99ea0a756df8a9a01158e934aac7ddad010da551 Mon Sep 17 00:00:00 2001 From: JarbasAi Date: Thu, 28 May 2026 09:13:53 +0100 Subject: [PATCH 4/6] =?UTF-8?q?FALLBACK-1=20=C2=A73.3:=20add=20priority=20?= =?UTF-8?q?tier=20guidance=20and=20default-response=20SHOULD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - §3.3: recommended three-tier convention (0-49 high confidence, 50-74 medium, 75-100 low confidence / catch-all) with examples per tier - §3.3: default-response skill guidance — deployments SHOULD include a catch-all skill at priority 100 that always returns can_handle: true; without it unmatched utterances produce no user response - §8.1: add deployment SHOULD for catch-all skill - §1 non-goals: rephrase to not claim priority ranges are undefined (§3.3 now provides non-normative guidance) Co-Authored-By: Claude Sonnet 4.6 --- fallback.md | 51 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/fallback.md b/fallback.md index d142f2d..e114f73 100644 --- a/fallback.md +++ b/fallback.md @@ -54,9 +54,9 @@ It does **not** define: - **what a fallback skill does internally** — whether it queries a language model, returns a canned response, or calls an external service is the skill's business; -- **priority number ranges or their mapping to stages** — the - integer space and any per-stage range boundaries are deployment - configuration; +- **per-stage range boundaries** — which priority numbers belong to + which stage is deployment configuration; §3.3 provides + non-normative guidance on the recommended tiers; - **query timeout values** — these are deployment-defined. --- @@ -107,7 +107,41 @@ index a registration where the payload `skill_id` differs from Removes the skill from the registry. Unknown `skill_id` is a no-op. -### 3.3 Session-scoped registration +### 3.3 Priority guidance + +Priority values have no normative meaning beyond ordering — lower +values appear earlier in the pool. This section provides +non-normative guidance for skill authors and deployers. + +The recommended convention divides the space into three tiers: + +| Range | Tier | Typical skills | +|-------|------|----------------| +| 0–49 | High confidence | Skills that search structured, bounded knowledge sources — local databases, domain-specific knowledge bases, FAQ indexes, entity lookups. These know quickly whether they have a relevant answer and are expected to be accurate when they claim the utterance. | +| 50–74 | Medium confidence | Skills that perform broader retrieval — web search, general knowledge queries — where answer quality depends on the query. They should handle the utterance if the topic is in scope but may decline when it is not. | +| 75–100 | Low confidence | General-purpose language-model chatbots and catch-all handlers that will attempt any utterance without domain restriction. These run last; they provide a response when nothing else can, not as a first choice. | + +This three-tier mapping corresponds directly to the +`fallback_high` / `fallback_medium` / `fallback_low` multi-stage +pipeline example in §8.2. + +A skill author uncertain which tier applies **SHOULD** register at +a higher number rather than a lower one. Pre-empting a more +precise handler with a low-confidence catch-all degrades response +quality silently. + +**Default response skill.** A voice assistant SHOULD always +produce an answer rather than silent failure. Every deployment +SHOULD include a catch-all fallback skill — registered at the +highest priority number in the pool (e.g. `priority: 100`) — that +unconditionally returns `can_handle: true` and responds with a +graceful "I don't know how to answer that" message. This skill is +the last entry in `session.fallback_handlers` if that field is +set, and the last resort after all higher-confidence handlers have +declined. Without it, an utterance that no skill can handle +produces `ovos.intent.unmatched` with no user-facing response. + +### 3.4 Session-scoped registration Registration is session-scoped per **OVOS-INTENT-4 §11.1**: the plugin keys each entry by `context.session.session_id` of the @@ -159,7 +193,7 @@ pool**: priority falls within that range. 3. **Availability.** Retain only skills present in the registry for the current `session_id` (including `"default"` registrations - per §3.3). + per §3.4). 4. **Policy.** Remove any `skill_id` present in `session.blacklisted_skills` (**OVOS-SESSION-1 §3**). @@ -253,6 +287,11 @@ intent-matching stages and after the persona stage (if present). Utterances that reach a fallback stage were not claimed by any earlier stage. +Every deployment **SHOULD** include a catch-all fallback skill +registered at the bottom of the priority pool (see §3.3) that +always returns `can_handle: true`. This ensures the user receives +a response to every utterance rather than silent `ovos.intent.unmatched`. + ### 8.2 Multiple stages and priority interleaving A deployment MAY load multiple fallback plugin instances at @@ -306,7 +345,7 @@ identically regardless of how many stages are present. - expose a `match(utterances, lang, session) → Match | None` operation per PIPELINE-1 §4; - maintain a session-scoped registry of skills with integer - priorities per §3.3; + priorities per §3.4; - subscribe to `ovos.fallback.register` and `ovos.fallback.deregister` (§3); - reject any registration where payload `skill_id` ≠ From 3d4930029d50cc64d7bee2e03a389dac05218dec Mon Sep 17 00:00:00 2001 From: JarbasAi Date: Thu, 28 May 2026 09:21:56 +0100 Subject: [PATCH 5/6] =?UTF-8?q?FALLBACK-1=20=C2=A72=20+=20=C2=A76.1:=20def?= =?UTF-8?q?ine=20self-parsing=20property;=20fix=20request=20payload?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit §2: add explicit statement that the defining property of a fallback skill is evaluating the utterance with its own logic rather than relying on intent registrations. Regular skills use INTENT-4 patterns selected by a pipeline plugin; fallback skills receive the raw utterance at query time and decide for themselves. Analogous to CONVERSE-1's per-skill converse poll. §6.1: fix missing utterance payload in the request. The request is derived via .reply() so context.session propagates, but data does not — the skill needs utterances+lang in the payload to do its evaluation. Add the two fields to the request table. Add prose explaining this is where the skill runs its own parsing logic. Co-Authored-By: Claude Sonnet 4.6 --- fallback.md | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/fallback.md b/fallback.md index e114f73..addccbb 100644 --- a/fallback.md +++ b/fallback.md @@ -77,6 +77,24 @@ that: The fallback plugin does not handle utterances itself. +**The defining property of a fallback skill** is that it evaluates +the utterance using its own internal logic rather than relying on +an intent model registered with the pipeline. Regular skills +declare their coverage through INTENT-4 registrations — vocabulary, +templates, or entity patterns — and a pipeline plugin selects them +by matching those patterns against the utterance. A fallback skill +declares no intent patterns; instead it receives the raw utterance +at query time (§6.1) and decides for itself whether it can respond. +This is the appropriate pattern when an utterance domain cannot be +reliably modelled as a grammar or template: open-domain question +answering, natural-language database queries, language-model +completions, and any skill whose coverage is determined +programmatically at runtime. + +This mechanism is analogous to **OVOS-CONVERSE-1**'s per-skill +converse poll, where active handlers evaluate the current utterance +themselves before the plugin dispatches to one of them. + --- ## 3. Skill registration @@ -213,9 +231,21 @@ at a time in pool order. For each skill it sends: `.fallback.request` using the **dotted addressed** form, derived via `.reply()` from -the inbound utterance Message (**OVOS-MSG-1 §5.2**). The session -and routing metadata propagate automatically through derivation; -no payload fields are required. +the inbound utterance Message (**OVOS-MSG-1 §5.2**), so that +`context.session` and routing metadata propagate automatically. + +Payload: + +| Field | Type | Required | Meaning | +|-------|------|----------|---------| +| `utterances` | array of string | yes | The candidate utterance list the skill should evaluate. | +| `lang` | string | yes | The resolved BCP-47 language tag. | + +The skill uses these to run its own evaluation logic and decide +whether it can produce a meaningful response. This is the point +at which the fallback skill parses the utterance — it may query a +knowledge base, run a classifier, call an LLM, or apply any other +internal logic. The reply carries only the decision: The queried skill replies with: From a1076b0074dbf41ef6402fb88bcb3ca4ba360597 Mon Sep 17 00:00:00 2001 From: JarbasAi Date: Thu, 28 May 2026 09:27:35 +0100 Subject: [PATCH 6/6] =?UTF-8?q?FALLBACK-1:=20rename=20fallback.request/res?= =?UTF-8?q?ponse=20=E2=86=92=20fallback.ping/pong?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Standardise on ping/pong for pipeline-plugin capability-discovery exchanges per AGENTS.md §4.5. The unicast dotted-addressed form .fallback.ping / .fallback.pong is consistent with the broadcast ovos.stop.ping / ovos.stop.pong pattern already established in STOP-1. Co-Authored-By: Claude Sonnet 4.6 --- fallback.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/fallback.md b/fallback.md index addccbb..ab3a7cd 100644 --- a/fallback.md +++ b/fallback.md @@ -228,7 +228,7 @@ earlier stage removed. When the effective pool is non-empty the plugin queries skills one at a time in pool order. For each skill it sends: -`.fallback.request` +`.fallback.ping` using the **dotted addressed** form, derived via `.reply()` from the inbound utterance Message (**OVOS-MSG-1 §5.2**), so that @@ -249,7 +249,7 @@ internal logic. The reply carries only the decision: The queried skill replies with: -`.fallback.response` +`.fallback.pong` | Field | Type | Required | Meaning | |-------|------|----------|---------| @@ -362,8 +362,8 @@ identically regardless of how many stages are present. |-------|------|-----------|---------| | `ovos.fallback.register` | broadcast | skill → fallback | Register as a fallback handler (§3.1). | | `ovos.fallback.deregister` | broadcast | skill → fallback | Deregister (§3.2). | -| `.fallback.request` | dotted addressed | fallback → skill | Query: willing to handle this utterance? (§6.1). | -| `.fallback.response` | dotted addressed | skill → fallback | Reply: willing or not (§6.1). | +| `.fallback.ping` | dotted addressed | fallback → skill | Query: willing to handle this utterance? (§6.1). | +| `.fallback.pong` | dotted addressed | skill → fallback | Reply: willing or not (§6.1). | | `:fallback` | dispatch | orchestrator → skill | Dispatch to the selected skill (§7). | --- @@ -381,8 +381,8 @@ identically regardless of how many stages are present. - reject any registration where payload `skill_id` ≠ `context.skill_id` (§3.1); - construct the effective handler pool per §5 on each match call; -- query skills sequentially via `.fallback.request` and - await `.fallback.response` before advancing (§6.1); +- query skills sequentially via `.fallback.ping` and + await `.fallback.pong` before advancing (§6.1); - select the first willing skill in pool order (§6.2); - return a `Match` with `intent_name: "fallback"` targeting the selected skill (§6.3); @@ -402,8 +402,8 @@ identically regardless of how many stages are present. - emit `ovos.fallback.register` with its `skill_id` and `priority` before receiving fallback dispatches (§3.1); -- subscribe to `.fallback.request` and reply with - `.fallback.response` (§6.1); +- subscribe to `.fallback.ping` and reply with + `.fallback.pong` (§6.1); - subscribe to `:fallback` to receive dispatches (§7). ### A deployment **SHOULD**: