notes

package
v1.0.0-alpha.25 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 17, 2026 License: MIT Imports: 8 Imported by: 0

Documentation

Overview

Package notes is a per-agent, cross-session key/value store the model writes via the note_* tools. Distinct from the chat-message store: notes are durable facts the user expects the agent to remember between sessions, not conversation history. Storage shares memory.db with the message store but lives in its own `notes` table.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrInvalidKey   = errors.New("invalid note key")
	ErrNoteTooLarge = errors.New("note content exceeds size cap")
	ErrTooManyNotes = errors.New("note count would exceed cap")
)

Sentinel errors. Wrapped with %w at every package boundary so callers can `errors.Is` to distinguish the user-fixable cases (oversize content, key collision past the cap) from genuine IO failures.

Functions

func RenderInContextBlock

func RenderInContextBlock(pinned []Note) string

RenderInContextBlock renders the pinned-notes section that flows into the system prompt on every step. Distinct from RenderPromptSection (the table of all notes by preview) in that each pinned note appears as a full-content `## <key>` markdown section — the model gets the whole body, not just a one-line preview, because pinned notes are facts it's expected to lean on without re-fetching.

Empty input → empty string so the caller can skip the separator.

func RenderPromptSection

func RenderPromptSection(notes []Note) string

RenderPromptSection turns a list of notes into the `## Notes` block injected into the agent's system prompt by the PrepareStep callback. Empty input returns the empty string so the caller can skip the separator entirely.

Output shape (markdown):

## Notes

| Key | Updated | Preview |
|-----|---------|---------|
| `k8s-cluster`   | 5m ago | homelab cluster, 3 nodes |
| `kubeconfig-path` | 2d ago | /kubeconfig.yaml         |

Notes persist across sessions. Use `note_show <key>` for full content;
`note_save` / `note_delete` to mutate.

Cells are sanitised: pipes in the preview are escaped to keep the table well-formed (rare, but cheap).

Types

type Note

type Note struct {
	Key       string
	Content   string
	Preview   string
	InContext bool
	CreatedAt time.Time
	UpdatedAt time.Time
}

Note is one stored fact. Preview is denormalised on Save so list rendering doesn't have to re-compute it across every row on every PrepareStep call. InContext, when true, marks the note for full inclusion in the agent's system prompt on every step — the model "pins" a fact it expects to reference frequently.

type Store

type Store struct {
	// contains filtered or unexported fields
}

func NewStore

func NewStore(ctx context.Context, db *sql.DB) (*Store, error)

NewStore opens (or migrates) the notes table on the supplied connection. Safe to call alongside memory.NewStore on the same db — the two stores use disjoint tables.

func (*Store) Count

func (s *Store) Count(ctx context.Context) (int, error)

Count returns the total number of stored notes. Cheap — used by Save to gate new-key inserts against the maxCount quota.

func (*Store) Delete

func (s *Store) Delete(ctx context.Context, key string) error

Delete removes a note by key. Missing keys are silently successful — the tool layer surfaces "deleted (or already absent)" to the model regardless.

func (*Store) Get

func (s *Store) Get(ctx context.Context, key string) (Note, error)

Get returns one note by key. sql.ErrNoRows is returned untouched so callers can errors.Is(err, sql.ErrNoRows) to render a "no such key" hint.

func (*Store) List

func (s *Store) List(ctx context.Context) ([]Note, error)

List returns every note ordered by most-recently-updated first. The model uses this ordering when deciding what's still relevant — touching a note acts as an implicit "this still matters".

func (*Store) ListInContext

func (s *Store) ListInContext(ctx context.Context) ([]Note, error)

ListInContext returns only the notes flagged in_context = 1. Used by the PrepareStep callback to render the per-step pinned block. Same row shape as List so the renderer can treat both uniformly.

func (*Store) Save

func (s *Store) Save(ctx context.Context, key, content string, maxBytes, maxCount int) error

Save upserts a note. Returns ErrInvalidKey if the key fails the validation regex, ErrNoteTooLarge if len(content) > maxBytes, and ErrTooManyNotes if inserting a *new* key would exceed maxCount (updates to an existing key are unaffected by the count guard).

Quotas live here, not in the tools layer, so there is one source of truth — anyone wiring a different surface (test harness, REPL, future operator RPC) gets the same enforcement for free.

func (*Store) SetInContext

func (s *Store) SetInContext(ctx context.Context, key string, inContext bool) error

SetInContext flips a note's in_context flag. Errors with sql.ErrNoRows if the key doesn't exist so the tool layer can surface a clean "no such note" hint.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL