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 void once UMS accepts the write; the updated value then arrives back through the conversations/update stream (see above) rather than in the dispatch() 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.note first 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.note fresh (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-note dispatch 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: true key. 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.