/** * ONE user, bound once — and everything this agent does for them. * * A host serving a person re-stated the same three things on every call: whose * turn it is, what the model may say about them, and what the tools need to act * on their behalf. `forUser` names them once and hands back the four faces that * follow from it — this user's turns, their conversations, and what the agent * remembers about them. * * WHAT IS BOUND AND WHAT IS NOT is the whole design. `profile` and `context` * are FACTS about a person: true between requests, so they are bound here and * ride every call. `headers` are the authority of ONE request — they expire * with it — so they ride PER CALL and are never kept. A facade that remembered * the first request's cookie would spend one caller's authority on the next * caller's turn, and nothing downstream could tell the difference. * * IT IMPLEMENTS NOTHING. `chat` is `startChat` with the subject filled in, * `turns` is `createTurns`, `threads` is the store's own thread helpers and * `memories` is the composition's memory adapter — each scoped to this subject, * which is the one thing this file adds. */ import { type Json, type ThreadId } from "../core/index.js"; import type { UIMessage } from "ai"; import { type Turns } from "./interruptions.js"; import type { Memory } from "./memory.js"; import { type AgentDeps, type ChatOptions, type Turn } from "./turn.js"; /** Who this user is, for as long as the facade lives. */ export interface UserOptions { /** Server-trust identity facts, model-visible (the `[User]` block) — the same * channel `chat({ user })` fills, under the name a host thinks of it by. * Nothing the user typed belongs here: the model reads it as established. */ profile?: Record; /** What the guard and the host's own tools need to act for this person — * a tenant, a locale, an account id. JSON-only because it is BOUND: it * outlives the request that named it, and a closure bound into a long-lived * facade would run in turns its author never saw. */ context?: Record; } /** What one call brings that a facade cannot hold: the request's own authority, * the conversation to continue, and the way to stop it. `as`, `user` and * `context` are gone by construction — they were bound at {@link createUser} * and passing them per call is what this face exists to end. */ export type UserChatOptions = Omit; /** One conversation of this user's. */ export interface UserThread { readonly id: ThreadId; readonly createdAt: string; readonly updatedAt: string; /** The transcript, oldest first — read when it is asked for, never with the * listing: a settings screen shows twenty conversations and opens one. */ messages(): Promise; } /** This user's conversations. There is no `create` and no `chat` here: a thread * is what a turn leaves behind, so one begins at `user.chat(message)` and is * continued with `user.chat(message, { threadId })`. */ export interface Threads { /** Most recently touched first. */ list(): Promise; /** A thread this user does not own is `not-found` — never an empty transcript * that reads like a conversation nobody said anything in. */ get(id: string): Promise; delete(id: string): Promise; } /** What the agent remembers about this user — the person's own view of it, so * there is no `add`: a memory is made by the model calling `remember` in front * of them, and forgetting is theirs alone. */ export interface Memories { /** Everything, newest first. */ list(): Promise; delete(id: string): Promise; clear(): Promise; } export interface AgentUser { /** ONE turn of this user's conversation. The bound profile and context ride * along; `headers` are this request's and are not kept. */ chat(message: string, options?: UserChatOptions): Turn; /** The turns of theirs that are waiting on them. */ readonly turns: Turns; readonly threads: Threads; readonly memories: Memories; } /** Everything one agent does for one person. `agent.forUser` is the door; * this takes the composition, so a host that assembled its own can hang the * same face off it. */ export declare function createUser(deps: AgentDeps, subject: string, options?: UserOptions): AgentUser;