Bot mutating its own input
# support
n
Is it considered an anti-pattern to have a bot update its own input? Would this trigger an update loop? I see the following code block in the fhir server repo that errors on operations occurring too quickly on a given resource. https://github.com/medplum/medplum/blob/38c20342ec77c1c01ad718dace4432c72bf7ad7d/packages/server/src/fhir/repo.ts#L671-L691 Is this the primary mechanism that prevents the update loop? My use case is to tie a Communication resource to an Encounter. To achieve this, a Communication subscription is setup with a bot that finds/creates an Encounter and ties it to the input Communication with an update. Curious - is there any documentation around this concept of Bots mutating their input?
It seems that the
isNotModified
check is preventing an update loop https://github.com/medplum/medplum/blob/38c20342ec77c1c01ad718dace4432c72bf7ad7d/packages/server/src/fhir/repo.ts#L506-L512 However, there is still an unnecessary reinvokation of the Bot which no-ops Depending on how quickly the reinvoking of the Bot occurs, an error will be encountered with too many versions.
r
@node , I wouldn't say it's an anti-pattern, but it's definitely a "proceeed with caution" pattern.
n
Could be interesting if the api allowed clients to signal along with a mutation to not trigger certain subscriptions. For instance, take the following example of a bot that updates a communication with a sentiment value:
Copy code
ts
import { BotEvent, MedplumClient } from '@medplum/core';
import { Communication } from '@medplum/fhirtypes';

export async function handler(medplum: MedplumClient, event: BotEvent<Communication>): Promise<boolean> {
  const communication = event.input;

  const content = communication.payload?.at(0)?.contentString;
  if (!content) {
    return true;
  }

  const sentimentExt = communication.extension?.find((e) => e.url === 'sentiment');
  if (sentimentExt) {
    return true;
  }

  const extension = communication.extension ?? [];
  const sentiment = await getSentiment(content);

  await medplum.updateResource({
    ...communication,
    extension: extension.concat({ url: 'sentiment', valueString: JSON.stringify(sentiment) }),
  });

  return true;
}

const getSentiment = async (message: string): Promise<{ magnitude: number; score: number }> => {
  // TODO: implement
  return {
    magnitude: Math.random(),
    score: message.length,
  };
};
If
BotEvent<T>
exposed the subscription id that triggered it, the
updateResource
could take an optional list of subscriptions to not trigger as part of the update. Assuming it's supported, another option is to specify a more detailed subscription criteria for this bot that omits Communicaions which already have a sentiment extension. This would provide less "colocation" but seems reasonable.
r
One way to prevent these loops is to tighten up you subscription "criteria". For instance, only respond to communications that are missing an
encounter
property
haha great minds 🧠
n
For the communication linking to encounter use case, would this subscription critera update make sense?
criteria: 'Communication?encounter:missing=true'
r
yes, thats' what I was thinking
n
Maybe an item for another support thread but how might I search a resource (or set filter criteria for a Subscription) based on an extensions existence (or non existence) by url or by value? For instance, in the Communication sentiment extension example, how might I prevent the re-invokation of the Bot with a criteria that filters out Communications that already have a sentiment extension? I tried using the
_filter
option as:
Communication?_filter=extension ni {url}
But I get an error
Unknown search paramter: extension
Wasn't have much success searching existing support items or docs for searching/querying by extension I wonder if this is a use case for a custom
SearchParameter
? I tried setting one up but am getting unknown search parameter.
r
Hi @node , do you mind posting in a new thread. I can give you a quick asnswer there
157 Views