# Memory

{/* Generated from backend/features/recipes/catalogue/memory.yaml by `make arch`. Never edit this page: edit the recipe and run `make arch`, or `--check` fails. */}

Give one agent a memory: notes about each person and about the business, taken after every conversation and handed back at the start of the next one.

This page is made from the recipe `memory`, version 1, and says nothing the recipe does not. [How a recipe is composed](/cookbook) explains every word it uses.

## Its setup

\[The agent that remembers\] remembers each person and what it learns about the business, and has it in mind when its next conversation starts.

Each phrase in brackets is a parameter the recipe asks for, named as the table of parameters below names it.

## Its parts, in the order data travels

1. **automation `note_each_conversation`** — Runs the noting when a conversation of the agent ends, tests left out.
   - set off by `interaction_ended`, with `agent` `${param.agent}`, `leave_out_tests` `true`
   - runs the flow `noting`
2. **placement `before_each_conversation`** — Hands the agent its newest notes before its first turn.
   - sits in the `pre` slot of the agent `${param.agent}` (the value of the parameter `agent`) and runs the tool `handing_over`
3. **flow `noting`** — Notes the business first and then, when the conversation has a contact, the person.
   - step `business` runs the tool `note_business`
   - step `clean_business` runs the tool `redact`
   - step `keep_business` runs the tool `${resource.notes.write_tool}` (the `write_tool` of this recipe's `notes`)
   - step `person` runs the tool `note_person`
   - step `clean_person` runs the tool `redact`
   - step `keep_person` runs the tool `${resource.notes.write_tool}` (the `write_tool` of this recipe's `notes`)
4. **flow `hand_over`** — Reads the newest business notes and, when the conversation has a contact, that person's newest notes.
   - step `business` runs the tool `${resource.notes.query_tool}` (the `query_tool` of this recipe's `notes`)
   - step `person` runs the tool `${resource.notes.query_tool}` (the `query_tool` of this recipe's `notes`)
   - step `business_only` runs the tool `gather`
   - step `both` runs the tool `gather`
5. **tool `note_person`** — Asks a model for the notes worth keeping about the person the agent spoke with.
   - runs the built-in `draft_text`
6. **tool `note_business`** — Asks a model for the notes worth keeping about the business, which reach every conversation.
   - runs the built-in `draft_text`
7. **tool `redact`** — Replaces each card, bank account and identity number in the notes by a placeholder.
   - runs the built-in `redact_sensitive_numbers`
8. **tool `gather`** — Hands the business notes and the person's notes back as one answer.
   - runs the built-in `pass_value`
9. **tool `handing_over`** — Offers the handing-over as one tool, handed the contact of the conversation it runs in.
   - runs the flow `hand_over` offered as one tool
10. **collection `notes`** — Keeps every note, about a person or about the business, one per row.

## Its parameters

| Parameter | Kind | What it asks | Value |
|---|---|---|---|
| `agent` | agent | The agent that remembers | required; fixed once installed |
| `notice` | text | What is worth noticing — Guides the model that takes the notes after each conversation. | default `What the person asked for, prefers or told us about themselves that would help next time, and what was promised to them; about the business, what was learnt that will hold for anyone who calls. When nothing is worth keeping, or nobody spoke, note nothing. Never copy a payment card, bank account or identity number into a note.` |
| `person_notes` | number | Notes about the person handed over at the start | default `5`; from 0 to 20 |
| `business_notes` | number | Notes about the business handed over at the start | default `5`; from 0 to 20 |

## How its data moves

The flow `noting`:

| Step | Input | Value | Comes from |
|---|---|---|---|
| `business` | `input` | `$ref:trigger.transcript` | `transcript` of what set the run off |
| `clean_business` | `text` | `$ref:business.rows` | `rows` of the step `business`'s answer |
| `keep_business` | `rows` | `$ref:clean_business.text` | `text` of the step `clean_business`'s answer |
| `keep_business` | `about` | `business` | fixed |
| `keep_business` | `origin` | `$ref:trigger.interaction_id` | `interaction_id` of what set the run off |
| `person` | `input` | `$ref:trigger.transcript` | `transcript` of what set the run off |
| `clean_person` | `text` | `$ref:person.rows` | `rows` of the step `person`'s answer |
| `keep_person` | `rows` | `$ref:clean_person.text` | `text` of the step `clean_person`'s answer |
| `keep_person` | `contact` | `$ref:trigger.contact` | `contact` of what set the run off |
| `keep_person` | `about` | `person` | fixed |
| `keep_person` | `origin` | `$ref:trigger.interaction_id` | `interaction_id` of what set the run off |

The flow `hand_over`:

| Step | Input | Value | Comes from |
|---|---|---|---|
| `business` | `about` | `business` | fixed |
| `business` | `newest_first` | `true` | fixed |
| `business` | `limit` | `${param.business_notes}` | replace with the value of the parameter `business_notes` |
| `person` | `contact` | `$ref:trigger.conversation_contact` | `conversation_contact` of what set the run off |
| `person` | `about` | `person` | fixed |
| `person` | `newest_first` | `true` | fixed |
| `person` | `limit` | `${param.person_notes}` | replace with the value of the parameter `person_notes` |
| `business_only` | `value.business` | `$ref:business.records` | `records` of the step `business`'s answer |
| `both` | `value.business` | `$ref:business.records` | `records` of the step `business`'s answer |
| `both` | `value.person` | `$ref:person.records` | `records` of the step `person`'s answer |

A value written `$ref:<step>.<path>` is what an earlier step answered, and `$ref:trigger.<path>` is what set the run off. A value with `${...}` in it is a placeholder: building it by hand, replace it with your own.

## Build it yourself

To install it as it is: `POST /api/v1/recipes/{key}/install` with the key `memory` and a value for each parameter. To build the same thing with your own particulars, make each part in this order -- each one may name the ones before it -- with the operations below.

The YAML under each part is the recipe's declaration, not a request body: the API takes other names for the same things (a tool's `builtin` is `source` and `config.builtin`, a step's `tool` is `tool_id`, an edge's `from` is `source_step_id`). [From a recipe to the API](/cookbook#from-a-recipe-to-the-api) on the lead page maps every field, kind by kind.

### 1. collection `notes`

Keeps every note, about a person or about the business, one per row.

- `POST /api/v1/collections` creates the collection with its fields.
- `PATCH /api/v1/collections/{collection_id}` sets the identity field once the fields exist.

```yaml
kind: collection
key: notes
name: Memory of ${param.agent.name}
says: Keeps every note, about a person or about the business, one per row.
description: 'What ${param.agent.name} remembers: one note per row, about the contact it names
  or, with no contact, about the business.'
fields:
- key: contact
  label: Contact
  type: text
  personal: true
- key: note
  label: Note
  type: text
  required: true
  personal: true
- key: about
  label: About
  type: option
  required: true
  options:
  - person
  - business
- key: day
  label: Day
  type: date
  default:
    kind: creation_day
- key: origin
  label: Conversation
  type: text
contact: contact
editable: true
records: whole
```

### 2. tool `note_person`

Asks a model for the notes worth keeping about the person the agent spoke with.

- `POST /api/v1/tools` creates the instance: a built-in's, or a flow offered as one tool by its `config.flow_id`.

```yaml
kind: tool
key: note_person
name: Note what is worth remembering about the person
says: Asks a model for the notes worth keeping about the person the agent spoke with.
description: Drafts the notes about the person after a conversation of ${param.agent.name}.
builtin: draft_text
config:
  rows:
  - key: note
    type: string
    description: One note about the person, in one short sentence.
fixed:
  instructions: 'You read the transcript of a conversation the agent had with one person,
    and note what the agent should remember about that person the next time they speak. Each
    note is one short sentence about that person alone. Note nothing about the business here.
    Never copy a payment card, bank account or identity number into a note. When the transcript
    is empty or nothing about the person is worth keeping, answer []. What is worth noticing:
    ${param.notice}'
deadline_seconds: 120
```

### 3. tool `note_business`

Asks a model for the notes worth keeping about the business, which reach every conversation.

- `POST /api/v1/tools` creates the instance: a built-in's, or a flow offered as one tool by its `config.flow_id`.

```yaml
kind: tool
key: note_business
name: Note what is worth remembering about the business
says: Asks a model for the notes worth keeping about the business, which reach every conversation.
description: Drafts the notes about the business after a conversation of ${param.agent.name}.
builtin: draft_text
config:
  rows:
  - key: note
    type: string
    description: One note about the business, in one short sentence.
fixed:
  instructions: 'You read the transcript of a conversation the agent had, and note what the
    agent learnt about the business it works for that will hold in every conversation, with
    anyone. Each note is one short sentence that names no person and says nothing only the
    person in this conversation should hear. Never copy a payment card, bank account or identity
    number into a note. When the transcript is empty or nothing about the business is worth
    keeping, answer []. What is worth noticing: ${param.notice}'
deadline_seconds: 120
```

### 4. tool `redact`

Replaces each card, bank account and identity number in the notes by a placeholder.

- `POST /api/v1/tools` creates the instance: a built-in's, or a flow offered as one tool by its `config.flow_id`.

```yaml
kind: tool
key: redact
name: Replace sensitive numbers in the notes
says: Replaces each card, bank account and identity number in the notes by a placeholder.
builtin: redact_sensitive_numbers
```

### 5. tool `gather`

Hands the business notes and the person's notes back as one answer.

- `POST /api/v1/tools` creates the instance: a built-in's, or a flow offered as one tool by its `config.flow_id`.

```yaml
kind: tool
key: gather
name: Hand the notes over together
says: Hands the business notes and the person's notes back as one answer.
builtin: pass_value
```

### 6. flow `noting`

Notes the business first and then, when the conversation has a contact, the person.

- `POST /api/v1/flows` creates the flow.
- `POST /api/v1/flows/{flow_id}/steps` adds each step, naming the tool it runs.
- `POST /api/v1/flows/{flow_id}/edges` adds each edge.
- `PATCH /api/v1/flows/{flow_id}/entry-step` sets the step a run starts at.

```yaml
kind: flow
key: noting
name: Noting after each conversation of ${param.agent.name}
says: Notes the business first and then, when the conversation has a contact, the person.
steps:
- key: business
  tool: ${resource.note_business}
  params:
    input: $ref:trigger.transcript
- key: clean_business
  tool: ${resource.redact}
  params:
    text: $ref:business.rows
- key: keep_business
  tool: ${resource.notes.write_tool}
  params:
    rows: $ref:clean_business.text
    about: business
    origin: $ref:trigger.interaction_id
- key: person
  tool: ${resource.note_person}
  params:
    input: $ref:trigger.transcript
- key: clean_person
  tool: ${resource.redact}
  params:
    text: $ref:person.rows
- key: keep_person
  tool: ${resource.notes.write_tool}
  params:
    rows: $ref:clean_person.text
    contact: $ref:trigger.contact
    about: person
    origin: $ref:trigger.interaction_id
edges:
- from: business
  to: clean_business
- from: clean_business
  to: keep_business
- from: keep_business
  to: person
  condition:
    field: trigger.contact
    op: exists
- from: person
  to: clean_person
- from: clean_person
  to: keep_person
```

### 7. flow `hand_over`

Reads the newest business notes and, when the conversation has a contact, that person's newest notes.

- `POST /api/v1/flows` creates the flow.
- `POST /api/v1/flows/{flow_id}/steps` adds each step, naming the tool it runs.
- `POST /api/v1/flows/{flow_id}/edges` adds each edge.
- `PATCH /api/v1/flows/{flow_id}/entry-step` sets the step a run starts at.

```yaml
kind: flow
key: hand_over
name: Handing over before each conversation of ${param.agent.name}
says: Reads the newest business notes and, when the conversation has a contact, that person's
  newest notes.
steps:
- key: business
  tool: ${resource.notes.query_tool}
  params:
    about: business
    newest_first: true
    limit: ${param.business_notes}
- key: person
  tool: ${resource.notes.query_tool}
  params:
    contact: $ref:trigger.conversation_contact
    about: person
    newest_first: true
    limit: ${param.person_notes}
- key: both
  tool: ${resource.gather}
  params:
    value:
      business: $ref:business.records
      person: $ref:person.records
- key: business_only
  tool: ${resource.gather}
  params:
    value:
      business: $ref:business.records
edges:
- from: business
  to: person
  condition:
    field: trigger.conversation_contact
    op: exists
- from: business
  to: business_only
  condition:
    field: trigger.conversation_contact
    op: ===
- from: person
  to: both
```

### 8. tool `handing_over`

Offers the handing-over as one tool, handed the contact of the conversation it runs in.

- `POST /api/v1/tools` creates the instance: a built-in's, or a flow offered as one tool by its `config.flow_id`.

```yaml
kind: tool
key: handing_over
name: Remembered notes
says: Offers the handing-over as one tool, handed the contact of the conversation it runs
  in.
description: What ${param.agent.name} remembers about the business and about this contact.
flow: ${resource.hand_over}
fixed:
  conversation_contact: $ref:conversation.contact
```

### 9. automation `note_each_conversation`

Runs the noting when a conversation of the agent ends, tests left out.

- `POST /api/v1/automations` creates the automation on its trigger, running the flow.
- `PUT /api/v1/automations/{automation_id}/enabled` switches it on: an automation is created switched off.

```yaml
kind: automation
key: note_each_conversation
name: Noting each conversation of ${param.agent.name}
says: Runs the noting when a conversation of the agent ends, tests left out.
flow: ${resource.noting}
trigger:
  interaction_ended:
    agent: ${param.agent}
    leave_out_tests: true
```

### 10. placement `before_each_conversation`

Hands the agent its newest notes before its first turn.

No public operation places a tool in an agent's slot outside its versions yet. The nearest by hand puts the tool in the slot of the agent's draft and publishes it, which ties it to that version rather than to the agent:

- `PATCH /api/v1/agents/versions/{version_id}` adds the tool to the draft's `pre_hook_tool_ids` or `post_hook_tool_ids`.
- `POST /api/v1/agents/versions/{version_id}/publish` publishes the draft.

```yaml
kind: placement
key: before_each_conversation
name: Notes before each conversation
says: Hands the agent its newest notes before its first turn.
agent: ${param.agent}
slot: pre
tool: ${resource.handing_over}
```

## How to adapt it

Choose the agent, say in your own words what is worth noticing, and choose how many notes about the person and about the business reach each conversation. To build your own, keep its two halves -- after a conversation, a drafting step asked for rows, a step that replaces sensitive numbers and a write that fills in what the model must not choose; before one, a query of the newest notes in the agent's pre-conversation slot -- and change what is noted or how it is read.

## What cannot change once installed

Installed, every part is the recipe's: it is listed where its kind lives, marked as the recipe's, and refuses every edit and deletion by hand, naming the recipe.

- collection `notes`: its fields.
- tool `note_person`: its configuration and fixed values.
- tool `note_business`: its configuration and fixed values.
- tool `redact`: its configuration and fixed values.
- tool `gather`: its configuration and fixed values.
- flow `noting`: its steps and edges.
- flow `hand_over`: its steps and edges.
- tool `handing_over`: its configuration and fixed values.
- automation `note_each_conversation`: its trigger and flow.
- placement `before_each_conversation`: the agent, the slot and the tool it places.

What stays the organization's:

- the records in `notes`, read, written and deleted as any records are;
- the values of `notice`, `person_notes`, `business_notes`, changed on the installed recipe and written through to every part that uses them;
- not `agent`: the agent is fixed once installed, because it says which install this is -- moving the recipe to another agent is uninstalling it and installing it there;
- whether the recipe is on, which switches its automations on and off together;
- presentation -- a column's width, a step's position -- which changes nothing it runs.

## What retention deletes

The recipe declares the records of `notes` deleted whole: when the organization's retention window passes, a record with a personal field is deleted whole, rather than kept with its personal fields emptied. Its personal fields: `contact`, `note`.

## What it costs

What its parts consume -- a tool execution, a model's tokens, a message, storage -- is recorded and charged as those parts are, exactly as your own use of them is; nothing is charged for the recipe itself.
