chore: clean up docs
|
Before Width: | Height: | Size: 141 KiB |
|
Before Width: | Height: | Size: 153 KiB |
|
Before Width: | Height: | Size: 342 B |
@@ -1,145 +0,0 @@
|
||||
/* ────────────────────────────────────────────────────────────────
|
||||
assets/leaderboard.css (namespaced so it never leaks styles)
|
||||
──────────────────────────────────────────────────────────────── */
|
||||
|
||||
/* hide rows that don’t 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 doesn’t 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 */
|
||||
}
|
||||
@@ -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();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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 |
@@ -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 |
@@ -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;
|
||||
}
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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",
|
||||
)
|
||||
```
|
||||
@@ -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
|
||||
@@ -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.
|
||||
@@ -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).
|
||||
@@ -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>
|
||||
@@ -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).
|
||||
@@ -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>
|
||||
@@ -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="..."`.
|
||||
@@ -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>
|
||||
@@ -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(),
|
||||
)
|
||||
```
|
||||
@@ -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>
|
||||
@@ -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
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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).
|
||||
@@ -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>
|
||||
@@ -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?"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
@@ -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.
|
||||
@@ -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>
|
||||
@@ -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.
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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` |
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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.
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
Before Width: | Height: | Size: 73 KiB |
|
Before Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 323 KiB |
|
Before Width: | Height: | Size: 332 KiB |
|
Before Width: | Height: | Size: 125 KiB |
|
Before Width: | Height: | Size: 876 KiB |
|
Before Width: | Height: | Size: 864 KiB |
|
Before Width: | Height: | Size: 814 KiB |
|
Before Width: | Height: | Size: 820 KiB |
|
Before Width: | Height: | Size: 84 KiB |
|
Before Width: | Height: | Size: 125 KiB |
|
Before Width: | Height: | Size: 131 KiB |
|
Before Width: | Height: | Size: 92 KiB |
|
Before Width: | Height: | Size: 609 KiB |
|
Before Width: | Height: | Size: 413 KiB |
|
Before Width: | Height: | Size: 640 KiB |
|
Before Width: | Height: | Size: 381 KiB |
|
Before Width: | Height: | Size: 612 KiB |
|
Before Width: | Height: | Size: 437 KiB |
|
Before Width: | Height: | Size: 782 KiB |
|
Before Width: | Height: | Size: 559 KiB |
|
Before Width: | Height: | Size: 548 KiB |
|
Before Width: | Height: | Size: 377 KiB |
|
Before Width: | Height: | Size: 513 KiB |
|
Before Width: | Height: | Size: 367 KiB |
|
Before Width: | Height: | Size: 604 KiB |
|
Before Width: | Height: | Size: 409 KiB |
|
Before Width: | Height: | Size: 641 KiB |
|
Before Width: | Height: | Size: 382 KiB |
|
Before Width: | Height: | Size: 611 KiB |
|
Before Width: | Height: | Size: 436 KiB |
|
Before Width: | Height: | Size: 776 KiB |
|
Before Width: | Height: | Size: 556 KiB |
|
Before Width: | Height: | Size: 544 KiB |
|
Before Width: | Height: | Size: 376 KiB |
|
Before Width: | Height: | Size: 510 KiB |
|
Before Width: | Height: | Size: 366 KiB |
|
Before Width: | Height: | Size: 157 KiB |
|
Before Width: | Height: | Size: 218 KiB |
|
Before Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 971 KiB |
|
Before Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 169 KiB |
|
Before Width: | Height: | Size: 71 KiB |
|
Before Width: | Height: | Size: 154 KiB |
|
Before Width: | Height: | Size: 174 KiB |
|
Before Width: | Height: | Size: 68 KiB |