chore: clean up docs

This commit is contained in:
Caren Thomas
2025-10-09 17:45:05 -07:00
parent dbebadf2cf
commit 4e1c1c9079
355 changed files with 0 additions and 24067 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 342 B

View File

@@ -1,145 +0,0 @@
/* ────────────────────────────────────────────────────────────────
assets/leaderboard.css (namespaced so it never leaks styles)
──────────────────────────────────────────────────────────────── */
/* hide rows that dont match search */
#letta-leaderboard tr.hidden { display: none !important; }
/* clickable, sortable headers */
#letta-leaderboard thead th[data-key] {
cursor: pointer;
user-select: none;
position: relative;
}
#letta-leaderboard thead th.asc::after,
#letta-leaderboard thead th.desc::after {
position: absolute;
right: 6px;
top: 50%;
transform: translateY(-50%);
font-size: 10px;
line-height: 1;
}
#letta-leaderboard thead th.asc::after { content: "▲"; }
#letta-leaderboard thead th.desc::after { content: "▼"; }
/* bar-chart cells */
#letta-leaderboard .bar-cell {
position: relative;
padding: 8px;
overflow: hidden;
}
#letta-leaderboard .bar-viz {
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
height: 36px;
z-index: 1;
max-width: 100%;
border-radius: 0;
}
#letta-leaderboard .bar-cell span.value {
position: absolute;
left: 5px;
top: 50%;
transform: translateY(-50%);
background: rgba(255, 255, 255, 0.7);
padding: 0 4px;
font-size: 14px;
z-index: 2;
border-radius: 0;
}
#letta-leaderboard .bar-cell span.warn {
position: absolute;
right: 5px;
top: 50%;
transform: translateY(-50%);
font-size: 15px;
line-height: 1;
color: #dc3545;
cursor: help;
z-index: 2;
}
/* bar colours */
#letta-leaderboard .avg .bar-viz { background: rgba(40, 167, 69, 0.35); } /* green */
#letta-leaderboard .cost-ok .bar-viz { background: rgba(255, 193, 7, 0.35); } /* amber */
#letta-leaderboard .cost-high .bar-viz { background: rgba(220, 53, 69, 0.35); } /* red */
/* faint ruler + right border */
#letta-leaderboard .bar-cell::before {
content: "";
position: absolute;
top: 50%;
left: 0;
width: 100%;
height: 8px;
transform: translateY(-50%);
pointer-events: none;
background: repeating-linear-gradient(
90deg,
rgba(170, 170, 170, 0.5) 0 1px,
transparent 1px 25%
);
}
#letta-leaderboard .bar-cell::after {
content: "";
position: absolute;
top: 50%;
right: 0;
width: 1px;
height: 8px;
background: rgba(170, 170, 170, 0.5);
transform: translateY(-50%);
pointer-events: none;
}
/* table layout tweaks */
#letta-leaderboard tbody tr { height: 50px; }
#letta-leaderboard .metric { width: 32%; }
#letta-leaderboard table { table-layout: fixed; }
/* search box */
#letta-leaderboard #lb-search,
#letta-leaderboard #lb-search:focus {
border-radius: 0 !important;
outline: none;
}
/* ───────────────────────────────
Dark-mode overrides
(everything else inherits)
───────────────────────────────*/
:is(.dark) #letta-leaderboard {
/* 1. Bar-fill colours — a hair brighter & less transparent */
.avg .bar-viz { background: rgba(56, 189, 98 , .55); } /* green */
.cost-ok .bar-viz { background: rgba(255, 213, 90 , .55); } /* amber */
.cost-high .bar-viz { background: rgba(255, 99 ,132 , .55); } /* red */
/* 2. Ruler + right-edge -- subtle light lines instead of grey */
.bar-cell::before {
background: repeating-linear-gradient(
90deg,
rgba(255,255,255,.12) 0 1px,
transparent 1px 25%
);
}
.bar-cell::after { background: rgba(255,255,255,.12); }
/* 3. Value pill dark background so it doesnt glow */
.bar-cell span.value {
background: rgba(0,0,0,.65);
color: #fff;
}
/* 4. Header text & sort glyphs lighten slightly */
thead th { color:#e2e2e2; }
thead th::after { color:#e2e2e2; }
}
/* 5. Header row background */
:is(.dark) #letta-leaderboard thead {
background:#1a1a1a !important; /* pick any dark tone */
}

View File

@@ -1,153 +0,0 @@
/* ──────────────────────────────────────────────────────────
assets/leaderboard.js
Load via docs.yml → js: - path: assets/leaderboard.js
(strategy: lazyOnload is fine)
────────────────────────────────────────────────────────── */
import yaml from 'https://cdn.jsdelivr.net/npm/js-yaml@4.1.0/+esm';
console.log('🏁 leaderboard.js loaded on', location.pathname);
const COST_CAP = 20;
/* ---------- helpers ---------- */
const pct = (v) => Number(v).toPrecision(3) + '%';
const cost = (v) => '$' + Number(v).toFixed(2);
const ready = (cb) =>
document.readyState === 'loading'
? document.addEventListener('DOMContentLoaded', cb)
: cb();
/* ---------- main ---------- */
ready(async () => {
// const host = document.getElementById('letta-leaderboard');
// if (!host) {
// console.warn('LB-script: #letta-leaderboard not found - bailing out.');
// return;
// }
/* ---- wait for the leaderboard container to appear (SPA nav safe) ---- */
const host = await new Promise((resolve, reject) => {
const el = document.getElementById('letta-leaderboard');
if (el) return resolve(el); // SSR / hard refresh path
const obs = new MutationObserver(() => {
const found = document.getElementById('letta-leaderboard');
if (found) {
obs.disconnect();
resolve(found); // CSR navigation path
}
});
obs.observe(document.body, { childList: true, subtree: true });
setTimeout(() => {
obs.disconnect();
reject(new Error('#letta-leaderboard never appeared'));
}, 5000); // safety timeout
}).catch((err) => {
console.warn('LB-script:', err.message);
return null;
});
if (!host) return; // still no luck → give up
/* ----- figure out URL of data.yaml ----- */
// const path = location.pathname.endsWith('/')
// ? location.pathname
// : location.pathname.replace(/[^/]*$/, ''); // strip file/slug
// const dataUrl = `${location.origin}${path}data.yaml`;
// const dataUrl = `${location.origin}/leaderboard/data.yaml`; // one-liner, always right
// const dataUrl = `${location.origin}/assets/leaderboard.yaml`;
// const dataUrl = `./assets/leaderboard.yaml`; // one-liner, always right
// const dataUrl = `${location.origin}/data.yaml`; // one-liner, always right
// const dataUrl = 'https://raw.githubusercontent.com/letta-ai/letta-leaderboard/main/data/letta_memory_leaderboard.yaml';
const dataUrl =
'https://cdn.jsdelivr.net/gh/letta-ai/letta-leaderboard@latest/data/letta_memory_leaderboard.yaml';
console.log('LB-script: fetching', dataUrl);
/* ----- fetch & parse YAML ----- */
let rows;
try {
const resp = await fetch(dataUrl);
console.log(`LB-script: status ${resp.status}`);
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
rows = yaml.load(await resp.text());
} catch (err) {
console.error('LB-script: failed to load YAML →', err);
return;
}
/* ----- wire up table ----- */
const dir = Object.create(null);
const tbody = document.getElementById('lb-body');
const searchI = document.getElementById('lb-search');
const headers = document.querySelectorAll('#lb-table thead th[data-key]');
searchI.value = ''; // clear any persisted filter
const render = () => {
const q = searchI.value.toLowerCase();
tbody.innerHTML = rows
.map((r) => {
const over = r.total_cost > COST_CAP;
const barW = over ? '100%' : (r.total_cost / COST_CAP) * 100 + '%';
const costCls = over ? 'cost-high' : 'cost-ok';
const warnIcon = over
? `<span class="warn" title="Cost exceeds $${COST_CAP} cap - bar is clipped to full width">⚠</span>`
: '';
return `
<tr class="${q && !r.model.toLowerCase().includes(q) ? 'hidden' : ''}">
<td style="padding:8px">${r.model}</td>
<td class="bar-cell avg metric">
<div class="bar-viz" style="width:${r.average}%"></div>
<span class="value">${pct(r.average)}</span>
</td>
<td class="bar-cell ${costCls} metric">
<div class="bar-viz" style="width:${barW}"></div>
<span class="value">${cost(r.total_cost)}</span>
${warnIcon}
</td>
</tr>`;
})
.join('');
};
const setIndicator = (activeKey) => {
headers.forEach((h) => {
h.classList.remove('asc', 'desc');
if (h.dataset.key === activeKey) h.classList.add(dir[activeKey]);
});
};
/* initial sort ↓ */
dir.average = 'desc';
rows.sort((a, b) => b.average - a.average);
setIndicator('average');
render();
/* search */
searchI.addEventListener('input', render);
/* column sorting */
headers.forEach((th) => {
const key = th.dataset.key;
th.addEventListener('click', () => {
const asc = dir[key] === 'desc';
dir[key] = asc ? 'asc' : 'desc';
rows.sort((a, b) => {
const va = a[key],
vb = b[key];
const cmp =
typeof va === 'number'
? va - vb
: String(va).localeCompare(String(vb));
return asc ? cmp : -cmp;
});
setIndicator(key);
render();
});
});
});

View File

@@ -1,16 +0,0 @@
<svg width="75" height="22" viewBox="0 0 75 22" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_80_2)">
<path d="M13.2017 8.80036H8.80133V13.2002H13.2017V8.80036Z" fill="white"/>
<path d="M17.6019 2.99742V0H4.40033V2.99742C4.40033 3.77228 3.77267 4.39988 2.99773 4.39988H0V17.6001H2.99773C3.77267 17.6001 4.40033 18.2277 4.40033 19.0026V22H17.6019V19.0026C17.6019 18.2277 18.2296 17.6001 19.0045 17.6001H22.0023V4.39988H19.0045C18.2296 4.39988 17.6019 3.77228 17.6019 2.99742ZM17.6019 16.1971C17.6019 16.9719 16.9743 17.5995 16.1993 17.5995H5.80355C5.0286 17.5995 4.40094 16.9719 4.40094 16.1971V5.80234C4.40094 5.02747 5.0286 4.39988 5.80355 4.39988H16.1993C16.9743 4.39988 17.6019 5.02747 17.6019 5.80234V16.1971Z" fill="white"/>
<path d="M34.9429 4.39986H33.0025V17.5995H41.6265V15.7326H34.9429V4.39986Z" fill="white"/>
<path d="M47.221 8.28637H46.531C44.4567 8.28637 42.3641 9.55806 42.3641 12.3984V13.7789C42.3641 16.3534 43.8541 17.8909 46.3495 17.8909H47.4031C49.5085 17.8909 51.0065 16.6516 51.3139 14.6558L51.3408 14.4798H49.3423L49.3093 14.5886C49.0135 15.5676 48.2404 16.024 46.8763 16.024C45.1058 16.024 44.2703 15.2376 44.2501 13.5503H51.3878V12.3984C51.3878 9.55806 49.2952 8.28637 47.221 8.28637ZM44.3076 11.9004C44.5056 10.6623 45.2628 10.1533 46.8757 10.1533C48.4885 10.1533 49.2451 10.6623 49.4431 11.9004H44.3076Z" fill="white"/>
<path d="M55.2595 4.39986H53.3197V8.28642H52.0302V10.1533H53.3197V13.851C53.3197 17.1124 55.3042 17.5995 56.4874 17.5995H57.7115V15.7326H57.0142C55.768 15.7326 55.2595 15.1032 55.2595 13.5608V10.1539H57.7115V8.28703H55.2595V4.39986Z" fill="white"/>
<path d="M61.815 4.39986H59.8751V8.28642H58.5856V10.1533H59.8751V13.851C59.8751 17.1124 61.8596 17.5995 63.0428 17.5995H64.2669V15.7326H63.5696C62.3234 15.7326 61.815 15.1032 61.815 13.5608V10.1539H64.2669V8.28703H61.815V4.39986Z" fill="white"/>
<path d="M74.2617 15.7326C73.8772 15.7326 73.7061 15.5724 73.7061 15.2131V12.0348C73.7061 8.77341 71.7217 8.28637 70.5385 8.28637H68.7588C67.2199 8.28637 65.5728 9.41323 65.5728 11.0907V11.2435H67.5126V11.0907C67.5126 10.5737 68.1452 10.1539 68.922 10.1539H70.0117C71.4039 10.1539 71.7046 10.655 71.7602 11.7739H68.958C66.7915 11.7739 65.3363 12.9301 65.3363 14.6509V14.8507C65.3363 15.7594 65.6889 17.8732 68.958 17.8732C69.7929 17.8732 71.2517 17.7272 72.0364 16.7959C72.5119 17.6007 73.5136 17.6007 74.2617 17.6007H74.4144V15.7338H74.2617V15.7326ZM71.7657 14.7407C71.7657 15.7778 70.1192 16.0045 69.4842 16.0045C67.6367 16.0045 67.2755 15.5541 67.2755 14.7768C67.2755 13.9139 68.0395 13.4581 69.4842 13.4581H71.7657V14.7407Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_80_2">
<rect width="75" height="22" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -1,9 +0,0 @@
<svg aria-hidden="true" fill="none" height="100%" preserveaspectratio="xMidYMid meet" role="img" viewBox="0 0 75 22" width="100%" xmlns="http://www.w3.org/2000/svg">
<path d="M13.2017 8.80036H8.80133V13.2002H13.2017V8.80036Z" fill="currentColor"></path>
<path d="M17.6019 2.99742V0H4.40033V2.99742C4.40033 3.77228 3.77267 4.39988 2.99773 4.39988H0V17.6001H2.99773C3.77267 17.6001 4.40033 18.2277 4.40033 19.0026V22H17.6019V19.0026C17.6019 18.2277 18.2296 17.6001 19.0045 17.6001H22.0023V4.39988H19.0045C18.2296 4.39988 17.6019 3.77228 17.6019 2.99742ZM17.6019 16.1971C17.6019 16.9719 16.9743 17.5995 16.1993 17.5995H5.80355C5.0286 17.5995 4.40094 16.9719 4.40094 16.1971V5.80234C4.40094 5.02747 5.0286 4.39988 5.80355 4.39988H16.1993C16.9743 4.39988 17.6019 5.02747 17.6019 5.80234V16.1971Z" fill="currentColor"></path>
<path d="M34.9429 4.39986H33.0025V17.5995H41.6265V15.7326H34.9429V4.39986Z" fill="currentColor"></path>
<path d="M47.221 8.28637H46.531C44.4567 8.28637 42.3641 9.55806 42.3641 12.3984V13.7789C42.3641 16.3534 43.8541 17.8909 46.3495 17.8909H47.4031C49.5085 17.8909 51.0065 16.6516 51.3139 14.6558L51.3408 14.4798H49.3423L49.3093 14.5886C49.0135 15.5676 48.2404 16.024 46.8763 16.024C45.1058 16.024 44.2703 15.2376 44.2501 13.5503H51.3878V12.3984C51.3878 9.55806 49.2952 8.28637 47.221 8.28637ZM44.3076 11.9004C44.5056 10.6623 45.2628 10.1533 46.8757 10.1533C48.4885 10.1533 49.2451 10.6623 49.4431 11.9004H44.3076Z" fill="currentColor"></path>
<path d="M55.2595 4.39986H53.3197V8.28642H52.0302V10.1533H53.3197V13.851C53.3197 17.1124 55.3042 17.5995 56.4874 17.5995H57.7115V15.7326H57.0142C55.768 15.7326 55.2595 15.1032 55.2595 13.5608V10.1539H57.7115V8.28703H55.2595V4.39986Z" fill="currentColor"></path>
<path d="M61.815 4.39986H59.8751V8.28642H58.5856V10.1533H59.8751V13.851C59.8751 17.1124 61.8596 17.5995 63.0428 17.5995H64.2669V15.7326H63.5696C62.3234 15.7326 61.815 15.1032 61.815 13.5608V10.1539H64.2669V8.28703H61.815V4.39986Z" fill="currentColor"></path>
<path d="M74.2617 15.7326C73.8772 15.7326 73.7061 15.5724 73.7061 15.2131V12.0348C73.7061 8.77341 71.7217 8.28637 70.5385 8.28637H68.7588C67.2199 8.28637 65.5728 9.41323 65.5728 11.0907V11.2435H67.5126V11.0907C67.5126 10.5737 68.1452 10.1539 68.922 10.1539H70.0117C71.4039 10.1539 71.7046 10.655 71.7602 11.7739H68.958C66.7915 11.7739 65.3363 12.9301 65.3363 14.6509V14.8507C65.3363 15.7594 65.6889 17.8732 68.958 17.8732C69.7929 17.8732 71.2517 17.7272 72.0364 16.7959C72.5119 17.6007 73.5136 17.6007 74.2617 17.6007H74.4144V15.7338H74.2617V15.7326ZM71.7657 14.7407C71.7657 15.7778 70.1192 16.0045 69.4842 16.0045C67.6367 16.0045 67.2755 15.5541 67.2755 14.7768C67.2755 13.9139 68.0395 13.4581 69.4842 13.4581H71.7657V14.7407Z" fill="currentColor"></path>
</svg>

Before

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -1,307 +0,0 @@
/* .fern-header-container * {
font-weight: 600;
} */
/* Remove rounded corners across the docs site */
:root {
--radius: 0px;
}
/* Override styles related to soft borders */
.fern-button {
border-radius: 0 !important;
}
.fern-collapsible-card {
border-radius: 0 !important;
}
.fern-api-property-meta code {
border-radius: 0 !important;
}
.fern-docs-badge {
border-radius: 0 !important;
}
.bg-accent-highlight {
border-radius: 0 !important;
}
.fern-scroll-area {
border-radius: 0 !important;
}
.fern-dropdown-item {
border-radius: 0 !important;
}
.fern-anchor-icon {
border-radius: 0 !important;
}
.fern-search-bar {
border-radius: 0 !important;
}
.keyboard-shortcut-hint {
border-radius: 0 !important;
}
.fern-search-button {
border-radius: 0 !important;
}
code:not(.code-block) {
border-radius: 0 !important;
}
.fern-accordion {
border-radius: 0 !important;
}
.fern-table-root,
.fern-table,
.fern-table thead,
.fern-table tbody,
.fern-table tr,
.fern-table th,
.fern-table td {
border-radius: 0 !important;
}
/* [data-radix-scroll-area-viewport] {
border-radius: 0 !important;
}
[data-radix-popper-content-wrapper] {
border-radius: 0 !important;
} */
[data-radix-popper-content-wrapper],
[data-radix-popper-content-wrapper] > * {
border-radius: 0 !important;
}
.rounded-xl,
.rounded-lg,
.rounded-md,
.rounded-sm,
.fern-sidebar-link {
border-radius: 0px !important;
}
:is(.light) .code-block-line-content span[style*="color: rgb(194, 195, 197);"] {
color: #8e8e8e !important;
}
/* Different opacity for active items in the sidebar */
/* Light mode */
:is(.light) .fern-sidebar-link-container[data-state="active"] .fern-sidebar-link {
background-color: rgba(7, 7, 172, 0.04);
}
:is(.light) body#fern-docs .fern-sidebar-link[data-state="active"] {
background-color: rgba(7, 7, 172, 0.04);
}
:is(.light) .fern-sidebar-link-container[data-state="active"] .fern-sidebar-link-text {
color: #0707ac;
}
:is(.light) body#fern-docs .fern-sidebar-link[data-state="active"] span {
color: #0707ac;
}
/* Dark mode */
:is(.dark) .fern-sidebar-link-container[data-state="active"] .fern-sidebar-link {
background-color: rgba(255, 187, 173, 0.08); /* #FFBBAD */
}
:is(.dark) body#fern-docs .fern-sidebar-link[data-state="active"] {
background-color: rgba(255, 187, 173, 0.08); /* #FFBBAD */
}
:is(.dark) .fern-sidebar-link-container[data-state="active"] .fern-sidebar-link-text {
color: #FF5533;
}
:is(.dark) body#fern-docs .fern-sidebar-link[data-state="active"] span {
color: #FF5533;
}
/* Make uppercase sidebar heading */
.fern-sidebar-heading .fern-sidebar-heading-content,
.fern-breadcrumb-item {
/* font-family: var(--typography-code-font-family); */
font-weight: 600;
/* letter-spacing: 0.05em; */
text-transform: uppercase;
/* color: var(--gray-12); */
font-size: 0.8rem;
/* text-decoration: none; */
}
/* .fern-theme-default.fern-container .fern-header-tabs .fern-header-tab-button .fern-header-container * {
font-size: 1rem;
} */
.t-muted.whitespace-nowrap.text-xs,
.inline-flex.items-baseline.gap-1 {
display: none !important;
}
/* @supports (overscroll-behavior: none) {
html, body {
overscroll-behavior: none;
}
} */
/* dark/light mode toggle for images */
:is(.dark) img.dark {
display: block;
}
:is(.dark) img.light {
display: none;
}
:is(.light) img.light {
display: block;
}
:is(.light) img.dark {
display: none;
}
/* Landing page styles */
.landing-page {
margin-inline: auto;
min-width: calc(var(--spacing) * 0);
padding-inline: var(--page-padding);
max-width: calc(var(--spacing-page-width) + var(--spacing-page-padding)*2);
.letta-header {
padding-top: 7rem !important;
padding-bottom: 7rem !important;
position: relative !important;
}
.letta-header-bg {
background-color: #f6f6f6 !important;
width: 100vw;
position: absolute;
top: 0%;
bottom: 0%;
left: 50%;
transform: translate(-50%);
z-index: -1;
}
.hero-image-container {
width: var(--page-width);
position: relative;
}
.hero-image {
position: absolute !important;
right: 0 !important;
top: 50% !important;
transform: translateY(-50%) !important;
height: 100% !important;
max-height: 400px !important;
z-index: 0 !important;
opacity: 0.5 !important;
width: fit-content;
pointer-events: none !important;
}
.hero-image.dark {
display: none !important;
}
.letta-header h1 {
font-size: 4.0rem !important;
line-height: 1.1 !important;
font-weight: 300 !important;
font-family: Roobert, sans-serif !important; /* Use regular Roobert instead of Medium */
}
.letta-header p {
font-size: 1.25rem !important;
line-height: 1.3 !important;
font-weight: 400 !important;
}
.letta-header a {
border-bottom: 1px solid rgba(255,255,255,0.5) !important;
font-size: 0.5rem !important;
font-weight: normal !important;
}
.letta-header a:hover {
border-bottom-color: white !important;
}
.fern-main .landingbody {
max-width: 1195px !important;
margin-left: auto !important;
margin-right: auto !important;
}
#fern-sidebar {
display: none !important;
}
@media (max-width: 1504px) {
.hero-image-container {
width: 100vw !important;
}
}
/* Tablet viewport breakpoint */
@media (max-width: 1024px) {
.letta-header {
padding-top: 4rem !important;
padding-bottom: 4rem !important;
}
.letta-header h1 {
font-size: 3rem !important;
}
.letta-header p {
font-size: 1.1rem !important;
}
.hero-image-container {
display: none !important;
}
}
/* Mobile viewport breakpoint */
@media (max-width: 640px) {
.letta-header {
padding-top: 3rem !important;
padding-bottom: 3rem !important;
}
.letta-header h1 {
font-size: 2.5rem !important;
}
.letta-header p {
font-size: 1rem !important;
}
.letta-header .max-w-4xl {
padding-left: 1rem !important;
padding-right: 1rem !important;
}
.landingbody {
padding-left: 1rem !important;
padding-right: 1rem !important;
}
}
}
:is(.dark) .landing-page .letta-header-bg {
background-color: #151515 !important;
}
:is(.dark) .landing-page.hero-image.light {
display: none !important;
}
:is(.dark) .landing-page .hero-image.dark {
display: block !important;
}

View File

@@ -1,72 +0,0 @@
## Consistency Across Messages APIs
<Note> These are the final changes from our API overhaul, which means they are not backwards compatible to prior versions of our APIs and SDKs. Upgrading may require changes to your code. </Note>
### Flattened `UserMessage` content
The content field on `UserMessage` objects returned by our Messages endpoints have been simplified to flat strings containing raw message text, rather than JSON strings with message text nested inside.
#### Before:
```python
{
"id": "message-dea2ceab-0863-44ea-86dc-70cf02c05946",
"date": "2025-01-28T01:18:18+00:00",
"message_type": "user_message",
"content": "{\n \"type\": \"user_message\",\n \"message\": \"Hello, how are you?\",\n \"time\": \"2025-01-28 01:18:18 AM UTC+0000\"\n}"
}
```
#### After:
```python
{
"id": "message-dea2ceab-0863-44ea-86dc-70cf02c05946",
"date": "2025-01-28T01:18:18+00:00",
"message_type": "user_message",
"content": "Hello, how are you?"
}
```
### Top-level `use_assistant_message` parameter defaults to True
All message related APIs now include a top-level `use_assistant_message` parameter, which defaults to `True` if not specified. This parameter controls whether the endpoint should parse specific tool call arguments (default `send_message`) as AssistantMessage objects rather than ToolCallMessage objects.
#### Before:
```python
response = client.agents.messages.create(
agent_id=agent.id,
messages=[
MessageCreate(
role="user",
content="call the big_return function",
),
],
config=LettaRequestConfig(use_assistant_message=False),
)
```
#### After:
```python
response = client.agents.messages.create(
agent_id=agent.id,
messages=[
MessageCreate(
role="user",
content="call the big_return function",
),
],
use_assistant_message=False,
)
```
Previously, the `List Messages` endpoint defaulted to False internally, so this change may cause unexpected behavior in your code. To fix this, you can set the `use_assistant_message` parameter to `False` in your request.
```python
messages = client.agents.messages.list(
limit=10,
use_assistant_message=False,
)
```
### Consistent message return type
All message related APIs return `LettaMessage` objects now, which are simplified versions of `Message` objects stored in the database backend. Previously, our `List Messages` endpoint returned `Message` objects by default, which is no longer an option.

View File

@@ -1,22 +0,0 @@
### Tool rules improvements
ToolRule objects no longer should specify a `type` at instantiation, as this field is now immutable.
#### Before:
```python
rule = InitToolRule(
tool_name="secret_message",
type="run_first"
)
```
#### After:
```python
rule = InitToolRule(tool_name="secret_message")
```
Letta also now supports smarter retry behavior for tool rules in the case of unrecoverable failures.
### New API routes to query agent steps
The [`List Steps`](https://docs.letta.com/api-reference/steps/list-steps) and [`Retrieve Step`](https://docs.letta.com/api-reference/steps/retrieve-step) routes have been added to enable querying for additional metadata around agent execution.

View File

@@ -1,42 +0,0 @@
### Query tools by name
The `List Tools` API now supports querying by tool name.
```python
send_message_tool_id = client.agents.tools.list(tool_name="secret_message")[0].id
```
### Authorization header now supports password
For self-deployed instances of Letta that are password-protected, the `Authorization` header now supports parsing passwords in addition to API keys. `X-BARE-PASSWORD` will still be supported as legacy, but will be deprecated in a future release.
#### Before:
```sh
curl --request POST \
--url https://MYSERVER.up.railway.app/v1/agents/ \
--header 'X-BARE-PASSWORD: password banana' \
--header 'Content-Type: application/json' \
--data '{
...
}'
```
#### After:
```sh
curl --request POST \
--url https://MYSERVER.up.railway.app/v1/agents/ \
--header 'AUTHORIZATION: Bearer banana' \
--header 'Content-Type: application/json' \
--data '{
...
}'
```
Password can now be passed via the `token` field when initializing the Letta client:
```python
client = LettaClient(
base_url="https://MYSERVER.up.railway.app",
token="banana",
)
```

View File

@@ -1,11 +0,0 @@
## Agents API Improvements
<Note> These APIs are only available for Letta Cloud. </Note>
### Agent Search
The [`/v1/agents/search`](https://docs.letta.com/api-reference/agents/search) API has been updated to support pagination via `after` query parameter
### Agent Creation from Template
The [`/v1/templates/`](https://docs.letta.com/api-reference/templates/createagentsfromtemplate) creation API has been updated to support adding `tags` at creation time

View File

@@ -1,3 +0,0 @@
## Temperature and Max Tokens Supported via LLM Config
These values are now configurable when creating and modifying agents via [`llm_config`](https://docs.letta.com/api-reference/agents/modify#request.body.llm_config) parameter for subsequent LLM requests.

View File

@@ -1,9 +0,0 @@
## New Features
### Google Vertex support
Google Vertex is now a supported endpoint type for Letta agents.
### Option to disable message persistence for a given agent
Letta agents now have an optional `message_buffer_autoclear` flag. If set to True (default False), the message history will not be persisted in-context between requests (though the agent will still have access to core, archival, and recall memory).

View File

@@ -1,113 +0,0 @@
## Project Slug Moved to Request Header
<Note> Projects are only available for Letta Cloud. </Note>
Project slug can now be specified via request header `X-Project` for agent creation. The existing `project` parameter will soon be deprecated.
#### Before
<CodeBlocks>
```curl title="curl"
curl -X POST https://app.letta.com/v1/agents \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-d '{
"project":"YOUR_PROJECT_SLUG"
"model":"gpt-4o-mini",
"embedding":"openai/text-embedding-3-small"
"memory_blocks": [
{
"label": "human",
"value": "name: Caren"
}
],
}'
```
```python title="python"
from letta_client import CreateBlock, Letta
client = Letta(
token="YOUR_API_KEY",
)
agent = client.agents.create(
project="YOUR_PROJECT_SLUG",
model="gpt-4o-mini",
embedding="openai/text-embedding-3-small"
memory_blocks=[
CreateBlock(
"label": "human",
"value": "name: Caren"
),
],
)
```
```typescript title="node.js"
import { LettaClient } from '@letta-ai/letta-client';
const client = new LettaClient({
token: "YOUR_API_KEY",
});
const agent = await client.agents.create({
project: "YOUR_PROJECT_SLUG",
model: "gpt-4o-mini",
embedding: "openai/text-embedding-3-small"
memory_blocks: [
{
label: "human",
value: "name: Caren"
},
],
});
```
</CodeBlocks>
#### After
<CodeBlocks>
```curl title="curl"
curl -X POST https://app.letta.com/v1/agents \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'X-Project: YOUR_PROJECT_SLUG' \
-d '{
"model":"gpt-4o-mini",
"embedding":"openai/text-embedding-3-small"
"memory_blocks": [
{
"label": "human",
"value": "name: Caren"
}
],
}'
```
```python title="python"
from letta_client import CreateBlock, Letta
client = Letta(
token="YOUR_API_KEY",
)
agent = client.agents.create(
x_project="YOUR_PROJECT_SLUG",
model="gpt-4o-mini",
embedding="openai/text-embedding-3-small"
memory_blocks=[
CreateBlock(
"label": "human",
"value": "name: Caren"
),
],
)
```
```typescript title="node.js"
import { LettaClient } from '@letta-ai/letta-client';
const client = new LettaClient({
token: "YOUR_API_KEY",
});
const agent = await client.agents.create({
x_project: "YOUR_PROJECT_SLUG",
model: "gpt-4o-mini",
embedding: "openai/text-embedding-3-small"
memory_blocks: [
{
label: "human",
value: "name: Caren"
},
],
});
```
</CodeBlocks>

View File

@@ -1,7 +0,0 @@
## New Identities Feature
We've added a new Identities feature that helps you manage users in your multi-user Letta application. Each Identity can represent a user or organization in your system and store their metadata.
You can associate an Identity with one or more agents, making it easy to track which agents belong to which users. Agents can also be associated with multiple identities, enabling shared access across different users. This release includes full CRUD (Create, Read, Update, Delete) operations for managing Identities through our API.
For more information on usage, visit our [Identities documentation](/api-reference/identities) and [usage guide](/guides/agents/multi-user).

View File

@@ -1,85 +0,0 @@
## Core Memory and Archival Memory SDK APIs Renamed to Blocks and Passages
<Note> This is a breaking SDK change and is not backwards compatible. </Note>
Given the confusion around our advanced functionality for managing memory, we've renamed the Core Memory SDK API to `blocks` and the Archival Memory SDK API to `passages` so that our API naming reflects the unit of memory stored. This change only affects our SDK, and does not affect Letta's Rest API.
#### Before
<CodeBlocks>
```python title="python"
from letta_client import CreateBlock, Letta
client = Letta(
token="YOUR_API_KEY",
)
agent = client.agents.create(
model="gpt-4o-mini",
embedding="openai/text-embedding-3-small"
memory_blocks=[
CreateBlock(
"label": "human",
"value": "name: Caren"
),
],
)
blocks = client.agents.core_memory.list_blocks(agent_id=agent.id)
client.agents.core_memory.detach_block(agent_id=agent.id, block_id=blocks[0].id)
```
```typescript title="node.js"
import { LettaClient } from '@letta-ai/letta-client';
const client = new LettaClient({
token: "YOUR_API_KEY",
});
const agent = await client.agents.create({
model: "gpt-4o-mini",
embedding: "openai/text-embedding-3-small"
memory_blocks: [
{
label: "human",
value: "name: Caren"
},
],
});
const blocks = await client.agents.coreMemory.listBlocks(agent.id);
await client.agents.coreMemory.detachBlock(agent.id, blocks[0].id);
```
</CodeBlocks>
#### After
<CodeBlocks>
```python title="python"
from letta_client import CreateBlock, Letta
client = Letta(
token="YOUR_API_KEY",
)
agent = client.agents.create(
model="gpt-4o-mini",
embedding="openai/text-embedding-3-small"
memory_blocks=[
CreateBlock(
"label": "human",
"value": "name: Caren"
),
],
)
blocks = client.agents.blocks.list(agent_id=agent.id)
client.agents.blocks.detach(agent_id=agent.id, block_id=blocks[0].id)
```
```typescript title="node.js"
import { LettaClient } from '@letta-ai/letta-client';
const client = new LettaClient({
token: "YOUR_API_KEY",
});
const agent = await client.agents.create({
model: "gpt-4o-mini",
embedding: "openai/text-embedding-3-small"
memory_blocks: [
{
label: "human",
value: "name: Caren"
},
],
});
const blocks = client.agents.blocks.list(agent.id)
await client.agents.blocks.detach(agent.id, blocks[0].id)
```
</CodeBlocks>

View File

@@ -1,3 +0,0 @@
## xAI / Grok Now Supported
We've added xAI support in the latest SDK version. To enable xAI models, set your `XAI_API_KEY` as an environment variable: `export XAI_API_KEY="..."`.

View File

@@ -1,28 +0,0 @@
## Added Modify Passage API
We've introduced a new API endpoint that allows you to modify existing passages within agent memory.
<CodeBlocks>
```python title="python"
from letta_client import Letta
client = Letta(
token="YOUR_API_KEY",
)
client.agents.modify_passage(
agent_id="AGENT_ID",
memory_id="MEMORY_ID",
text="Updated passage content"
)
```
```typescript title="node.js"
import { LettaClient } from '@letta-ai/letta-client';
const client = new LettaClient({
token: "YOUR_API_KEY",
});
await client.agents.modifyPassage({
agent_id: "AGENT_ID",
memory_id: "MEMORY_ID",
text: "Updated passage content"
});
```
</CodeBlocks>

View File

@@ -1,77 +0,0 @@
## Enhanced Tool Definitions with Complex Schemas
### Complex Schema Support for Tool Arguments
You can now use complex Pydantic schemas to define arguments for tools, enabling better type safety and validation for your tool inputs.
```python
from pydantic import BaseModel
from typing import List, Optional
class ItemData(BaseModel):
name: str
sku: str
price: float
description: Optional[str] = None
class InventoryEntry(BaseModel):
item: ItemData
location: str
current_stock: int
minimum_stock: int = 5
class InventoryEntryData(BaseModel):
data: InventoryEntry
quantity_change: int
```
## Tool Creation from Function with Complex Schema
Use the args_schema parameter to specify a Pydantic model for tool arguments when creating tools from functions.
```python
from letta_client import Letta
client = Letta(
token="YOUR_API_KEY",
)
def manage_inventory_mock(data: InventoryEntry, quantity_change: int) -> bool:
"""
Implementation of the manage_inventory tool
"""
print(f"Updated inventory for {data.item.name} with a quantity change of {quantity_change}")
return True
tool_from_func = client.tools.upsert_from_function(
func=manage_inventory_mock,
args_schema=InventoryEntryData,
)
```
### BaseTool Class Extension
For more complex tool implementations, you can also extend the `BaseTool` class to create custom tools with full control over the implementation.
```python
from letta_client import BaseTool
from typing import Type, List
from pydantic import BaseModel
class ManageInventoryTool(BaseTool):
name: str = "manage_inventory"
args_schema: Type[BaseModel] = InventoryEntryData
description: str = "Update inventory catalogue with a new data entry"
tags: List[str] = ["inventory", "shop"]
def run(self, data: InventoryEntry, quantity_change: int) -> bool:
"""
Implementation of the manage_inventory tool
"""
# implementation
print(f"Updated inventory for {data.item.name} with a quantity change of {quantity_change}")
return True
custom_tool = client.tools.add(
tool=ManageInventoryTool(),
)
```

View File

@@ -1,29 +0,0 @@
## Added List Run Steps API
We've introduced a new API endpoint that allows you to list all steps associated with a specific run. This feature makes it easier to track and analyze the sequence of steps performed during a run.
<CodeBlocks>
```python title="python"
from letta_client import Letta
client = Letta(
token="YOUR_API_KEY",
)
steps = client.runs.list_run_steps(
run_id="RUN_ID",
)
for step in steps:
print(f"Step ID: {step.id}, Tokens: {step.total_tokens}")
```
```typescript title="node.js"
import { LettaClient } from '@letta-ai/letta-client';
const client = new LettaClient({
token: "YOUR_API_KEY",
});
const steps = await client.runs.listRunSteps({
run_id: "RUN_ID",
});
steps.forEach(step => {
console.log(`Step ID: ${step.id}, Tokens: ${step.total_tokens}`);
});
```
</CodeBlocks>

View File

@@ -1,60 +0,0 @@
## Agent Serialization: Download and Upload APIs
We've added new APIs that allow you to download an agent's serialized JSON representation and upload it to recreate the agent in the system. These features enable easy agent backup, transfer between environments, and version control of agent configurations.
### Import Agent Serialized
Import a serialized agent file and recreate the agent in the system.
<CodeBlocks>
```python title="python"
from letta_client import Letta
client = Letta(
token="YOUR_API_KEY",
)
agent = client.agents.import_agent_serialized(
file=open("/path/to/agent/file.af", "rb"),
)
```
```typescript title="node.js"
import { LettaClient } from '@letta-ai/letta-client';
import * as fs from 'fs';
const client = new LettaClient({
token: "YOUR_API_KEY",
});
const agent = await client.agents.importAgentSerialized({
file: fs.createReadStream("/path/to/your/file"),
});
```
</CodeBlocks>
### Export Agent Serialized
Export the serialized JSON representation of an agent, formatted with indentation.
<CodeBlocks>
```python title="python"
from letta_client import Letta
client = Letta(
token="YOUR_API_KEY",
)
agent_json = client.agents.export_agent_serialized(
agent_id="AGENT_ID",
)
```
```typescript title="node.js"
import { LettaClient } from '@letta-ai/letta-client';
const client = new LettaClient({
token: "YOUR_API_KEY",
});
const agentJson = await client.agents.exportAgentSerialized({
agent_id: "AGENT_ID",
});
```
</CodeBlocks>
## Use Cases
- Environment Migration: Transfer agents between local, desktop, and cloud environments
- Version Control: Save agent configurations before making significant changes
- Templating: Create template agents that can be quickly deployed for different use cases
- Sharing: Share agent configurations with team members or across organizations

View File

@@ -1,32 +0,0 @@
## Message Modification API
We've added a new API endpoint that allows you to modify existing messages in an agent's conversation history. This feature is particularly useful for editing message history to refine agent behavior without starting a new conversation.
<CodeBlocks>
```python title="python"
from letta_client import Letta, UpdateSystemMessage
client = Letta(
token="YOUR_API_KEY",
)
client.agents.messages.modify(
agent_id="AGENT_ID",
message_id="MESSAGE_ID",
request=UpdateSystemMessage(
content="The agent should prioritize brevity in responses.",
),
)
```
```typescript title="node.js"
import { LettaClient } from '@letta-ai/letta-client';
const client = new LettaClient({
token: "YOUR_API_KEY",
});
await client.agents.messages.modify({
agent_id: "AGENT_ID",
message_id: "MESSAGE_ID",
request: {
content: "The agent should prioritize brevity in responses."
}
});
```
</CodeBlocks>

View File

@@ -1,51 +0,0 @@
## Identity Support for Memory Blocks
Memory blocks can now be associated with specific identities, allowing for better organization and retrieval of contextual information about various entities in your agent's knowledge base.
### Adding Blocks to an Identity
<CodeBlocks>
```python title="python"
from letta_client import Letta, CreateBlock
client = Letta(
token="YOUR_API_KEY",
)
client.agents.identities.modify(
identity_id="IDENTITY_ID",
block_ids=["BLOCK_ID"],
)
```
```typescript title="node.js"
import { LettaClient } from '@letta-ai/letta-client';
const client = new LettaClient({
token: "YOUR_API_KEY",
});
await client.agents.identities.modify({
identity_id: "IDENTITY_ID",
block_ids: ["BLOCK_ID"],
});
```
</CodeBlocks>
### Querying Blocks by Identity
<CodeBlocks>
```python title="python"
from letta_client import Letta
client = Letta(
token="YOUR_API_KEY",
)
client.agents.blocks.list(
identity_id="IDENTITY_ID",
)
```
```typescript title="node.js"
import { LettaClient } from '@letta-ai/letta-client';
const client = new LettaClient({
token: "YOUR_API_KEY",
});
await client.agents.blocks.list({
identity_id: "IDENTITY_ID",
});
```
</CodeBlocks>

View File

@@ -1,3 +0,0 @@
## MCP Now Supported
We've added MCP support in the latest SDK version. For full documentation on how to enable MCP with Letta, visit [our MCP guide](/guides/mcp/setup).

View File

@@ -1,24 +0,0 @@
## New `include_relationships` Parameter for List Agents API
You can now leverage a more customized, lightweight response from the list agents API by setting the `include_relationships` parameter to which fields you'd like to fetch in the response.
<CodeBlocks>
```python title="python"
from letta_client import Letta
client = Letta(
token="YOUR_API_KEY",
)
agents = client.agents.list(
include_relationships=["identities", "blocks", "tools"],
)
```
```typescript title="node.js"
import { LettaClient } from '@letta-ai/letta-client';
const client = new LettaClient({
token: "YOUR_API_KEY",
});
const agents = await client.agents.list({
include_relationships: ["identities", "blocks", "tools"],
});
```
</CodeBlocks>

View File

@@ -1,28 +0,0 @@
## Message `content` field extended to include Multi-modal content parts
The `content` field on `UserMessage` and `AssistantMessage` objects returned by our Messages endpoints has been extended to support multi-modal content parts, in anticipation of allowing you to send and receive messages with text, images, and other media.
### Before:
```curl
{
"id": "message-dea2ceab-0863-44ea-86dc-70cf02c05946",
"date": "2025-01-28T01:18:18+00:00",
"message_type": "user_message",
"content": "Hello, how are you?"
}
```
### After:
```curl
{
"id": "message-dea2ceab-0863-44ea-86dc-70cf02c05946",
"date": "2025-01-28T01:18:18+00:00",
"message_type": "user_message",
"content": [
{
"type": "text",
"text": "Hello, how are you?"
}
]
}
```

View File

@@ -1,3 +0,0 @@
## `Embedding` model info now specified directly on Source
The `Source` object returned by our Sources endpoints now stores embedding related fields, to specify the embedding model and chunk size used to generate the source.

View File

@@ -1,39 +0,0 @@
## Max invocation count tool rule
A new tool rule has been introduced for configuring a max step count per tool rule.
<CodeBlocks>
```python title="python"
from letta_client import Letta
client = Letta(
token="YOUR_API_KEY",
)
client.agents.create(
model="openai/gpt-4o-mini",
embedding="openai/text-embedding-3-small",
tool_rules=[
MaxCountPerStepToolRule(
tool_name="manage_inventory",
max_count_limit=10
)
]
)
```
```typescript title="node.js"
import { LettaClient } from '@letta-ai/letta-client';
const client = new LettaClient({
token: "YOUR_API_KEY",
});
const agent = await client.agents.create({
model: "openai/gpt-4o-mini",
embedding: "openai/text-embedding-3-small",
tool_rules: [
{
type: "max_count_per_step",
tool_name: "manage_inventory",
max_count_limit: 10
}
]
});
```
</CodeBlocks>

View File

@@ -1,11 +0,0 @@
## Output messages added to Steps API
The `Step` object returned by our Steps endpoints now includes a `steps_messages` field, which contains a list of messages generated by the step.
## Order parameter added to List Agents and List Passages APIs
The `List Agents` and `List Passages` endpoints now support an `ascending` parameter to sort the results based on creation timestamp.
## Filter parameters added List Passages API
The `List Passages` endpoint now supports filter parameters to filter the results including `after`, `before`, and `search` for filtering by text.

View File

@@ -1,30 +0,0 @@
## New fields to support reasoning models
The `LlmConfig` object now includes a `enable_reasoner` field, enables toggling on thinking steps for reasoning models like Sonnet 3.7. This change also includes support for specifying this along with `max_reasoning_tokens` in the agent creation API.
<CodeBlocks>
```python title="python"
from letta_client import Letta
client = Letta(
token="YOUR_API_KEY",
)
agent = client.agents.create(
model="claude/sonnet-3-7",
enable_reasoner=True,
max_reasoning_tokens=10000,
max_tokens=100000
)
```
```typescript title="node.js"
import { LettaClient } from '@letta-ai/letta-client';
const client = new LettaClient({
token: "YOUR_API_KEY",
});
const agent = await client.agents.create({
model: "claude/sonnet-3-7",
enable_reasoner: true,
max_reasoning_tokens: 10000,
max_tokens: 100000
});
```
</CodeBlocks>

View File

@@ -1,28 +0,0 @@
## Modify Agent API now supports `model` and `embedding` fields
The `Modify Agent` API now supports `model` and `embedding` fields to update the model and embedding used by the agent using the handles rather than specifying the entire configs.
<CodeBlocks>
```python title="python"
from letta_client import Letta
client = Letta(
token="YOUR_API_KEY",
)
client.agents.modify(
agent_id="AGENT_ID",
model="openai/gpt-4o-mini",
embedding="openai/text-embedding-3-small",
)
```
```typescript title="node.js"
import { LettaClient } from '@letta-ai/letta-client';
const client = new LettaClient({
token: "YOUR_API_KEY",
});
await client.agents.modify({
agent_id: "AGENT_ID",
model: "openai/gpt-4o-mini",
embedding: "openai/text-embedding-3-small",
});
```
</CodeBlocks>

View File

@@ -1,26 +0,0 @@
## New `strip_messages` field in Import Agent API
The `Import Agent` API now supports a new `strip_messages` field to remove messages from the agent's conversation history when importing a serialized agent file.
<CodeBlocks>
```python title="python"
from letta_client import Letta
client = Letta(
token="YOUR_API_KEY",
)
client.agents.import_agent_serialized(
file=open("/path/to/agent/file.af", "rb"),
strip_messages=True,
)
```
```typescript title="node.js"
import { LettaClient } from '@letta-ai/letta-client';
const client = new LettaClient({
token: "YOUR_API_KEY",
});
await client.agents.importAgentSerialized({
file: fs.createReadStream("/path/to/your/file"),
strip_messages: true,
});
```
</CodeBlocks>

View File

@@ -1,41 +0,0 @@
## Add new `otid` field to Message API
The `Message` object returned by our Messages endpoints now includes an offline threading id field, a unique identifier set at creation time, which can be used by the client to deduplicate messages.
### Before:
<CodeBlocks>
```python title="python"
from letta_client import Letta, MessageCreate
import uuid
client = Letta(
token="YOUR_API_KEY",
)
messages = client.agents.messages.create(
agent_id="AGENT_ID",
messages=[
MessageCreate(
role="user",
content="Hello, how are you?"
otid=uuid.uuid4(),
)
]
)
```
```typescript title="node.js"
import { LettaClient } from '@letta-ai/letta-client';
import { v4 as uuid } from 'uuid';
const client = new LettaClient({
token: "YOUR_API_KEY",
});
const messages = await client.agents.messages.create({
agent_id: "AGENT_ID",
messages: [
{
role: "user",
content: "Hello, how are you?",
otid: uuid.v4(),
},
],
});
```
</CodeBlocks>

View File

@@ -1,24 +0,0 @@
## Runs API can now be filtered by Agent ID
The Runs API now supports filtering by `agent_id` to retrieve all runs and all active runs associated with a specific agent.
<CodeBlocks>
```python title="python"
from letta_client import Letta
client = Letta(
token="YOUR_API_KEY",
)
runs = client.runs.list_active_runs(
agent_id="AGENT_ID",
)
```
```typescript title="node.js"
import { LettaClient } from '@letta-ai/letta-client';
const client = new LettaClient({
token: "YOUR_API_KEY",
});
const runs = await client.runs.listActiveRuns({
agent_id: "AGENT_ID",
});
```
</CodeBlocks>

View File

@@ -1,39 +0,0 @@
## New Parent Tool Rule
A new tool rule has been introduced for configuring a parent tool rule, which only allows a target tool to be called after a parent tool has been run.
<CodeBlocks>
```python title="python"
from letta_client import Letta
client = Letta(
token="YOUR_API_KEY",
)
agent = client.agents.create(
model="openai/gpt-4o-mini",
embedding="openai/text-embedding-3-small",
tool_rules=[
ParentToolRule(
tool_name="parent_tool",
children=["child_tool"]
)
]
)
```
```typescript title="node.js"
import { LettaClient } from '@letta-ai/letta-client';
const client = new LettaClient({
token: "YOUR_API_KEY",
});
const agent = await client.agents.create({
model: "openai/gpt-4o-mini",
embedding: "openai/text-embedding-3-small",
tool_rules: [
{
type: "parent",
tool_name: "parent_tool",
children: ["child_tool"]
}
]
});
```
</CodeBlocks>

View File

@@ -1,48 +0,0 @@
# New Upsert Properties API for Identities
The `Upsert Properties` API has been added to the Identities endpoint, allowing you to update or create properties for an identity.
<CodeBlocks>
```python title="python"
from letta_client import IdentityProperty, Letta
client = Letta(
token="YOUR_TOKEN",
)
client.identities.upsert_properties(
identity_id="IDENTITY_ID",
request=[
IdentityProperty(
key="name",
value="Caren",
type="string",
),
IdentityProperty(
key="email",
value="caren@example.com",
type="string",
)
],
)
```
```typescript title="node.js"
import { LettaClient } from '@letta-ai/letta-client';
const client = new LettaClient({
token: "YOUR_API_KEY",
});
await client.identities.upsertProperties({
identity_id: "IDENTITY_ID",
properties: [
{
key: "name",
value: "Caren",
type: "string",
},
{
key: "email",
value: "caren@example.com",
type: "string",
},
],
});
```
</CodeBlocks>

View File

@@ -1,42 +0,0 @@
## New `reasoning_effort` field added to LLMConfig
The `reasoning_effort` field has been added to the `LLMConfig` object to control the amount of reasoning the model should perform, to support OpenAI's o1 and o3 reasoning models.
## New `sender_id` parameter added to Message model
The `Message` object now includes a `sender_id` field, which is the ID of the sender of the message, which can be either an identity ID or an agent ID. The `sender_id` is expected to be passed in at message creation time.
<CodeBlocks>
```python title="python"
from letta_client import Letta
client = Letta(
token="YOUR_API_KEY",
)
messages = client.agents.messages.create(
agent_id="AGENT_ID",
messages=[
MessageCreate(
role="user",
content="Hello, how are you?",
sender_id="IDENTITY_ID",
)
]
)
```
```typescript title="node.js"
import { LettaClient } from '@letta-ai/letta-client';
const client = new LettaClient({
token: "YOUR_API_KEY",
});
const messages = await client.agents.messages.create({
agent_id: "AGENT_ID",
messages: [
{
role: "user",
content: "Hello, how are you?",
sender_id: "IDENTITY_ID",
},
],
});
```
</CodeBlocks>

View File

@@ -1,24 +0,0 @@
## New List Agent Groups API added
The `List Agent Groups` API has been added to the Agents endpoint, allowing you to retrieve all multi-agent groups associated with a specific agent.
<CodeBlocks>
```python title="python"
from letta_client import Letta
client = Letta(
token="YOUR_API_KEY",
)
agent_groups = client.agents.list_agent_groups(
agent_id="AGENT_ID",
)
```
```typescript title="node.js"
import { LettaClient } from '@letta-ai/letta-client';
const client = new LettaClient({
token: "YOUR_API_KEY",
});
const agentGroups = await client.agents.listAgentGroups({
agent_id: "AGENT_ID",
});
```
</CodeBlocks>

View File

@@ -1,5 +0,0 @@
## New Batch message creation API
A series of new `Batch` endpoints has been introduced to support batch message creation, allowing you to perform multiple LLM requests in a single API call. These APIs leverage provider batch APIs under the hood, which can be more cost-effective than making multiple API calls.
New endpoints can be found here: [Batch Messages](https://docs.letta.com/api-reference/messages/batch)

View File

@@ -1,7 +0,0 @@
# New Projects Endpoint
<Note> These APIs are only available for Letta Cloud. </Note>
A new `Projects` endpoint has been added to the API, allowing you to manage projects and their associated templates.
The new endpoints can be found here: [Projects](https://docs.letta.com/api-reference/projects)

View File

@@ -1,31 +0,0 @@
## SDK Method Name Changes
In an effort to keep our SDK method names consistent with our conventions, we have renamed the following methods:
### Before and After
| SDK Method Name | Before | After |
| --- | --- | --- |
| List Tags | `client.tags.list_tags` | `client.tags.list` |
| Export Agent | `client.agents.export_agent_serialized` | `client.agents.export` |
| Import Agent | `client.agents.import_agent_serialized` | `client.agents.import` |
| Modify Agent Passage | `client.agents.modify_passage` | `client.agents.passages.modify` |
| Reset Agent Messages | `client.agents.reset_messages` | `client.agents.messages.reset` |
| List Agent Groups | `client.agents.list_agent_groups` | `client.agents.groups.list` |
| Reset Group Messages | `client.groups.reset_messages` | `client.groups.messages.reset` |
| Upsert Identity Properties | `client.identities.upsert_identity_properties` | `client.identities.properties.upsert` |
| Retrieve Source by Name | `client.sources.get_by_name` | `client.sources.retrieve_by_name` |
| List Models | `client.models.list_llms` | `client.models.list` |
| List Embeddings | `client.models.list_embedding_models` | `client.embeddings.list` |
| List Agents for Block | `client.blocks.list_agents_for_block` | `client.blocks.agents.list` |
| List Providers | `client.providers.list_providers` | `client.providers.list` |
| Create Provider | `client.providers.create_providers` | `client.providers.create` |
| Modify Provider | `client.providers.modify_providers` | `client.providers.modify` |
| Delete Provider | `client.providers.delete_providers` | `client.providers.delete` |
| List Runs | `client.runs.list_runs` | `client.runs.list` |
| List Active Runs | `client.runs.list_active_runs` | `client.runs.list_active` |
| Retrieve Run | `client.runs.retrieve_run` | `client.runs.retrieve` |
| Delete Run | `client.runs.delete_run` | `client.runs.delete` |
| List Run Messages | `client.runs.list_run_messages` | `client.runs.messages.list` |
| List Run Steps | `client.runs.list_run_steps` | `client.runs.steps.list` |
| Retrieve Run Usage | `client.runs.retrieve_run_usage` | `client.runs.usage.retrieve` |

View File

@@ -1,140 +0,0 @@
# Letta Documentation Diagrams
This directory contains mermaid diagram code for the Letta documentation.
## Diagrams Included
### 1. Agent Reasoning Loop (`agent-reasoning-loop.md`)
**Purpose:** Shows how an agent processes a user message step-by-step
**Location:** `fern/pages/agents/overview.mdx`
**Key insight:** Illustrates the complete lifecycle from request to response, including tool calls
### 2. Memory Hierarchy (`memory-hierarchy.md`)
**Purpose:** Explains the difference between in-context and out-of-context memory
**Location:** `fern/pages/agents/memory.mdx`
**Key insight:** Clarifies why memory blocks are different from RAG/vector search
### 3. Stateful vs Stateless (`stateful-vs-stateless.md`)
**Purpose:** Shows why Letta's stateful design is fundamentally different
**Location:** `fern/pages/concepts/letta.mdx` or homepage
**Key insight:** The "aha moment" - explains why you only send new messages
### 4. Tool Execution Lifecycle (`tool-execution-lifecycle.md`)
**Purpose:** Demystifies how tools are registered, called, and executed
**Location:** `fern/pages/agents/tools.mdx`
**Key insight:** Shows the sandbox execution and tool schema generation
### 5. System Architecture (`system-architecture.md`)
**Purpose:** Complete picture of all Letta components
**Location:** `fern/pages/getting-started/letta_platform.mdx`
**Key insight:** Shows how everything fits together
## How to Use These Diagrams
### 1. Copy the mermaid code blocks into your .mdx files
```markdown
---
title: Your Page Title
---
Your intro text...
```mermaid
[paste diagram code here]
```
Your explanation text...
```
### 2. Customize as needed
Each diagram includes:
- Main version (detailed)
- Alternative version (simplified)
- Explanation text
- Usage notes
Use whichever fits your page best.
### 3. Styling
Mermaid supports both light and dark themes automatically. The diagrams use colors that work in both modes.
To customize colors:
```mermaid
graph TB
A[Node]
style A fill:#e3f2fd
```
## Recommended Diagram Placements
### Critical (Add immediately)
1. **Stateful vs Stateless** → Homepage or concepts page (highest impact)
2. **Agent Reasoning Loop** → Agents overview page
3. **Memory Hierarchy** → Memory guide page
### High Priority
4. **Tool Execution** → Tools guide page
5. **System Architecture** → Platform overview page
### Future Additions
6. Multi-agent communication diagram
7. Sleep-time agent architecture
8. Context window management
9. Streaming architecture
10. Authentication flow
## Creating New Diagrams
When creating new diagrams for Letta docs:
### Use consistent colors:
- Blue (`#e3f2fd`) - Client/API layer
- Purple (`#f3e5f5`) - Server/runtime
- Yellow (`#fff9c4`) - Storage/memory
- Green (`#e8f5e9`) - External services
### Keep them simple:
- One concept per diagram
- 5-10 nodes maximum
- Clear labels and annotations
### Provide alternatives:
- Detailed version for in-depth pages
- Simplified version for quickstarts
- Code comparison when relevant
### Include explanations:
- What the diagram shows
- Why it matters
- How it relates to code
## Mermaid Resources
- [Mermaid Live Editor](https://mermaid.live/) - Test your diagrams
- [Mermaid Documentation](https://mermaid.js.org/) - Syntax reference
- [Fern Mermaid Support](https://buildwithfern.com/learn/docs/content/diagrams) - How Fern renders mermaid
## Testing
Before committing diagrams:
1. Test in [Mermaid Live Editor](https://mermaid.live/)
2. Check both light and dark themes
3. Verify on mobile (diagrams should be responsive)
4. Ensure text is readable at all sizes
## Contributing
To add a new diagram:
1. Create a new `.md` file in this directory
2. Include mermaid code, alternatives, and explanation
3. Add entry to this README
4. Open PR with screenshot of rendered diagram
## Questions?
Slack: #docs
Owner: Documentation Team

View File

@@ -1,104 +0,0 @@
# Agent Reasoning Loop
**Location:** Add to `fern/pages/agents/overview.mdx` after the "Building Stateful Agents" introduction
**What it shows:** The complete lifecycle of an agent processing a user message, including internal reasoning, tool calls, and responses.
## Diagram Code
```mermaid
sequenceDiagram
participant User
participant API as Letta API
participant Agent as Agent Runtime
participant LLM
participant Tools
participant DB as Database
User->>API: POST /agents/{id}/messages
Note over User,API: {"role": "user", "content": "..."}
API->>DB: Load agent state
DB-->>API: AgentState + Memory
API->>Agent: Process message
rect rgb(240, 248, 255)
Note over Agent,LLM: Agent Step 1
Agent->>LLM: Context + User message
Note over Agent,LLM: Context includes:<br/>- System prompt<br/>- Memory blocks<br/>- Available tools<br/>- Recent messages
LLM-->>Agent: Reasoning + Tool call
Note over Agent: reasoning_message:<br/>"User asked about...<br/>I should check..."
Agent->>DB: Save reasoning message
Agent->>Tools: Execute tool
Tools-->>Agent: Tool result
Note over Agent: tool_return_message
Agent->>DB: Save tool call + result
end
rect rgb(255, 250, 240)
Note over Agent,LLM: Agent Step 2
Agent->>LLM: Context + Tool result
LLM-->>Agent: Response to user
Note over Agent: assistant_message:<br/>"Based on the data..."
Agent->>DB: Save response
end
Agent->>DB: Update agent state
Note over DB: State persisted:<br/>- New messages<br/>- Updated memory<br/>- Usage stats
Agent-->>API: Response object
API-->>User: HTTP 200 + messages
Note over User,API: {messages: [reasoning, tool_call,<br/>tool_return, assistant]}
```
## Alternative: Simplified Version
If the above is too detailed, use this simpler version:
```mermaid
sequenceDiagram
participant User
participant Agent
participant LLM
participant Tools
User->>Agent: "What's the weather?"
loop Agent Reasoning Loop
Agent->>LLM: Send context + message
LLM-->>Agent: Think + decide action
alt Agent calls tool
Agent->>Tools: Execute tool
Tools-->>Agent: Return result
Note over Agent: Continue loop with result
else Agent responds to user
Agent-->>User: "It's sunny, 72°F"
Note over Agent: Loop ends
end
end
```
## Explanation to Add
After the diagram, add this text:
> **How it works:**
>
> 1. **User sends message** - A single new message arrives via the API
> 2. **Agent loads context** - System retrieves agent state, memory blocks, and conversation history from the database
> 3. **LLM reasoning** - The agent thinks through the problem (chain-of-thought)
> 4. **Tool execution** - If needed, the agent calls tools to gather information or take actions
> 5. **Response generation** - The agent formulates its final response to the user
> 6. **State persistence** - All steps are saved to the database for future context
>
> Unlike stateless APIs, this entire loop happens **server-side**, and the agent's state persists between messages.
## Usage Notes
- Use the **detailed version** for the main agents overview page
- Use the **simplified version** for the quickstart guide
- Link between the two versions

View File

@@ -1,128 +0,0 @@
# Memory Hierarchy Architecture
**Location:** Add to `fern/pages/agents/memory.mdx` replacing or expanding the current content
**What it shows:** How Letta's memory system works with in-context and out-of-context storage tiers.
## Diagram Code
```mermaid
graph TB
subgraph Context["🧠 LLM Context Window (In-Context Memory)"]
direction TB
SP[System Prompt]
MB[Memory Blocks]
RM[Recent Messages]
subgraph MemBlocks["Core Memory (Self-Editing)"]
P[👤 Persona Block<br/>Who the agent is]
H[👥 Human Block<br/>Who you are]
C1[📝 Custom Block 1<br/>Project context]
C2[📊 Custom Block 2<br/>Task state]
end
SP --> MB
MB --> MemBlocks
MB --> RM
end
subgraph External["💾 External Storage (Out-of-Context Memory)"]
direction TB
subgraph Recall["Recall Memory (Archival)"]
OLD[Older Messages<br/>Searchable by semantic similarity]
end
subgraph Data["Data Sources"]
FILES[Files & Documents<br/>PDFs, text, etc.]
ARCH[Archival Memory<br/>Facts & knowledge]
end
end
MemBlocks -->|Agent edits| MemBlocks
MemBlocks -.->|Agent searches when needed| Recall
MemBlocks -.->|Agent searches when needed| Data
RM -->|When context fills| Recall
style Context fill:#e3f2fd
style External fill:#f3e5f5
style MemBlocks fill:#fff9c4
style P fill:#c8e6c9
style H fill:#c8e6c9
style C1 fill:#ffecb3
style C2 fill:#ffecb3
classDef editableClass stroke:#4caf50,stroke-width:3px
class P,H,C1,C2 editableClass
```
## Alternative: Simpler Conceptual View
```mermaid
graph LR
subgraph Fast["⚡ Core Memory<br/>(Always in context)"]
CORE[Memory Blocks<br/>Editable by agent<br/>Always available]
end
subgraph Slow["🔍 External Memory<br/>(Retrieved when needed)"]
EXT[Conversation History<br/>Files & Documents<br/>Searchable]
end
AGENT[Agent] --> |Reads/Writes| CORE
AGENT -.-> |Searches| Slow
style Fast fill:#c8e6c9
style Slow fill:#e1bee7
```
## Memory Comparison Table
Add this table after the diagram:
```markdown
## Memory Types in Letta
| Memory Type | Location | Size | Speed | Use Case |
|------------|----------|------|-------|----------|
| **Persona Block** | In-context | ~200 tokens | Instant | Agent's identity and behavior |
| **Human Block** | In-context | ~200 tokens | Instant | User information and preferences |
| **Custom Blocks** | In-context | ~200 tokens each | Instant | Task-specific context |
| **Recent Messages** | In-context | Variable | Instant | Conversation flow |
| **Recall Memory** | Out-of-context | Unlimited | ~1-2 sec | Old conversation history |
| **Data Sources** | Out-of-context | Unlimited | ~1-2 sec | Documents and knowledge |
```
## Explanation to Add
After the diagram:
> **How memory works in Letta:**
>
> **Core Memory (In-Context)**
> - **Memory blocks** are always in the LLM's context window
> - Agents can **edit these directly** using built-in tools like `core_memory_replace`
> - Changes persist across conversations
> - Limited by context window size (~2-4KB total)
> - Think of it as "working memory" or "short-term memory"
>
> **External Memory (Out-of-Context)**
> - **Recall memory** stores older messages that don't fit in context
> - **Data sources** store files and documents you upload
> - Agents **search these** when they need information
> - Unlimited size (stored in database)
> - Retrieved via semantic similarity search
> - Think of it as "long-term memory" or "external knowledge"
>
> **Why this matters:**
> Unlike RAG systems that retrieve everything on-demand, Letta agents have a **persistent working memory** that they actively manage. This enables:
> - Personalization that improves over time
> - Task continuity across sessions
> - Contextual awareness without re-retrieving everything
> - Self-directed memory management
## Usage Notes
- Use the **detailed graph** for the memory guide page
- Use the **simplified graph** for the quickstart or overview
- The table helps developers choose the right memory type

View File

@@ -1,161 +0,0 @@
# Stateful vs Stateless: Why Letta is Different
**Location:** Add to `fern/pages/concepts/letta.mdx` early in the document
**What it shows:** The fundamental difference between Letta's stateful agents and traditional stateless LLM APIs.
## Diagram Code
```mermaid
graph TB
subgraph Traditional["❌ Traditional Stateless API (e.g., ChatCompletions)"]
direction TB
U1[User/App]
API1[LLM API]
U1 -->|"Request 1:<br/>[msg1]"| API1
API1 -->|Response 1| U1
U1 -->|"Request 2:<br/>[msg1, response1, msg2]"| API1
API1 -->|Response 2| U1
U1 -->|"Request 3:<br/>[msg1, res1, msg2, res2, msg3]"| API1
API1 -->|Response 3| U1
Note1[❌ Client manages state<br/>❌ No memory persistence<br/>❌ Conversation grows linearly<br/>❌ Context window fills quickly]
style Note1 fill:#ffebee,stroke:#c62828
end
subgraph Letta["✅ Letta Stateful Agents"]
direction TB
U2[User/App]
LETTA[Letta Server]
DB[(Database)]
U2 -->|"Request 1:<br/>[msg1]"| LETTA
LETTA -->|Save state| DB
LETTA -->|Response 1| U2
U2 -->|"Request 2:<br/>[msg2] only!"| LETTA
DB -->|Load state| LETTA
LETTA -->|Update state| DB
LETTA -->|Response 2| U2
U2 -->|"Request 3:<br/>[msg3] only!"| LETTA
DB -->|Load state| LETTA
LETTA -->|Update state| DB
LETTA -->|Response 3| U2
Note2[✅ Server manages state<br/>✅ Persistent memory<br/>✅ Send only new messages<br/>✅ Intelligent context mgmt]
style Note2 fill:#e8f5e9,stroke:#2e7d32
end
```
## Alternative: Side-by-Side Comparison
```mermaid
graph LR
subgraph Stateless["Stateless (OpenAI/Anthropic)"]
direction TB
C1[Client] -->|Full history every time| S1[API]
S1 -->|Response| C1
S1 -.->|No memory| VOID[ ]
style VOID fill:none,stroke:none
end
subgraph Stateful["Stateful (Letta)"]
direction TB
C2[Client] -->|New message only| S2[Agent]
S2 -->|Response| C2
S2 <-->|Persistent state| DB[(Memory)]
end
style Stateless fill:#ffebee
style Stateful fill:#e8f5e9
```
## Comparison Table
```markdown
## Key Differences
| Aspect | Traditional (Stateless) | Letta (Stateful) |
|--------|------------------------|------------------|
| **State management** | Client-side | Server-side |
| **Request format** | Send full conversation history | Send only new messages |
| **Memory** | None (ephemeral) | Persistent database |
| **Context limit** | Hard limit, then fails | Intelligent management |
| **Agent identity** | None | Each agent has unique ID |
| **Long conversations** | Expensive & brittle | Scales infinitely |
| **Personalization** | App must manage | Built-in memory blocks |
| **Multi-session** | Requires external DB | Native support |
## Code Comparison
### Stateless API (e.g., OpenAI)
```python
# You must send the entire conversation every time
messages = [
{"role": "user", "content": "Hello, I'm Sarah"},
{"role": "assistant", "content": "Hi Sarah!"},
{"role": "user", "content": "What's my name?"}, # ← New message
]
# Send everything
response = openai.chat.completions.create(
model="gpt-4",
messages=messages # ← Full history required
)
# You must store and manage messages yourself
messages.append(response.choices[0].message)
```
### Stateful API (Letta)
```python
# Agent already knows context
response = client.agents.messages.create(
agent_id=agent.id,
messages=[
{"role": "user", "content": "What's my name?"} # ← New message only
]
)
# Agent remembers Sarah from its memory blocks
# No need to send previous messages
```
## Explanation Text
> **Why stateful matters:**
>
> **Traditional LLM APIs are stateless** - like hitting "clear chat" after every message. Your application must:
> - Store all messages in a database
> - Send the entire conversation history with each request
> - Manage context window overflow manually
> - Implement memory/personalization logic
> - Handle session management
>
> **Letta agents are stateful services** - like persistent processes. The server:
> - Stores all agent state in its database
> - Accepts only new messages (not full history)
> - Manages context window intelligently
> - Provides built-in memory via editable blocks
> - Maintains agent identity across sessions
>
> **The result:** Instead of building a stateful layer on top of a stateless API, you get statefulness as a primitive.
## Usage Notes
This diagram should appear VERY early in the documentation, ideally:
1. On the main overview page
2. In the concepts/letta.mdx page
3. Referenced in the quickstart
It's the "aha moment" diagram that explains why Letta exists.

View File

@@ -1,295 +0,0 @@
# Letta System Architecture
**Location:** Add to `fern/pages/getting-started/letta_platform.mdx` or `fern/pages/concepts/letta.mdx`
**What it shows:** The complete Letta system with all major components and their relationships.
## Diagram Code
```mermaid
graph TB
subgraph Client["👤 Client Applications"]
PYTHON[Python SDK]
TS[TypeScript SDK]
REST[REST API]
ADE[Agent Dev Environment<br/>Web UI]
end
subgraph Server["🚀 Letta Server"]
direction TB
API[REST API Layer]
subgraph Runtime["Agent Runtime"]
LOOP[Reasoning Loop]
TOOLS[Tool Executor]
MEM[Memory Manager]
end
subgraph Services["Core Services"]
AUTH[Authentication]
QUEUE[Job Queue]
STREAM[Streaming Handler]
end
API --> Runtime
API --> Services
end
subgraph Storage["💾 Storage Layer"]
DB[(PostgreSQL/SQLite)]
VECTOR[(Vector DB<br/>pgvector)]
DB --- VECTOR
end
subgraph External["☁️ External Services"]
LLM[LLM Providers<br/>OpenAI, Anthropic,<br/>Google, etc.]
EMBED[Embedding Models<br/>OpenAI, etc.]
MCPS[MCP Servers<br/>External tools]
end
Client --> Server
Runtime --> Storage
Runtime --> External
Services --> Storage
TOOLS -.->|Optional| MCPS
style Client fill:#e3f2fd
style Server fill:#f3e5f5
style Storage fill:#fff9c4
style External fill:#e8f5e9
```
## Deployment Architecture
```mermaid
graph TB
subgraph Cloud["☁️ Letta Cloud"]
CLOUD_API[API Gateway]
CLOUD_SERVERS[Load Balanced<br/>Letta Servers]
CLOUD_DB[(Managed<br/>PostgreSQL)]
CLOUD_REDIS[(Redis Cache)]
CLOUD_API --> CLOUD_SERVERS
CLOUD_SERVERS --> CLOUD_DB
CLOUD_SERVERS --> CLOUD_REDIS
end
subgraph Self["🏠 Self-Hosted"]
DOCKER[Docker Container]
LOCAL_DB[(PostgreSQL<br/>or SQLite)]
DOCKER --> LOCAL_DB
end
subgraph Apps["Your Applications"]
WEB[Web App]
MOBILE[Mobile App]
BOT[Chatbot]
API_APP[API Service]
end
Apps --> Cloud
Apps --> Self
style Cloud fill:#e3f2fd
style Self fill:#fff9c4
```
## Data Flow Diagram
```mermaid
flowchart LR
subgraph Input
USER[User Message]
end
subgraph Processing
LOAD[Load Agent State]
CONTEXT[Build Context]
LLM[LLM Inference]
TOOLS[Execute Tools]
SAVE[Save State]
end
subgraph Output
RESPONSE[Agent Response]
end
USER --> LOAD
LOAD --> CONTEXT
CONTEXT --> LLM
LLM --> TOOLS
TOOLS --> LLM
LLM --> SAVE
SAVE --> RESPONSE
DB[(Database)] -.-> LOAD
SAVE -.-> DB
style Input fill:#e3f2fd
style Processing fill:#f3e5f5
style Output fill:#c8e6c9
```
## Component Details
```markdown
## System Components
### Client SDKs
- **Python SDK** (`letta-client`) - Full-featured client for Python applications
- **TypeScript SDK** (`@letta-ai/letta-client`) - Full-featured client for Node.js/TypeScript
- **REST API** - Direct HTTP access for any language
- **ADE (Agent Development Environment)** - Web-based UI for building and testing agents
### Letta Server
#### API Layer
- RESTful endpoints for all operations
- OpenAPI/Swagger specification
- Authentication and authorization
- Request validation
#### Agent Runtime
- **Reasoning Loop** - Manages agent execution steps
- **Tool Executor** - Runs tools in isolated sandbox
- **Memory Manager** - Handles memory block operations and recall
#### Core Services
- **Authentication** - API key management, user sessions
- **Job Queue** - Async task processing
- **Streaming Handler** - Server-sent events for real-time updates
### Storage Layer
#### Database (PostgreSQL or SQLite)
Stores:
- Agent configurations and state
- Memory blocks
- Message history
- Tools and tool definitions
- User accounts and API keys
#### Vector Database (pgvector)
Stores:
- Message embeddings for semantic search
- Document embeddings for data sources
- Enables recall memory and archival search
### External Services
#### LLM Providers
- OpenAI (GPT-4, GPT-3.5)
- Anthropic (Claude)
- Google (Gemini)
- DeepSeek, xAI, Groq, etc.
- Local providers (Ollama, LM Studio, vLLM)
#### Embedding Providers
- OpenAI embeddings
- Local embedding models
#### MCP Servers (Optional)
- External tool providers
- Connect via HTTP/SSE or stdio
- Examples: GitHub, Gmail, databases
## Deployment Options
### Letta Cloud
- Fully managed service
- Multi-tenant architecture
- Automatic scaling
- Built-in monitoring
- 99.9% uptime SLA
- Managed database and infrastructure
**Best for:**
- Quick prototyping
- Production deployments
- No infrastructure management
### Self-Hosted
- Docker container
- Full control over infrastructure
- Your own database
- Custom configuration
**Best for:**
- Data privacy requirements
- Custom infrastructure needs
- Cost optimization at scale
- Air-gapped environments
## Data Flow
1. **Request arrives** - Client sends message to API
2. **Load state** - Agent configuration and memory loaded from DB
3. **Build context** - System prompt, memory blocks, tools assembled
4. **LLM inference** - Context sent to LLM provider
5. **Tool execution** - If LLM calls tools, they execute in sandbox
6. **Iteration** - Loop continues until agent responds to user
7. **Save state** - All changes persisted to database
8. **Response** - Agent response returned to client
## Scaling Characteristics
### Horizontal Scaling
- Multiple Letta server instances behind load balancer
- Shared database for state consistency
- Redis for distributed caching (optional)
### Vertical Scaling
- Increase database resources for more agents
- More CPU/RAM for concurrent agent execution
- SSD for faster database queries
### Performance
- ~1-5 seconds average response time (depends on LLM)
- Thousands of agents per server instance
- Millions of messages stored efficiently
- Concurrent agent execution supported
```
## Architecture Decision Records
```markdown
## Why This Architecture?
### Stateful Server Design
Unlike frameworks that run in your application, Letta is a separate service:
- **Persistent identity** - Agents exist independently
- **Shared access** - Multiple clients can connect to same agents
- **State isolation** - Client logic separated from agent logic
- **Easier debugging** - Centralized state inspection
### Database-Backed
All state in PostgreSQL/SQLite:
- **Durability** - Agents survive server restarts
- **Portability** - Export agents to move between servers
- **Auditability** - Complete history preserved
- **Multi-tenancy** - Secure isolation between users
### Pluggable LLMs
Model-agnostic design:
- **Provider flexibility** - Switch between OpenAI, Anthropic, local, etc.
- **No lock-in** - Your agent data is portable
- **Cost optimization** - Use cheaper models where appropriate
- **Future-proof** - New models work without code changes
### Sandbox Tool Execution
Tools run in isolation:
- **Security** - Untrusted code can't access server
- **Resource limits** - CPU, memory, time constraints
- **Reliability** - One tool crash doesn't kill agent
- **Debugging** - Tool failures are captured and logged
```
## Usage Notes
- Place the **main architecture diagram** on the platform overview page
- Use the **deployment diagram** in the self-hosting guide
- The **data flow diagram** helps debug issues
- The explanation text clarifies why Letta is architected this way

View File

@@ -1,214 +0,0 @@
# Tool Execution Lifecycle
**Location:** Add to `fern/pages/agents/tools.mdx` near the beginning
**What it shows:** How tools are registered, called by agents, executed, and return results.
## Diagram Code
```mermaid
sequenceDiagram
participant Dev as Developer
participant Server as Letta Server
participant Agent as Agent Runtime
participant LLM
participant Sandbox as Tool Sandbox
Note over Dev,Server: 1. Tool Registration
Dev->>Server: Create tool from function
Note over Dev,Server: def my_tool(arg: str) -> str:<br/> """Tool description"""<br/> return result
Server->>Server: Parse docstring
Server->>Server: Generate JSON schema
Note over Server: {<br/> "name": "my_tool",<br/> "parameters": {...}<br/>}
Server->>Server: Store in database
Note over Dev,Server: 2. Attach to Agent
Dev->>Server: Attach tool to agent
Server->>Agent: Update agent config
rect rgb(240, 248, 255)
Note over Agent,Sandbox: 3. Runtime Execution
Agent->>LLM: Send prompt + tools
Note over LLM: Available tools in context
LLM-->>Agent: Tool call decision
Note over Agent: {<br/> "name": "my_tool",<br/> "arguments": {"arg": "value"}<br/>}
Agent->>Agent: Validate arguments
Agent->>Agent: Save tool_call_message
Agent->>Sandbox: Execute in sandbox
Note over Sandbox: Isolated execution<br/>Resource limits applied
Sandbox-->>Agent: Return result
Agent->>Agent: Save tool_return_message
Agent->>LLM: Continue with result
Note over Agent,LLM: Result added to context
end
```
## Alternative: Simplified Flow
```mermaid
flowchart TD
Start([User message]) --> Think{Agent thinks}
Think -->|Need information| Tool[Call tool]
Think -->|Can respond| End([Send message])
Tool --> Execute[Execute in sandbox]
Execute --> Result[Get result]
Result --> Think
style Tool fill:#fff9c4
style Execute fill:#e1bee7
style Result fill:#c8e6c9
```
## Tool Types Diagram
```mermaid
graph TB
subgraph Built-in["🔧 Built-in Tools"]
MEM[Memory Tools<br/>edit_memory, etc.]
SEND[send_message<br/>Respond to user]
SEARCH[web_search<br/>Search internet]
CODE[run_code<br/>Execute code]
end
subgraph Custom["⚙️ Custom Tools"]
PYTHON[Python Functions<br/>Your code]
MCP[MCP Tools<br/>External servers]
COMP[Composio Tools<br/>SaaS integrations]
end
Agent[Agent] --> Built-in
Agent --> Custom
style Built-in fill:#e3f2fd
style Custom fill:#fff9c4
```
## Explanation to Add
```markdown
## How Tools Work
### 1. Tool Registration
When you create a tool, Letta:
- Parses your function signature and docstring
- Generates an OpenAI-compatible JSON schema
- Stores the tool code and schema in the database
Example:
```python
def search_database(query: str) -> list:
"""
Search the product database.
Args:
query (str): Search query
Returns:
list: Matching products
"""
# Your implementation
return results
```
Becomes:
```json
{
"name": "search_database",
"description": "Search the product database.",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "Search query"}
},
"required": ["query"]
}
}
```
### 2. Tool Context
When an agent processes a message:
- All attached tool schemas are included in the LLM context
- The LLM decides whether to call a tool or respond directly
- The LLM generates structured tool call arguments
### 3. Execution
When the agent calls a tool:
- **Arguments are validated** against the schema
- **Tool is executed** in an isolated sandbox (for security)
- **Result is returned** and added to the agent's context
- **Agent continues thinking** with the new information
### 4. Security
Tools run in a sandbox with:
- **Resource limits** (CPU, memory, time)
- **Isolated environment** (can't access other agents or server)
- **Restricted imports** (configurable)
- **Execution timeout** (prevents infinite loops)
### 5. Tool Types
#### Memory Tools (Built-in, Always Attached)
- `core_memory_append` - Add to memory block
- `core_memory_replace` - Update memory block
- `archival_memory_insert` - Store long-term facts
- `archival_memory_search` - Retrieve facts
- `conversation_search` - Search message history
#### Communication Tools (Built-in, Default)
- `send_message` - Respond to the user
#### Utility Tools (Built-in, Optional)
- `web_search` - Search the web (Letta Cloud includes credits)
- `run_code` - Execute code in multiple languages
#### Custom Tools
- **Python functions** - Your own code
- **MCP tools** - Connect to MCP servers
- **Composio tools** - Pre-built SaaS integrations
## Tool Call Flow Example
```
User: "What's the weather in SF?"
Agent thinks: "I need weather data"
Agent calls: web_search("weather san francisco")
Tool executes: Returns "Sunny, 72°F"
Agent thinks: "I have the information"
Agent calls: send_message("It's sunny and 72°F in San Francisco!")
User receives: "It's sunny and 72°F in San Francisco!"
```
## Tool Best Practices
1. **Clear descriptions** - The LLM relies on these to decide when to call tools
2. **Typed arguments** - Use type hints for automatic schema generation
3. **Error handling** - Return informative error messages
4. **Idempotency** - Tools may be called multiple times
5. **Performance** - Keep tool execution fast (< 5 seconds)
```
## Usage Notes
- Place the **sequence diagram** early in the tools documentation
- Use the **simplified flow** in the quickstart
- The **tool types diagram** helps users understand what's available
- The explanation clarifies the "magic" of tool execution

Binary file not shown.

Before

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 323 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 332 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 876 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 864 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 814 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 820 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 609 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 413 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 640 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 381 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 612 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 437 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 782 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 559 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 548 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 377 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 513 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 367 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 604 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 409 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 641 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 382 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 611 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 436 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 776 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 556 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 544 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 376 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 510 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 366 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 157 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 218 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 971 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 174 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

Some files were not shown because too many files have changed in this diff Show More