How do I program an agent to find aliases with specific name


(Richard Bullen) #1

I want an agent that shows all occurrences of an alias from one specific note.

I found the following recommendation in TbRef:

find($IsAlias & $Name.icontains(“Test”))

Logically this appears to fulfill my needs but the result is a list of all aliases in the whole document. This suggests that the “And” function is not being seen but its probably cockpit error.

What is the best prescription for locating and listing all the aliases that originate from one particular note?

Thanks.


(Mark Anderson) #2

If may be just forum auto-correct but do ensure you’re using straight and not ‘curly’ quotes, so:

find($IsAlias & $Name.icontains("Test"))

not

find($IsAlias & $Name.icontains(“Test”))

Anyway, if the note is called ‘Text’, then I would use:

find($Name=="Test" & $IsAlias)

We only want notes for the note or alias of ‘Text’ and then the extra filter drops out the original leaving only the aliases as for them $IsAlias is true.

If still getting erroneous result, can you post a minimal working example file. If your actual test case is more complex than described, I suggest peeling back to simpler steps. For instance is you’re actually referencing a note name passed as a variable, test the code first with a hard-coded name before moving to use a variable.

HTH


(Mark Anderson) #3

Also, don’t use find in an agent query, just use

$Name=="Test" & $IsAlias

But note that agents de-dupe so only one alias would be listed even if several. Therefore use an edict or stamp with find().


(Richard Bullen) #4

@mwr Thanks for your responses.
I’m confused about the use of an Edict or Stamp to use the Find statement.
I assume you’re applying these to an Agent, so wouldn’t you still need a query statement for the Agent?


(Galen Menzel) #5

The issue is that Tinderbox doesn’t support aliases of aliases, so you can’t use an agent to find all aliases with a specific name.

Each cycle, an agent iterates through every note in the document (including aliases) and evaluates its $AgentQuery on that note. If the $AgentQuery evaluates to true, an alias to that note is created as a child of the agent. However, in Tinderbox when you create an alias of an alias, you actually get an alias of the original note. Agents won’t create more than one alias of a note, so you can’t use an agent to find all aliases of a particular note.

Say you have a note with $ID 1527555444 and you have five aliases of that note throughout your document. If you created an agent with the query

$IsAlias & $ID(original)==1527555444

It would only ever have a single child, even though there are five aliases to note 1527555444 (actually six after the agent runs and creates another alias).

So to get the names of all aliases of a particular note, you have to do something like create a stamp with this action:

var id;
id = $ID;
$Text=find($IsAlias & $ID(original)==id)

When you apply this stamp to a note, it sets the text of the note to the names of all the note’s aliases.

As a side note, I would expect this stamp action to yield the same results, but it sets $Text to the empty string:

$Text=find($IsAlias & $ID(original)==$ID(that))

Does anyone know why that doesn’t work?


(Mark Anderson) #6

This can’t work because $ID(that) is the actual ID of the object on which the code is being run (and thus the find(), etc.). I think you meant something like:

$Text=find($IsAlias & $ID(original)==$MyNumber(that))

…where the calling note is storing, in a number-type attribute the $ID of the target original note .

The code doesn’t work because it appears that the ‘that’ designator isn’t functioning properly (I’ll report this separately).


(eastgate) #7

I’d not anticipated using find() in a stamp, so that not currently bound to anything. In the next update (b316 and later), stamps will bind that to this – the note being stamped.


(Mark Anderson) #8

So for now, put this code in a in an edict (so it’s not running continuously). I can confirm that this example does work as an edict:

$Text=find($IsAlias & $ID(original)==$MyNumber(that))

Just kicking myself for not also trying it in an edict as well as a Stamp. Bear in mind:

  • Stamp: One pass, manually invoked action, scope is current selection
  • Edict: Low repeat frequency action, scope is current note. N.B. committing a new edit to an existing edict will fire just that Edict once. Running File menu –> Update Agents Now will force all edicts to run once. So, with care an Edict can stand for a stamp in this scenario.
  • Rule: Always-on repeat action, scope current note.
  • AgentAction: Always-on repeat action, scope is alias of any notes matching the agent query.

(Galen Menzel) #9

$Text=find($IsAlias & $ID(original)==$ID(that)) does work as an edict. It’s just the same limitation of that in stamps.


(Mark Anderson) #10

See my earlier note about the error in using $ID(that) vs the desired $ID value stored in a number-type attribute e.g. $MyNumber(that). The latter is used in my code suggesting an edict. I would not expect your version to work as that is calling the $ID value of the note running the find(). No matter, it’s an easy enough mistake. I had to think about this a bit when first testing.


(Galen Menzel) #11

Ah, right because $ID is intrinsic, so $ID(that) evaluates to different values for the aliases and for the original. Gotcha.


(Richard Bullen) #12

$Text=find($IsAlias & $ID(original)==$MyNumber(that))

I have this working in a test case as an EDICT, so thanks for all the efforts to produce a result.

The result I get is a copy of each alias name separated by semicolons. Is there any way to format this result so that each items appears on a separate line?

Also I noted that if I manually inserted line breaks (return key) after each item, then saved the document, then moved a new note, then returned to the test case note all my manual formatting is removed and the layout returns to its original state. I suppose this is to be expected if the edict works as I think it does and continually reprocesses the instructions, but if that’s the case it would seem that having some way to format the result would be a necessity.

Thanks.


(Galen Menzel) #13

This will do it:

$Text=find($IsAlias & $ID(original)==$MyNumber(that)).format("\n")

You could also add to the edict to set $MyNumber automatically, say if you were to use this in a prototype:

$MyNumber=$ID(original);
$Text=find($IsAlias & $ID(original)==$MyNumber(that)).format("\n")

(Mark Anderson) #14

The solution to the layout is as per @galen’s solution above. The cause, which may affect other action coding you may try is also simple. You need to understand Tinderbox’s data types. Looking up find(), we see that:

The find() operator returns List-type data of the $Path of all items matching query.

So, we expect a List, which we find is:

A semi-colon delimited list of string values.

So, unless the find() returns one item, you should expect the semi-colon delimited list you reported.

As already noted .format("\n") can be used to format a returned list (List and Set type data) into a format of one list item per line (paragraph) suitable for use in $Text display or for subsequent export.

Each run of the edict refreshes $Text. So, as long as the formatting code is part of the same action code, the $Text will refresh to show your formatted data.