Tinderbox Forum

Adding Notes to an Agent?

Hi Folks,

I am designing my course for the semester, and I use a map that has adornments for each day. I add topics, readings, assignments, learning activities, etc. Using adornments lets me see everything at once, but I also need a space to plan the sequence of particular days, adding notes to capture minor activities for the day. (I often use an adornment with a time grid to assign sequence and duration to activities.) I used to just drag the notes from the Day adornment to a container for that day, then work within that container, arranging and adding the minor things.

It ends up looking like this:

I was inspired by Mark’s recent video to use smart adornments. I assigned the user attribute Day_#, and then I hoped to use Day_# to create aliases that could be sorted into containers that I could then use to plan each day individually. Naturally, an agent seemed best for this. So I created them. But. I realized that I could add an adornment (the time grid for the day) within the agent, but I could not add new notes for the minor activities. I would rather not have the minor, low-level stuff on the main set of adornments for the whole semester because it gets in the way of clearly perceiving what is going on (and what needs to be changed).

This is a simple representation of what I have.

Is there some way around this problem? I thought about creating an alias within the agent that then might be transferred to a container for the specific day, but I wasn’t sure how to stop the action from constantly creating new copies in that day container. Further, how do I handle the problem of moving, say, a reading, from one day to another? It works fine with agents, but …

Thanks as usual for your thoughts and for your goodwill.

Cheers,

Kent

1 Like

Inside an agent (whether active or even if turned off):

  • you can’t create (original) notes at all
  • you can create adornments, though it is best to do so with the agents auto-cleanup ($CleanupAction) disabled.
    • You can (I just tested!) use smart adornment within an agent map. As the adornment’s query is run after the agent’s in each agent cycle, the smart adornment query will trump an active grid cleanup in the agent map.
  • You can make aliases of the aliases in the map (something else I just tried for the first time.

Perhaps the last offers a solution, by essentially duplicating the existing alias, the new alias can then be dragged away to the new location without agent making a new version.

If you want your workflow to ‘empty’ the agent, i.e. removing the alias to elsewhere and it not being replaced, you need do something (e.g. set an attribute value) to that alias when it is moved out of the agent such that the note no longer matches the agent’s query.

I tested an agent OnRemove action but it seems to have no effect on the note. As per documented behaviour, the OnRemove action should fire and apply its effect to the original. IOW, i.e. if the attribute(s) affected are intrinsic, even though the agent’s OnRemove is triggered by the alias’ move, the value set is that of the original and not the alias. Currently it appears an OnRemove action is being applied to note added to a container (i.e. both OnAdd and OnRemove code are applied!).

When the latter (OnRemove) is fixed, that might be the neatest approach.

This doesn’t speak to your specific question but I’m putting together my Winter courses as I write and have similar needs/concerns about how to go about scheduling. For the last two terms though, I’ve been using the Attribute Browser rather than agents for this work and it’s working well.

Like you, I use the map to sort out the arrangement and pacing of topics to be covered and assignments to be submitted. I then use map placement to set a $cDate attribute that does the same thing as your $Day_#. But then, instead of using agents, I open a tab with the Attribute Browser and view my notes organized by $cDate. This automatically arranges all of my scheduled notes into a chronological class schedule that looks like this:

As for the notes you want to add to your agents, on my main map, I have a note called “Odds and Ends” that contains notes for all the small things I don’t want crowding my main map. These notes, however, appear in the Attribute Browser. If they already have a $cDate, they are slotted into the schedule. If they don’t, they are listed in the “no value” grouping: to assign a date I just drag them where I want them.

So for me, the AB creates the daily schedule I want without me having to fiddle with agents.

ps—I use the query box in the AB to exclude notes based on prototypes, which might be useful if you have things on the map you don’t want on your schedule. My initial query (it will grow as my course plan does) is:

The real idea of agents is that they’re active — that they’re always adding and removing stuff. That’s not really what we’re doing here: our agent is just a way to get a bunch of aliases of notes that have a Day#.

What I’d suggest is that you make those aliases — using an agent is fine — and then copy/paste the aliases into a regular container. That won’t automatically gather new notes with a Day#, but my impression is that work is now mostly done. (You could create an agent that looks for notes with a Day# that are not also inside() your working container; these are new notes for which you need to make new aliases).

1 Like

Thanks Mark A., Brian, and Mark B! It does look like this manual copying over of the aliases is the best strategy. What I end up doing for each day is adding a lot of smaller activities, stretched to indicate the time spent, so that each day-note/container looks like this:

The idea is that only the colorful notes would be located on the whole-semester map. I could do the copying of the aliases before each class period, so that any changes I make will first be reflected in the agents.

Note: I wasn’t sure if the aliases would then be re-collected into the agent, but they were not. I realized then that the user-assigned attribute (Day_#) would only be intrinsic to the original note. And so changing the Day_# for the alias changed the original note. Yet another example of how working with a document is the best way to learn Tinderbox.

An agent doesn’t collect anything, rather it creates a new alias inside the agent for each object that matches the agent’s query. This is why if you drag an alias out of an agent, it simply generates a new one unless/until you do something so the original note in question no longer matches the query. An agent only create one alias per object even if several are in scope (e.g. an original and one of its aliases). An agent can never match an adornment. See more on agents.

You may be confusing agents with smart adornments. The latter uses a query but:

  • The scope of the query is always limited to the current map (regardless of whether the query implies a broader scope).
  • A smart adornment doesn’t creates aliases but instead moves matching items on the map atop the smart adornment. A smart adornment cannot match/move another adornment.

Thus whilst agents and smart adornments both use agents, they work in different ways. More on smart adornments.

FWIW, there is also a way to use an agent to move notes to a container of your choice. Either the alias or the original.
I made a little TB document with a few adornments (Feb 4 -7), that have an OnAdd action like:

$Checked = false; $Day_# = 1;

Then an agent with the query:

$Checked == false & $Prototype == “Task”;

and the action:

$Container = $Day_#;

so that the alias, that was just created by the agent, will be moved into the container $Day_#, which is an key attribute of the note, that was added on the adornment.

The container itself has an OnAdd action:

$Checked = true;

so that the agent will not create another copy (alias) of this note.
This could be any boolean KeyAttribute, I only used $Checked as it came first to my mind.
Now, if you drag the note from one adornment to the next, the KA $Checked is set again to false, the agent creates a new alias and moves this one to the next container, so that there are two aliases of the original note now. You can avoid this by moving around the original note with CMD-x, CMD-v, because by cutting the original, all aliases will be deleted.
And I made a prototype for the containers with the OnAdd action.

Here is the TBX file:
Container.tbx.zip (46.4 KB)

1 Like

Before new users get confused. For agent (not smart adornments):

  • An agent query creates aliases of in-scope notes (including alias and other agents but never adornments).
  • An agent action may move an original note or agent, or an alias of these by setting that objects $Container to a new value. If this is done to an alias within an agent, the alias moves to the new container and the agent creates a a new alias to replace it on the next agent cycle. Aside, dragging an alias out of an agent has the same effect of spawning a new alias in the agent.

Note that $Container is an intrinsic attribute. That is to say an alias(es) may hold a different value to that of their original note. In an agent action this:

$Container="New place";

moves the alias in the agent into the container ‘New place’ (and a new alias of the same note is added to the agent next agent update cycle). However:

$Container(original)="New place";

moves the original note of the alias to that location. See more on the original designator.

2 Likes

Kay, thanks for this! Your file does exactly what I want.

I am having a strange problem with my own file, however. I cannot get the agent to move the aliases to the new target container. Instead, it moves them to a new container at the root level, not the target one, which is several children deep. I have tried using the action $Container=$Day_#, just like in your example. (That approach would be ideal because I would need only one agent, rather than an agent for each day.) I also tried using $Container=“1” for the $Day_#, and I even put the agent and the target containers in the same parent container. Nevertheless, each time it moved the alias to a container at the root level.

What confused me was that in the file you created, it would always put the alias in the desired container, even if the container were not at the root level. Why did it work in your file and not mine? I couldn’t see anything special about the way you named your containers (just a simple 1, 2, 3).

At this point, I’ve lost all time-saving utility from the effort I’ve put into this, but it has become a puzzle to solve and something to learn.

Thanks again to all.

–Kent

Well, I’m not sure what happened, but now it seems to be working. I simply tried a few new actions, and then returning to the $Container=$Day_# caused the desired result. I’m 99% certain that it was correctly typed each of the previous times.

Another possibility is that I may at first have been trying to put it in a container named “01” instead of the $Day_# of “1”. I definitely renamed it to “1” at some point, but maybe after some initial failures. This occurred to me because I found that once it started working, it sorted properly except for containers 2-9, which I had named 02-09. Once I renamed them and deleted the new containers 2-9 it had created at the root level, it worked.

So perhaps I first tried to move the aliases to “01”, and it created a “1” container at the root level (that I did not notice until later). Once that root-level container was created, then all aliases would be moved there before the container at a deeper level.

Hi Kent,

I don’t know your file exactly, but things can get a bit tricky here and there… :grinning:
If there is only one container with the name “1”, everything works as expected, but if there are more containers with this name, Tinderbox obviously “guesses”, which of the both you want to use.
In such a case, it is safer to use the full path name within in the agent action, like:

$Container = “/Blah/Blaah/” + $Day_#;

when your file looks like:

2020-01-20_23-13-21

I attach you another example of this file, in which the containers “2”-“4” exist twice, and the “1” only in a deeper level. You can try it:

  1. With the agent like it is
  2. With the agent like it was in the last example (without the path)

and see, what happens to the note…
HTH

Container2.tbx (91.6 KB)

Actually, it doesn’t guess. All matches are made to the first (non-unique $Name) match as sorted by $OutlineOrder. If container titles are not unique use $Path rather than just $Name, but note that can’t work if two same-named notes or containers are siblings (as both have the same path).

1 Like

I also still have a lot to learn… :sweat_smile:

1 Like

That illustrates it nicely, thanks Kay.

And Mark, it’s helpful to know about the $OutlineOrder and $Path versus $Name. Would $Path then be another way to move an alias or a note? Instead of:

$Container = “/Blah/Blaah/” + $Day_#;

I tried using:

$Path = "/Blah/Blaah/" + $Day_#

But that did not seem to work. I thought that changing the $Path attribute would have the same effect as changing the $Container attribute. Are they different kinds of attributes? Can $Path not be used in an action? Does $Container have a special kind of permission?

Thanks again.

As you can see here, in @mwra’s TB Reference (aTBRef), $Path is a read-only attribute, so this won’t work.

I think you’ve misunderstood the values to set (i.e. $Path instead of $Name) with the attribute being set ($Container). Normally, to set a new container, we just use the title of a note (i.e. $Name), on the assumption that the title is unique. Thus, if we set the container, e.g. setting the original in an agent action:

$Container(original)="Blaah/";

But what if the note (or container note) ‘Blaah’ exists in more than place in the note? Now if we set the container:

$Container(original)="Blaah/";

Now the new container used is always the “Blaah” note with the lowest $OutlineOrder†. But if we know the full $Path of the same-named notes (e.g. /Dot/Blaah vs. /Dash/Blaah) we can unambiguously say we want a particular one:

$Container(original)="/Dash/Blaah/";

Note that path values always start with a forward slash.

† Actually it is a little more complex than ‘lowest $OutlineOrder’.That rule of thumb generally holds if the code (e.g. in an agent) is executed at the beginning or end of the outline. If the agent is part-way through the outline and it lies between the two matching notes in the outline, then the second note is the first match and the one used. If it’s confusing it is nature telling you not to use $Name for setting attributes if the $Name is not unique!

There is one edge case I only mention so no one thinks I’ve overlooked it, which is that of having two sibling notes of the same $Name. Of course, they also share the same path (i.e. $Path value) as they have the same $Name and the same parent ($Container). Can we differentiate these? Yes, see use of a note ID ($ID) as a designator. But, I’d suggest not setting out on a document design that can only only work by using ID designators without considering if there is a better design method.

Sidenote: one way around lots of same-named notes is to give them actual unique names but to set the duplicate screen name via a display expression. Thus if you have a set of projects, each needing the same sub-container “References”, give the actual containers a unique $Name and set their $DisplayExpression to "References". On screen each container will have the same name whilst being uniquely addressable via their actual $Name.

1 Like

Thanks! That’s perfectly clear now.

1 Like