feat(impression): expose entity identity updates

Add core-owned APIs for renaming canonical subjects and adding aliases so updater logic can request identity changes without bypassing indexes.

Synchronize bound active entity subjects after renames and keep capability test stubs aligned.
This commit is contained in:
2026-06-10 14:50:13 +08:00
parent a23657ec0c
commit 15c24154f8
4 changed files with 83 additions and 0 deletions

View File

@@ -57,6 +57,16 @@ public interface CognitionCapability {
*/
boolean bindActiveEntity(String runtimeId, String entityUuid);
/**
* Rename the canonical subject of a known entity and refresh entity/active-entity indexes.
*/
boolean renameEntitySubject(String entityUuid, String newSubject);
/**
* Add an alias or mention form for a known entity and refresh entity indexes.
*/
boolean addEntityAlias(String entityUuid, String alias, boolean deprecated);
/**
* Add or replace an impression on a known entity and refresh all entity indexes.
*/

View File

@@ -153,6 +153,45 @@ public class ImpressionCore implements StateSerializable {
return true;
}
/**
* Rename the canonical subject of a known entity and keep its previous subject as a historical alias.
*/
@CapabilityMethod
public boolean renameEntitySubject(String entityUuid, String newSubject) {
Entity entity = knownEntitiesByUuid.get(entityUuid);
if (entity == null || newSubject == null || newSubject.isBlank()) {
return false;
}
boolean renamed = entity.renameSubject(newSubject.trim());
if (!renamed) {
return false;
}
refreshKnownEntityIndexes(entity);
syncBoundActiveEntitySubjects(entity);
return true;
}
/**
* Add an alias or mention form for a known entity and refresh search indexes.
*/
@CapabilityMethod
public boolean addEntityAlias(String entityUuid, String alias, boolean deprecated) {
Entity entity = knownEntitiesByUuid.get(entityUuid);
if (entity == null || alias == null || alias.isBlank()) {
return false;
}
boolean added = entity.addAlias(alias.trim(), deprecated);
if (!added) {
return false;
}
refreshKnownEntityIndexes(entity);
return true;
}
/**
* Update a known entity impression through the core so text/vector indexes stay consistent.
* newImpression can be null or blank to update the existing impression in place.
@@ -355,6 +394,20 @@ public class ImpressionCore implements StateSerializable {
refreshKnownEntityTextSearch(entity);
}
private void syncBoundActiveEntitySubjects(Entity entity) {
List<ActiveEntity> boundEntities;
synchronized (activeEntities) {
boundEntities = activeEntities.stream()
.filter(activeEntity -> entity.getUuid().equals(activeEntity.getBoundEntityUuid()))
.toList();
}
boundEntities.forEach(activeEntity -> {
activeEntity.updateSubject(entity.getSubject());
refreshActiveEntityTextSearch(activeEntity);
});
}
/**
* Replace text-search documents for one known entity.
*/

View File

@@ -174,6 +174,16 @@ class CommunicationProducerTest {
return false;
}
@Override
public boolean renameEntitySubject(String entityUuid, String newSubject) {
return false;
}
@Override
public boolean addEntityAlias(String entityUuid, String alias, boolean deprecated) {
return false;
}
@Override
public boolean updateEntityImpression(String entityUuid, String impression, String newImpression, double confidence) {
return false;

View File

@@ -127,6 +127,16 @@ class MemoryRuntimeTest {
return false;
}
@Override
public boolean renameEntitySubject(String entityUuid, String newSubject) {
return false;
}
@Override
public boolean addEntityAlias(String entityUuid, String alias, boolean deprecated) {
return false;
}
@Override
public boolean updateEntityImpression(String entityUuid, String impression, String newImpression, double confidence) {
return false;