OVOS-PIPELINE-1 — utterance lifecycle and pipeline (draft)#11
Conversation
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThis PR introduces ChangesPipeline Orchestrator Specification
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related issues
Possibly related PRs
Poem
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
d8e49b2 to
499ce40
Compare
Refactors INTENT-4 around the refined pipeline-plugin model discussed for OVOS-PIPELINE-1: - Registrations are **broadcast** on the bus. There is no central party that owns, validates, or routes them. Pipeline plugins (OVOS-PIPELINE-1) consume what they want. The orchestrator passively indexes everything for the introspection topics. - INTENT-4 shrinks ~30% (1100 → 736 lines) by moving the bus-level utterance lifecycle (match-result notification, dispatch, handler-lifecycle trio) into OVOS-PIPELINE-1, where it belongs. - Title becomes "Intent and Entity Registration Bus Contract" (was "...and Dispatch"). The spec is now purely about how a skill puts an intent on the bus — what happens to it after that is OVOS-PIPELINE-1's domain. Sections removed (moved to OVOS-PIPELINE-1): - §10 The match-result message (ovos.intent.matched) - §11 Dispatch (<skill_id>:<intent_name>) - §12 Handler-lifecycle messages (ovos.intent.handler.*) - §15 Other utterance-lifecycle messages (out of scope) Sections rewritten: - §1 Scope — much shorter; lists registration topics only, explicit pointer to PIPELINE-1 for the rest - §2 Architectural model — "registrations are broadcast" instead of "host as sole consumer". The orchestrator is now described as a passive indexer, not a routing party. - §3.2 Responses — now plugin-optional; no orchestrator handshake. Producers must not require a response. - §3.3 Error codes — drops `no_compatible_engine` (no central rejection party); the remaining four codes are plugin-emitted on `.response` rejections only. - §4 Topics table — broadcast direction marked explicitly; references to the moved topics are removed. - §10 Introspection — reframed as the orchestrator's passive registration index; clearer that it reflects what skills declared, not what plugins matched. - §11 Conformance — split per-party (skill MUST, plugin MAY, orchestrator MUST). Orchestrator's only responsibility is the passive index. Also folds in the "host → orchestrator" rename (companion to INTENT-3 v2 in #13). 81 occurrences renamed; one explanatory sentence added in §2. CHANGELOG, README, GLOSSARY updated to match. Cross-spec composition: - OVOS-MSG-1: unchanged - OVOS-INTENT-3 v2 (#13): provides the renamed "orchestrator" term - OVOS-INTENT-4 (this PR): pure registration protocol - OVOS-PIPELINE-1 (#11, draft): owns everything else (orchestrator contract, pipeline plugins, utterance lifecycle, dispatch, handler-lifecycle trio, terminal events) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
499ce40 to
986023e
Compare
d765e67 to
3877683
Compare
…atch.updated_session Restructure the converse plugin role so it is structurally indistinguishable from any other pipeline plugin under OVOS-PIPELINE-1, with no spec-level exceptions: - No dispatch suppression. A converse-plugin Match dispatches on <owner_id>:converse via PIPELINE-1 §7 normally; the orchestrator fires the full handler-trio and end-marker. Same for <owner_id>:response under §5.2. The reserved intent_names are a namespace lease (PIPELINE-1 §7.3), not a dispatch modification. - Match.updated_session is the canonical channel for the converse plugin's match-phase session mutations (decrementing auto_continue, removing response_mode, pre-promoting the claimer to the active-list head). Per PIPELINE-1 §4.2 the orchestrator picks up updated_session only when the match claims; declined-poll session mutations are discarded. - Polymorphism aligns with PIPELINE-1 §7.0's two-shape model: plain skill, or pipeline plugin with bundled handlers (pipeline_id == skill_id). The converse plugin itself is the second shape; it publishes its bundled-handler intent_names (converse, response) to the per-pipeline passive index (PIPELINE-1 §7.0 / §10), NOT via OVOS-INTENT-4 registration. - §3 activation lifecycle adds the match-phase mutation pathway (§4.2 Match.updated_session) as the orchestrator-side equivalent of automatic §3.1 activation, applied at match-time rather than dispatch-time. - §4.2 poll round-trip uses dotted addressed topics <owner_id>.converse.request / .response — NOT dispatches. The poll is a pure decision query; user-facing work happens only in the dispatched <owner_id>:converse handler invocation. - §5.2 response-mode delivery: the converse plugin's match returns a Match on intent_name "response" carrying updated_session with decremented auto_continue; orchestrator dispatches <owner_id>:response per PIPELINE-1 §7. Pre-emption of other intent stages is structural (first-match-wins, deployer configures converse plugin at front of session.pipeline) rather than a "no pipeline stage runs" exception. Companion PR: PIPELINE-1 (#11) carries the matching changes (§4.1 Match.updated_session, §4.2 emit-during-match allowance, §7.0 collapsed two-shape polymorphism, §7.3 simplified reservation registry). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…re matcher The converse plugin produces matches whose owner_id is some OTHER component's identity (the claiming active handler, or the response-mode holder). It bundles no handler and has no skill_id — the dispatched <owner_id>:converse and <owner_id>:response topics are handled by the OWNER (typically a skill via framework convention), not by the converse plugin itself. This is the 'pure matcher' shape PIPELINE-1 §7.0 distinguishes from 'pipeline plugin with bundled handlers' (fallback, persona, OCP — those DO bundle handlers and DO have pipeline_id == skill_id). Fixes in: - §1 reserved-intent-names bullet — drop 'bundled-handler set' framing; describe as 'pure matcher' producing matches addressed to other components - §4 leading paragraph — drop bundled-handler description; clarify the plugin publishes its intent_name set for observability, not because it owns the handlers - §9.2 conformance — drop 'MUST be addressable as plugin-with-bundled-handlers'; replace with 'is a pure matcher in §7.0 terms'; drop the MUST-NOT-register-under-INTENT-4 clause (the plugin has no skill_id so it can't register anyway) - §9.2 passive-index bullet — describe as 'intent_names it produces matches on' Companion PR: PIPELINE-1 (#11) adds the pure-matcher shape explicitly and notes that plain skills handle reserved-intent- name dispatches via framework convention. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
pipeline.md (1)
1330-1343: ⚡ Quick winConsider adding frequently-referenced companion specs to "See also" section.
The document references OVOS-TRANSFORM-1 (§§6.1, 6.2, multiple transformer chains), OVOS-CONTEXT-1 (§§3.1, 4.2, 6.1), and OVOS-CONVERSE-1 (§§7.0, 7.3) throughout, but these specs are not listed in the "See also" section. Adding them would improve navigability for implementers who need to understand the full context.
📚 Suggested addition
- *Intent Definition Specification* (OVOS-INTENT-3) — the intent concept and the orchestrator role. +- *Transformer Chain Specification* (OVOS-TRANSFORM-1) — the + utterance, metadata, intent, dialog, and TTS transformer chains + integrated into the lifecycle of §6. +- *Context Management Specification* (OVOS-CONTEXT-1) — the + intent_context promotion and decay mechanisms referenced in the + post-match-pre-dispatch window. +- *Converse Specification* (OVOS-CONVERSE-1) — the reserved + intent_names `converse` and `response` and their semantics.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@pipeline.md` around lines 1330 - 1343, Add the three frequently-referenced companion specs to the "See also" section: include bullet items for OVOS-TRANSFORM-1 (referenced in §§6.1, 6.2 and transformer chains), OVOS-CONTEXT-1 (referenced in §§3.1, 4.2, 6.1) and OVOS-CONVERSE-1 (referenced in §§7.0, 7.3) using the same prose style as the existing entries (brief title plus parenthetical description), ensuring the new bullets appear alongside the existing "Bus Message Specification", "Session Specification", "Intent and Entity Registration Bus Contract" and "Intent Definition Specification" entries and reference the `session` / `pipeline` context where appropriate.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@pipeline.md`:
- Line 928: Update the dispatch payload docs so `data.lang` is optional to match
upstream optionality: change the dispatch payload table entry for `lang` from
"yes" to "no" and add a short note clarifying that dispatch MAY omit `data.lang`
when neither Match.lang nor the entry topic provide it; ensure this is
consistent with the optional `Match.lang` symbol and the entry topic `data.lang`
symbol and remove or reconcile any text that currently forbids synthesizing a
lang fallback so the spec is internally consistent.
- Line 108: The document mistakenly references "OVOS-SESSION-2" at the phrase
"(OVOS-SESSION-1 §3.1). The full state-ownership model is owned by"—confirm
whether the intended spec is OVOS-SESSION-1 or OVOS-SESSION-2 and then either
(a) replace "OVOS-SESSION-2" with "OVOS-SESSION-1" where referenced, or (b) add
"OVOS-SESSION-2" to the companion-spec list in the introduction (the companion
specs block around lines 17-26) so the reference is consistent; update the
phrase containing "OVOS-SESSION-2" accordingly.
---
Nitpick comments:
In `@pipeline.md`:
- Around line 1330-1343: Add the three frequently-referenced companion specs to
the "See also" section: include bullet items for OVOS-TRANSFORM-1 (referenced in
§§6.1, 6.2 and transformer chains), OVOS-CONTEXT-1 (referenced in §§3.1, 4.2,
6.1) and OVOS-CONVERSE-1 (referenced in §§7.0, 7.3) using the same prose style
as the existing entries (brief title plus parenthetical description), ensuring
the new bullets appear alongside the existing "Bus Message Specification",
"Session Specification", "Intent and Entity Registration Bus Contract" and
"Intent Definition Specification" entries and reference the `session` /
`pipeline` context where appropriate.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
|
|
||
| The orchestrator is **stateless for named sessions** and holds | ||
| persistent state only for the reserved `session_id == "default"` | ||
| (OVOS-SESSION-1 §3.1). The full state-ownership model is owned by |
There was a problem hiding this comment.
Verify the spec reference: OVOS-SESSION-2 vs OVOS-SESSION-1.
The document references "OVOS-SESSION-2" here, but the companion specs listed in the introduction (lines 17-26) include only "OVOS-SESSION-1." Either OVOS-SESSION-2 should be added to the companion spec list, or this reference should be corrected to OVOS-SESSION-1 if that's the intended spec.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@pipeline.md` at line 108, The document mistakenly references "OVOS-SESSION-2"
at the phrase "(OVOS-SESSION-1 §3.1). The full state-ownership model is owned
by"—confirm whether the intended spec is OVOS-SESSION-1 or OVOS-SESSION-2 and
then either (a) replace "OVOS-SESSION-2" with "OVOS-SESSION-1" where referenced,
or (b) add "OVOS-SESSION-2" to the companion-spec list in the introduction (the
companion specs block around lines 17-26) so the reference is consistent; update
the phrase containing "OVOS-SESSION-2" accordingly.
| |-------|------|----------|---------| | ||
| | `owner_id` | string | yes | The `Match.owner_id` — the topic's prefix, repeated for the handler's convenience. | | ||
| | `intent_name` | string | yes | The `Match.intent_name` — the topic's suffix. | | ||
| | `lang` | string | yes | The language the utterance was recognized in (`data.lang`, OVOS-MSG-1 §4.2). | |
There was a problem hiding this comment.
Clarify the requirement for data.lang in dispatch payload.
The dispatch payload table (line 928) marks lang as "yes" (required), but:
Match.langis optional (§4.1, line 314, marked "no" in the Required column)- The entry topic
data.langis optional (§9.1, line 1108)
If both the entry topic and the Match can omit lang, it's unclear how the dispatch payload can always include a required lang field. The spec should either:
- Clarify that
data.langin dispatch defaults to a specific value (e.g., empty string, "unknown", or a session-derived fallback) when both sources are absent, or - Mark
data.langas optional in the dispatch payload table to match the optionality upstream.
The current wording at line 294-296 prohibits the orchestrator from synthesizing a lang value, which suggests option 2 (marking dispatch data.lang as optional) is more consistent with the design.
🧰 Tools
🪛 LanguageTool
[uncategorized] ~928-~928: Do not mix variants of the same word (‘recognize’ and ‘recognise’) within a single text.
Context: ... | yes | The language the utterance was recognized in (data.lang, OVOS-MSG-1 §4.2). | | ...
(EN_WORD_COHERENCY)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@pipeline.md` at line 928, Update the dispatch payload docs so `data.lang` is
optional to match upstream optionality: change the dispatch payload table entry
for `lang` from "yes" to "no" and add a short note clarifying that dispatch MAY
omit `data.lang` when neither Match.lang nor the entry topic provide it; ensure
this is consistent with the optional `Match.lang` symbol and the entry topic
`data.lang` symbol and remove or reconcile any text that currently forbids
synthesizing a lang fallback so the spec is internally consistent.
Defines the orchestrator and the pipeline-plugin abstraction: opaque-pipeline_id black boxes the orchestrator iterates in session.pipeline_stages order per utterance, first-match-wins. Plugins expose one operation — match(utterance, session) → Match | None, side-effect-free — and are otherwise black boxes. The orchestrator handles dispatch, notifications, and terminal events. Dispatch topic is <owner_id>:<intent_name> where owner is either a skill_id (skill-owned handler) or a pipeline_id (plugin-bundled handler). From outside, skills and plugin-bundled handlers are indistinguishable. Utterance-layer events: - recognizer_loop:utterance (entry) - ovos.intent.matched (positive match notification) - ovos.utterance.cancelled (transformer cancellation) - complete_intent_failure (no plugin claimed) - ovos.utterance.handled (universal end-marker) Handler-lifecycle trio: - ovos.intent.handler.start / .complete / .error Transformer chain: pre-pipeline modification or cancellation. Per-plugin behavioural contracts (converse, fallback, etc.) are out of scope — plugins are black boxes; each defines itself. The spec body is timeless: no mycroft references, no implementation-code citations, no "where this differs from current OVOS" appendix in the spec itself. Current-OVOS context and divergence catalogues belong in APPENDIX.md (covered in a separate commit). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Revert field rename: keep `session.pipeline` (not `pipeline_stages`). The legacy name stays; no need to break observers for a clarity-only edit. - Dispatch topic `<owner_id>:<intent_name>` (§7): clarify that the split is at the FIRST `:`. skill_id and pipeline_id MUST NOT contain `:`; intent_name MAY contain further `:` so handlers can namespace dispatched topics inside their own surface. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Simpler than first-colon-wins. The dispatch topic `<owner_id>:<intent_name>` now contains exactly one `:`, so the split is trivially unambiguous and there is no edge case to specify. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Per the draft-stage versioning policy, v1 is reserved for content drop-in compatible with current OVOS. PIPELINE-1 adds the orchestrator passive registration index and normalizes the universal `ovos.utterance.handled` end-marker across all terminal paths (current workshop misses it on the error path) — both require OVOS-side changes, so the first release ships as v2. Also update the CHANGELOG bullet that still referenced the defunct `session.pipeline_stages` rename — kept as `session.pipeline`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two related cleanups: 1. **Remove the transformer chain from the normative spec.** Transformers are pre-pipeline message modifiers — they don't match, they don't dispatch, they only mutate the message or cancel it. Their loading/ordering/contract is a separate concern and doesn't need to ride along with the pipeline plugin spec. §10 deleted; §6.1 flow simplified to two terminal paths (matched / no-match); §6.4 terminal-events table loses the cancelled row; §9.3 (`ovos.utterance.cancelled`) deleted and §9.4–§9.6 renumbered to §9.3–§9.5; §11 conformance transformer block deleted and §11 renumbered to §10. Non-goals list updated to explicitly exclude any pre-pipeline utterance- transformer chain. 2. **Refine the V2 rationale** in the CHANGELOG to match the V0/V1/V2 framing: the trigger for V2 is the handler-lifecycle rename (mycroft.skill.handler.* → ovos.intent.handler.*) which actively breaks observers of the legacy names. The passive registration index and the universal `ovos.utterance.handled` end-marker would have been V1-compatible on their own — missing them degrades experience (empty introspection, missed end-marker on workshop's error path) but doesn't break V0 producers/consumers. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…p transformers mention
§2 — the orchestrator is the logical role; it MAY be implemented as a single process or as multiple cooperating processes (a natural split runs audio-input / utterance-handling / audio-output as separate services). From the spec's perspective those processes together are "the orchestrator"; the split is a deployment / containerization choice. Pipeline plugins, the loaded-plugin set, and the match contract live in the orchestrator process that implements the utterance lifecycle (utterance-handling under the audio-boundary split). Generic voice-OS framing (no "current OVOS does X" wording in the spec body). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ection §3 pipeline_id: drop colon-rule restatement; reference MSG-1 §2.1.1. §5 session.pipeline: drop field restatement; reference SESSION-1 §2.1 claim and §2.5 deployment-default fallback. Tighten partial- unknown rule (orchestrator MUST NOT fall back to deployment default merely because one identifier is unknown). §7 dispatch topic: drop colon-rule restatement; reference MSG-1 §2.1.1. §8.1 handler trio: tighten from SHOULD to MUST — handler MUST emit exactly one terminal event (complete / error). start stays SHOULD. Reason: §9.5 universal end-marker and §8.3 timeout bookkeeping depend on terminal event being deterministic. §10 (new): per-pipeline_id intent introspection. Pull-query topic ovos.pipeline.<pipeline_id>.intents.list with scatter-response pattern. No aggregate query — consumers walk per-pipeline. Pull-query is source of truth; load-time broadcasts are MAY, consumers MUST NOT rely on them. §11 (renumbered) conformance: handler MUST emit terminal event (was SHOULD); pipeline plugin MUST respond to per-pipeline_id introspection queries; orchestrator MUST NOT synthesize trio events. Non-goals: session shape moved to SESSION-1. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Per design clarification: third-party handler code carries no obligation under this specification. The orchestrator wraps every handler invocation and emits the trio itself — start before the call, complete on normal return, error on exception or timeout. §8.1: trio MUSTs now bind the orchestrator. No handler-side participation required. §8.3: rename 'Orchestrator timeout' → 'Handler timeout'. On timeout the orchestrator emits .error (it owns the topic), then ovos.utterance.handled. Drops the prior 'orchestrator MUST NOT synthesize .error' rule since the orchestrator now owns it unambiguously. §11 handler section: replaced with a 'no normative obligation' clause. The spec binds the orchestrator that invokes the handler, not the handler. Also addresses the workshop utterance.handled asymmetry: workshop acts as orchestrator-ish wrapper but didn't emit the trio. Under this revision the wrapper IS responsible — that's the right ownership. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…n boundary A plugin needs the shape contract without having to read TRANSFORM-1 §3.2 to infer it. Now: 'a non-empty list of candidate strings, may have been modified by utterance-transformer chain, all in the same language, no particular order, plugin chooses how to weight'. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entry-topic name is deferred to a separate spec covering audio-input ↔ assistant-core wire contracts. Current OVOS uses recognizer_loop:utterance for compatibility; conformant orchestrators MAY subscribe to that name in the interim. What IS normative is the behaviour after entry: §6 lifecycle, §9.5 end-marker, §§7-8 obligations. The entry name and payload shape are not. Internal refs updated to 'entry topic (§9.1)' style throughout. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Drop all derivation/routing/authorship framing — that belongs in MSG-1. The section now states exactly what is needed: - orchestrator stamps context["pipeline_id"] before each match call - orchestrator stamps context["skill_id"] = owner_id on every dispatch Both fields flow automatically from there; no plugin author policy required. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Orchestrator stamps pipeline_id on match selection. Handler identity (skill_id) is INTENT-4's rule, applies to bundled-handler plugins identically to plain skills — fully polymorphic, nothing to add here. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Clarify that pipeline_id first appears on the dispatch Message (§7.1), not at match time. MSG-1 derivation semantics carry it through handler emissions with no further action required by the plugin or handler. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- §1: conformance cross-ref corrected to §11 (was §10) - §9 intro: drop hardcoded "five" event count - §7.0: remove named project references from pure-matcher paragraph (golden rule — describe by role, not by implementation name) - §7.1: replace "via forward (MSG-1 §5.1)" with "MSG-1 derivation semantics" — routing mechanics belong in MSG-1, not here; drop redundant skill_id drift paragraph (INTENT-4 §3.1 owns it) - §9.6: replace explicit forward/reply prescription with "derives from the dispatch Message per MSG-1 §5 derivation semantics" Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The "plain skill vs plugin-with-bundled-handlers" distinction was architectural noise — there is no difference. A match has an owner_id which is the skill_id of the handler. If that is the plugin itself, skill_id == pipeline_id. Same dispatch, same handler obligations, same INTENT-4 rules. Plugin just skipped the registration bus round-trip. - §7.0: rewritten to state the single rule plainly; table and "identifier polymorphism" heading removed - §7.1: pipeline_id stamp rule simplified — always stamped from the producing plugin; no conditional on handler-owner shape - §2: remove "two dispatch shapes" paragraph (no longer needed) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
owner_id was an abstract alias for skill_id with no distinct meaning. Now that the two-shapes framing is gone, the abstraction serves no purpose. Every match, dispatch topic, payload field, and prose reference now uses skill_id directly, consistent with INTENT-3/4 and the rest of the spec set. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
INTENT-4 is an optional layer built on top of PIPELINE-1, not a dependency of it. Move INTENT-4 to a "See also" note. Reframe the opening paragraph so the spec presents itself as the NL entry/exit boundary rather than a companion to the intent specs. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Follows MSG-1 dot-namespaced topic convention. Symmetric with ovos.intent.matched. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…handler Plugins SHOULD return from match immediately and defer expensive work (model inference, network calls) to the handler phase. Canonical example: an LLM plugin can match instantly and generate in the handler. Orchestrator SHOULD surface match-phase duration as an observable metric. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…rmative paragraphs - Match.captures → Match.slots throughout (§4.1, §4.3, §7.1, §9.2, §6.1) - match(utterance,…) → match(utterances,…) in signature, §4 inputs, §11 - Drop naming-convention explanation paragraphs from §9.1 and §9.6 - Drop §4.2 "flow diagram reflects this" cross-ref (diagram already shows it) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…andled They are not part of the pipeline lifecycle; move them outside the flow diagram's break point and correct the prose to say they run just before TTS rendering in the output layer, not inside the dispatch path. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Collapsed the 10-line circuit-breaker block to 4 lines — the SHOULD discipline is preserved, the over-specified event topic and payload are dropped. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Both are encoded in the topic (<skill_id>:<intent_name>); repeating them in data is redundant. A handler that needs them splits the topic on ':'. §9.2 ovos.intent.matched keeps them (broadcast, no topic encoding). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
By dispatch time the pipeline must have resolved a content language. lang is now required in the dispatch data; a match with no lang and no entry-topic lang is treated as declined. Match.lang updated to reflect the same obligation. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Match.lang is now required. Language resolution is the plugin's explicit responsibility: use the entry-topic lang hint, session signals, or any other policy, then declare the result. A Match without lang is malformed and treated as declined. Dispatch lang is taken directly from Match.lang with no orchestrator fallback. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Documents the get_response nesting pattern: inner utterance lifecycle runs to completion (including its own .handled) while the outer handler is blocked. Mandates orchestrator concurrency (deadlock otherwise). Clarifies that the per-entry .handled invariant applies independently to each ovos.utterance.handle. Cross-references CONVERSE-1 §5 for the response routing mechanism. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- §2: fix sentence run-on - §4.2/§9.1/§9.6: remove double blank lines - §6.1: drop "(highlighted)" — not meaningful in markdown - §11 plugin MUST: add lang to the required Match fields - §11 orchestrator MUST: add §6.5 concurrency obligation - §10.1: fix confusing Match.skill_id parenthetical → pipeline_id Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…atch.updated_session Restructure the converse plugin role so it is structurally indistinguishable from any other pipeline plugin under OVOS-PIPELINE-1, with no spec-level exceptions: - No dispatch suppression. A converse-plugin Match dispatches on <owner_id>:converse via PIPELINE-1 §7 normally; the orchestrator fires the full handler-trio and end-marker. Same for <owner_id>:response under §5.2. The reserved intent_names are a namespace lease (PIPELINE-1 §7.3), not a dispatch modification. - Match.updated_session is the canonical channel for the converse plugin's match-phase session mutations (decrementing auto_continue, removing response_mode, pre-promoting the claimer to the active-list head). Per PIPELINE-1 §4.2 the orchestrator picks up updated_session only when the match claims; declined-poll session mutations are discarded. - Polymorphism aligns with PIPELINE-1 §7.0's two-shape model: plain skill, or pipeline plugin with bundled handlers (pipeline_id == skill_id). The converse plugin itself is the second shape; it publishes its bundled-handler intent_names (converse, response) to the per-pipeline passive index (PIPELINE-1 §7.0 / §10), NOT via OVOS-INTENT-4 registration. - §3 activation lifecycle adds the match-phase mutation pathway (§4.2 Match.updated_session) as the orchestrator-side equivalent of automatic §3.1 activation, applied at match-time rather than dispatch-time. - §4.2 poll round-trip uses dotted addressed topics <owner_id>.converse.request / .response — NOT dispatches. The poll is a pure decision query; user-facing work happens only in the dispatched <owner_id>:converse handler invocation. - §5.2 response-mode delivery: the converse plugin's match returns a Match on intent_name "response" carrying updated_session with decremented auto_continue; orchestrator dispatches <owner_id>:response per PIPELINE-1 §7. Pre-emption of other intent stages is structural (first-match-wins, deployer configures converse plugin at front of session.pipeline) rather than a "no pipeline stage runs" exception. Companion PR: PIPELINE-1 (#11) carries the matching changes (§4.1 Match.updated_session, §4.2 emit-during-match allowance, §7.0 collapsed two-shape polymorphism, §7.3 simplified reservation registry). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…re matcher The converse plugin produces matches whose owner_id is some OTHER component's identity (the claiming active handler, or the response-mode holder). It bundles no handler and has no skill_id — the dispatched <owner_id>:converse and <owner_id>:response topics are handled by the OWNER (typically a skill via framework convention), not by the converse plugin itself. This is the 'pure matcher' shape PIPELINE-1 §7.0 distinguishes from 'pipeline plugin with bundled handlers' (fallback, persona, OCP — those DO bundle handlers and DO have pipeline_id == skill_id). Fixes in: - §1 reserved-intent-names bullet — drop 'bundled-handler set' framing; describe as 'pure matcher' producing matches addressed to other components - §4 leading paragraph — drop bundled-handler description; clarify the plugin publishes its intent_name set for observability, not because it owns the handlers - §9.2 conformance — drop 'MUST be addressable as plugin-with-bundled-handlers'; replace with 'is a pure matcher in §7.0 terms'; drop the MUST-NOT-register-under-INTENT-4 clause (the plugin has no skill_id so it can't register anyway) - §9.2 passive-index bullet — describe as 'intent_names it produces matches on' Companion PR: PIPELINE-1 (#11) adds the pure-matcher shape explicitly and notes that plain skills handle reserved-intent- name dispatches via framework convention. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…atch.updated_session Restructure the converse plugin role so it is structurally indistinguishable from any other pipeline plugin under OVOS-PIPELINE-1, with no spec-level exceptions: - No dispatch suppression. A converse-plugin Match dispatches on <owner_id>:converse via PIPELINE-1 §7 normally; the orchestrator fires the full handler-trio and end-marker. Same for <owner_id>:response under §5.2. The reserved intent_names are a namespace lease (PIPELINE-1 §7.3), not a dispatch modification. - Match.updated_session is the canonical channel for the converse plugin's match-phase session mutations (decrementing auto_continue, removing response_mode, pre-promoting the claimer to the active-list head). Per PIPELINE-1 §4.2 the orchestrator picks up updated_session only when the match claims; declined-poll session mutations are discarded. - Polymorphism aligns with PIPELINE-1 §7.0's two-shape model: plain skill, or pipeline plugin with bundled handlers (pipeline_id == skill_id). The converse plugin itself is the second shape; it publishes its bundled-handler intent_names (converse, response) to the per-pipeline passive index (PIPELINE-1 §7.0 / §10), NOT via OVOS-INTENT-4 registration. - §3 activation lifecycle adds the match-phase mutation pathway (§4.2 Match.updated_session) as the orchestrator-side equivalent of automatic §3.1 activation, applied at match-time rather than dispatch-time. - §4.2 poll round-trip uses dotted addressed topics <owner_id>.converse.request / .response — NOT dispatches. The poll is a pure decision query; user-facing work happens only in the dispatched <owner_id>:converse handler invocation. - §5.2 response-mode delivery: the converse plugin's match returns a Match on intent_name "response" carrying updated_session with decremented auto_continue; orchestrator dispatches <owner_id>:response per PIPELINE-1 §7. Pre-emption of other intent stages is structural (first-match-wins, deployer configures converse plugin at front of session.pipeline) rather than a "no pipeline stage runs" exception. Companion PR: PIPELINE-1 (#11) carries the matching changes (§4.1 Match.updated_session, §4.2 emit-during-match allowance, §7.0 collapsed two-shape polymorphism, §7.3 simplified reservation registry). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…re matcher The converse plugin produces matches whose owner_id is some OTHER component's identity (the claiming active handler, or the response-mode holder). It bundles no handler and has no skill_id — the dispatched <owner_id>:converse and <owner_id>:response topics are handled by the OWNER (typically a skill via framework convention), not by the converse plugin itself. This is the 'pure matcher' shape PIPELINE-1 §7.0 distinguishes from 'pipeline plugin with bundled handlers' (fallback, persona, OCP — those DO bundle handlers and DO have pipeline_id == skill_id). Fixes in: - §1 reserved-intent-names bullet — drop 'bundled-handler set' framing; describe as 'pure matcher' producing matches addressed to other components - §4 leading paragraph — drop bundled-handler description; clarify the plugin publishes its intent_name set for observability, not because it owns the handlers - §9.2 conformance — drop 'MUST be addressable as plugin-with-bundled-handlers'; replace with 'is a pure matcher in §7.0 terms'; drop the MUST-NOT-register-under-INTENT-4 clause (the plugin has no skill_id so it can't register anyway) - §9.2 passive-index bullet — describe as 'intent_names it produces matches on' Companion PR: PIPELINE-1 (#11) adds the pure-matcher shape explicitly and notes that plain skills handle reserved-intent- name dispatches via framework convention. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
OVOS-PIPELINE-1 — Utterance Lifecycle and Pipeline
Formalises the orchestrator-side utterance lifecycle and the pipeline-plugin machinery.
What the spec defines
ovos.utterance.handled, with four guaranteed-terminal paths: cancelled, matched, unmatched, matched-with-handler-error.pipeline_idstrings insession.pipeline; eachpipeline_idresolves to a plugin instance offeringmatch(utterance, lang, message) → StageMatch | null. First-match-wins;matchis side-effect-free.<owner_id>:<intent_name>, whereowner_idis polymorphically askill_idorpipeline_id. Skill IDs, pipeline IDs, and intent names MUST NOT contain:.context.skill_id— the orchestrator stampsMessage.context["skill_id"]from the dispatch topic prefix when dispatching to a skill, so forward/reply derivations carry it structurally.ovos.intent.handler.start/.complete/.error. The orchestrator owns the trio and wraps every handler invocation; handler code carries no protocol obligation. The orchestrator emits.erroron handler timeout.ovos.pipeline.<pipeline_id>.intents.list/.response. Under a split orchestrator the plugin's hosting process answers.session.pipeline.Out of scope
session.pipelineis set or updated.Status
Draft (v2).
Summary by CodeRabbit