Skip to content

[voice] LLMItemSerializer: Get semantic relationships from metadata & Include semantic children of non-semantic groups - #5758

Open
florian-h05 wants to merge 5 commits into
openhab:mainfrom
florian-h05:voice-llmitemserializer
Open

[voice] LLMItemSerializer: Get semantic relationships from metadata & Include semantic children of non-semantic groups#5758
florian-h05 wants to merge 5 commits into
openhab:mainfrom
florian-h05:voice-llmitemserializer

Conversation

@florian-h05

Copy link
Copy Markdown
Contributor
  • Get semantic relationships from semantics metadata instead of checking group memberships (so SemanticsMetadataProvider is single source of truth for building the model).
  • Include semantic children of non-semantic groups in the non-semantic items section of the output.

…ta, only falling back to group membership

Signed-off-by: Florian Hotze <dev@florianhotze.com>
…c groups between semantic and non-semantic items

Signed-off-by: Florian Hotze <dev@florianhotze.com>
Signed-off-by: Florian Hotze <dev@florianhotze.com>
@florian-h05
florian-h05 requested a review from a team as a code owner August 7, 2026 12:11
@florian-h05 florian-h05 changed the title [voice] LLMItemSerializer: Get semantic relationships from semantics metadata & Include semantic children of non-semantic groups [voice] LLMItemSerializer: Get semantic relationships from metadata & Include semantic children of non-semantic groups Aug 7, 2026

@wborn wborn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR was reviewed by AI first; a manual maintainer review will still follow.

The overall direction makes sense. Using the semantics metadata as the source for semantic relationships avoids duplicating the hierarchy rules in LLMItemSerializer, and including semantic Items below non-semantic Groups is useful for the LLM context.

There are still a few issues that should be addressed:

  • Root semantic Items that are only members of non-semantic Groups are no longer emitted in the semantic section. They should remain semantic roots and additionally be included below the non-semantic Group.
  • The new recursive traversal of non-semantic Groups has no protection against recursive group membership, which can result in unbounded recursion.
  • org.openhab.core.voice now depends on constants from org.openhab.core.semantics.internal. The semantics metadata contract used across bundles should be exposed from a non-internal API rather than coupling the voice bundle to an implementation class.

The added tests cover the main metadata-based hierarchy and an Item that occurs in both sections, but test cases for a root semantic Item inside a non-semantic Group and recursive group membership would help cover the two functional cases above.

if (parentName != null) {
for (String parentName : parentNames) {
parentToChildren.computeIfAbsent(parentName, k -> new ArrayList<>()).add(child);
childNames.add(child.getName());

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

childNames now combines two different kinds of relationships: semantic parent relationships from the metadata and membership in non-semantic Groups. This causes a semantic Item to stop being a semantic root merely because it belongs to a non-semantic Group.

For example, if a semantic Point has no hasLocation/isPointOf relationship but is a member of gSensors, it is added to childNames. It is therefore omitted from rootPoints and only appears below gSensors in the non-semantic section, where its semantic type and properties are no longer represented.

The existing test covers an Item that has both a semantic parent and a non-semantic parent, so it still remains reachable through the semantic tree.

Could we track semantic-parent relationships separately from non-semantic Group relationships so that root detection for semantic Items only considers semantic parents? It would also be good to add a test for a root semantic Item that belongs to a non-semantic Group.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will split that 👍

List<NonSemanticItemNode> childNodes = new ArrayList<>();

for (Item child : children) {
childNodes.add(buildNonSemanticNode(child, parentToChildren, locale));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This recursive traversal needs protection against recursive Group membership.

Recursive Groups can exist in the Item model, and other core code such as SemanticsMetadataProvider and EnrichedItemDTOMapper explicitly tracks ancestors to avoid a StackOverflowError. With a hierarchy such as A -> B -> C -> B, where A is a root Group, this method will keep recursively building B -> C -> B -> ....

Could we carry an ancestor/visited set through buildNonSemanticNode, skip a child that is already an ancestor, and add a corresponding regression test?

@mherwege mherwege Aug 10, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this an issue? The SemanticsMetadataProvider would not allows this recursive structure to be created in the first place. The semantics namespace is also protected from creating anything directly, it can only be done through item tags.
I see, it is because non-semantic nodes are in this as well.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will address this 👍

*/
package org.openhab.core.voice.text.interpreter.llm;

import static org.openhab.core.semantics.internal.SemanticsMetadataProvider.NAMESPACE;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we avoid depending on SemanticsMetadataProvider here? It is in org.openhab.core.semantics.internal, so its constants are implementation details of the semantics bundle rather than API for other bundles.

Since the metadata namespace and relation names are now intentionally consumed by another bundle, they should probably be exposed from a suitable class in the public org.openhab.core.semantics package, or the relationship lookup itself could be exposed through the semantics API. SemanticsMetadataProvider and LLMItemSerializer could then both use that public contract.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure 👍

Signed-off-by: Florian Hotze <dev@florianhotze.com>
Signed-off-by: Florian Hotze <dev@florianhotze.com>
@florian-h05
florian-h05 requested a review from wborn August 13, 2026 20:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants