Lets an agent attach a free-text note to a conversation, visible to any agent who has (or later takes) the conversation. The SDK's wire contract is a single opaque string per conversation — it does not model note authorship, timestamps, or multiple entries. If your UI needs multiple, timestamped, attributed notes (one per agent-turn, not one shared field), you encode that structure into the string yourself, as shown below.
Clients: all examples use only the public MessagingClient API — client.on({ callback }) for
events and client.dispatch({ action, value }) for actions. dispatch() returns a Promise;
inline references below omit await for brevity, but always await it in real code.
Reading the current note
What it does: Surfaces a conversation's note with no separate fetch — it rides along with the conversation data you're already consuming.
Instructions:
client.on({
callback: (event) => {
if (event.type === 'conversations/update') {
const { conversation } = event.value;
console.log(conversation.note); // '' if no note has ever been set
}
},
});
Conversation.note is populated from the wire on every conversations/update notification — the
same mapping used for every other conversation field. A note set by any agent, including an echo
of the current agent's own write, surfaces automatically this way.
Writing a note
What it does: Overwrites the conversation's note with the given string.
Instructions:
await client.dispatch({
action: 'conversation/set-summary-note',
value: { conversationId, note: 'Consumer requesting a refund, escalate if unresolved by EOD.' },
});
- Resolves
voidonce UMS accepts the write; the updated value then arrives back through theconversations/updatestream (see above) rather than in thedispatch()resolution itself. - This is a full overwrite, not an append — the previous note string is replaced entirely. If you
need to preserve prior content, read the current
conversation.notefirst and fold it into the string you send (see the multi-note pattern below).
⚠️ Note:
dispatch()re-sends whatever string you give it as-is; the SDK does not parse, validate, or interpret its contents.
Pattern: multiple timestamped, attributed notes
Since the wire field is a single string, an agent workspace UI that wants one entry per agent-turn — author, timestamp, text — treats the string as an opaque JSON-encoded array it owns the shape of. The SDK has no awareness this string happens to contain JSON.
interface AgentNote {
agentId: string;
name: string;
noteContent: string;
noteId: string;
time: number;
}
function parseNotes(note: string | undefined): AgentNote[] {
if (!note) return [];
try {
const parsed = JSON.parse(note);
return Array.isArray(parsed) ? parsed : [];
} catch {
return [];
}
}
async function saveNote(conversationId: string, existingNote: string | undefined, agent: { id: string; name: string }, content: string) {
const notes = parseNotes(existingNote);
const lastNote = [...notes].sort((a, b) => b.time - a.time)[0];
if (lastNote?.agentId === agent.id) {
// Same agent revisiting their own last note: update it in place rather than appending.
const idx = notes.findIndex((n) => n.noteId === lastNote.noteId);
notes[idx] = { ...notes[idx], noteContent: content };
} else {
notes.push({
agentId: agent.id,
name: agent.name,
noteContent: content,
noteId: `${agent.id}::${Date.now()}`,
time: Date.now(),
});
}
await client.dispatch({
action: 'conversation/set-summary-note',
value: { conversationId, note: JSON.stringify(notes) },
});
}
- The whole array is re-serialized and re-sent on every save — there's no per-note server-side
patch. Always read
conversation.notefresh (not a stale local copy) immediately before building the array to save, to minimize the window for the next caveat.
⚠️ Note: there's no concurrency control. If two agents save around the same time, the second
set-summary-notedispatch wins and silently overwrites the first, since the entire array is replaced on every write. Acceptable for a lightweight notes UI; an integration needing stronger guarantees would need its own optimistic-concurrency layer (e.g. compare-and-swap on a version field inside the JSON) on top of this.
⚠️ Note: if an automated conversation summary feature is enabled for the account, it is expected to append an entry to this same array with an additional
isAutoSummary: truekey. Nothing in the SDK or the pattern above special-cases that key — such an entry renders like any other note unless your UI explicitly checks for it.
Enforcing the max note length
What it does: Site setting messaging.agent.notes.max.length caps how long a note string may
be; UMS does not reject over-length writes, so validate client-side if you want to warn the agent
before they lose content on submit.
Instructions:
const { maxAgentNotesLength } = session.permissions.configuration;
if (JSON.stringify(notes).length > maxAgentNotesLength) {
// warn the agent / truncate before dispatching
}
maxAgentNotesLength is read once at connect time as part of session.permissions.configuration
(see authentication-flow.md for the full SessionObject /
permissions shape). If you adopt the multi-note JSON pattern above, remember the length limit
applies to the serialized array as a whole, not to each individual note's text.