Merge pull request 'letta: placed state, a route, accepted keys, and a runtime that can log in' (#171) from feat/letta-for-ace into main

This commit was merged in pull request #171.
This commit is contained in:
2026-09-30 13:55:23 +00:00
2 changed files with 29 additions and 29 deletions
+8 -4
View File
@@ -1,10 +1,10 @@
// The Letta API client — letta's own code, living in the module (novox/hq ADR 0039). Its tools // The Letta API client — letta's own code, living in the module (novox/hq ADR 0039). Its tools
// import it; nothing outside letta does. // import it; nothing outside letta does.
// //
// Letta authenticates with a single server password, presented as a Bearer token. That password is // Letta authenticates with a single server password. That password is a mesh own-secret handed to
// a mesh own-secret, minted once and handed to both the server (LETTA_SERVER_PASSWORD) and this // both the server (LETTA_SERVER_PASSWORD) and this client, through the runtime config file the mesh
// client (MESH_LETTA_PASSWORD) — so the module's tools are live without anything configured by hand. // mounts (its `password` key) — so the module's tools are live without anything configured by hand.
// The runtime config file may still override the URL or password. // Where a server already has clients, the password is accepted rather than minted.
import { readFileSync } from "node:fs"; import { readFileSync } from "node:fs";
@@ -58,6 +58,10 @@ export class LettaClient {
...options, ...options,
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
// The server's --secure mode checks X-BARE-PASSWORD ("password <it>") and answers a Bearer
// token alone with 401 (letta/server/rest_api/app.py, 0.6.x). Both are sent: Bearer is what
// later servers read.
"X-BARE-PASSWORD": `password ${this.password}`,
Authorization: `Bearer ${this.password}`, Authorization: `Bearer ${this.password}`,
...(options.headers as Record<string, string> | undefined), ...(options.headers as Record<string, string> | undefined),
}, },
+21 -25
View File
@@ -5,21 +5,28 @@
"container-runtime" "container-runtime"
], ],
"requires": [ "requires": [
"postgres-database" "postgres-database",
"route"
], ],
"contributes": { "contributes": {
"postgres-database": { "postgres-database": {
"name": "letta" "name": "letta"
},
"route": {
"label": "letta",
"endpoint": "web"
} }
}, },
"binds": { "binds": {
"postgres-database": "/var/lib/letta/database.json" "postgres-database": "${dir:state}/database.json",
"route": "${dir:state}/route.json"
}, },
"secrets": { "secrets": {
"postgres-database": "/var/lib/letta/database.secret" "postgres-database": "${dir:state}/database.secret"
}, },
"own-secrets": { "own-secrets": {
"server-password": "/var/lib/letta/server-password.secret", "server-password": "${dir:state}/server-password.secret",
"openai-api-key": "${dir:state}/openai-api-key.secret",
"broker": "/var/lib/mesh/letta/broker" "broker": "/var/lib/mesh/letta/broker"
}, },
"listens": [ "listens": [
@@ -28,7 +35,7 @@
"port": 8283, "port": 8283,
"protocol": "tcp", "protocol": "tcp",
"from": "mesh", "from": "mesh",
"why": "the Letta agent server REST API and web UI; a public name is a route grant later" "why": "the Letta agent server REST API and web UI, password-protected (--secure); a public name is the route's"
} }
], ],
"resources": [ "resources": [
@@ -41,15 +48,15 @@
{ {
"id": "state", "id": "state",
"type": "directory", "type": "directory",
"path": "/var/lib/letta", "mode": "0700",
"mode": "0700" "place": "."
}, },
{ {
"id": "server-env", "id": "server-env",
"type": "file", "type": "file",
"path": "/var/lib/letta/server.env", "path": "${dir:state}/server.env",
"mode": "0600", "mode": "0600",
"content": "LETTA_PG_URI=postgresql://${bound:postgres-database:as}:${secret:postgres-database}@${bound:postgres-database:at}:${bound:postgres-database:port}/${bound:postgres-database:as}\nLETTA_SERVER_PASSWORD=${secret:server-password}\nSECURE=true\nTZ=Europe/Brussels\n" "content": "LETTA_PG_URI=postgresql://${bound:postgres-database:as}:${secret:postgres-database}@${bound:postgres-database:at}:${bound:postgres-database:port}/${bound:postgres-database:as}\nLETTA_SERVER_PASSWORD=${secret:server-password}\nOPENAI_API_KEY=${secret:openai-api-key}\nSECURE=true\nTZ=Europe/Brussels\n"
}, },
{ {
"id": "net", "id": "net",
@@ -60,31 +67,24 @@
"id": "server", "id": "server",
"type": "container", "type": "container",
"name": "letta", "name": "letta",
"image": "letta/letta@sha256:1d2e0692514287c5ed1a483e14e16ed945f8632d315539f5e66373bb7d7c471b", "image": "letta/letta@sha256:bfd1e49ce45b9a208c941e832c1d1d194017ff210a3784b0ca6c323aed767a29",
"network": "letta", "network": "letta",
"env-file": [ "env-file": [
"/var/lib/letta/server.env" "${dir:state}/server.env"
], ],
"ports": [ "ports": [
"8283" "8283"
], ],
"secrets-in-environment": "the letta image is env-driven and its file-source support could not be verified; the mesh runtime can take its password from config.json (client.ts) \u2014 not yet converted" "secrets-in-environment": "letta 0.6.x reads its settings from the environment only (pydantic settings, no secrets_dir or _FILE twin), and its startup.sh starts an embedded PostgreSQL unless LETTA_PG_URI is set - so the database password travels inside that URI (startup.sh also echoes it to the log); LETTA_SERVER_PASSWORD and OPENAI_API_KEY have no file source either"
}, },
{ {
"id": "runtime-config", "id": "runtime-config",
"type": "file", "type": "file",
"path": "/var/lib/mesh/letta/config.json", "path": "/var/lib/mesh/letta/config.json",
"mode": "0600", "mode": "0600",
"content": "{}\n", "content": "{\n \"password\": \"${secret:server-password}\"\n}\n",
"merge": "json" "merge": "json"
}, },
{
"id": "runtime-env",
"type": "file",
"path": "/var/lib/letta/runtime.env",
"mode": "0600",
"content": "MESH_LETTA_PASSWORD=${secret:server-password}\n"
},
{ {
"id": "runtime", "id": "runtime",
"type": "container", "type": "container",
@@ -99,14 +99,10 @@
"MESH_LETTA_URL": "http://letta:8283", "MESH_LETTA_URL": "http://letta:8283",
"MESH_LETTA_CONFIG_FILE": "/run/config/config.json" "MESH_LETTA_CONFIG_FILE": "/run/config/config.json"
}, },
"env-file": [
"/var/lib/letta/runtime.env"
],
"restart-on": [ "restart-on": [
"runtime-config" "runtime-config"
], ],
"artifact": "runtime", "artifact": "runtime"
"secrets-in-environment": "the letta image is env-driven and its file-source support could not be verified; the mesh runtime can take its password from config.json (client.ts) \u2014 not yet converted"
} }
], ],
"build": { "build": {