@data-club/ai-hub-server 0.0.9 → 0.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth/encryption.d.ts +5 -5
- package/dist/auth/encryption.js +5 -5
- package/dist/auth/userView.d.ts +8 -15
- package/dist/auth/userView.d.ts.map +1 -1
- package/dist/auth/userView.js +10 -23
- package/dist/auth/userView.js.map +1 -1
- package/dist/bootstrap.d.ts +2 -8
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +2 -35
- package/dist/bootstrap.js.map +1 -1
- package/dist/db/migrate.js +6 -17
- package/dist/db/migrate.js.map +1 -1
- package/dist/db/schema.d.ts +17 -263
- package/dist/db/schema.d.ts.map +1 -1
- package/dist/db/schema.js +8 -57
- package/dist/db/schema.js.map +1 -1
- package/dist/db/seed.d.ts +4 -19
- package/dist/db/seed.d.ts.map +1 -1
- package/dist/db/seed.js +6 -33
- package/dist/db/seed.js.map +1 -1
- package/dist/handlers/fetch.d.ts +6 -7
- package/dist/handlers/fetch.d.ts.map +1 -1
- package/dist/handlers/fetch.js +1 -3
- package/dist/handlers/fetch.js.map +1 -1
- package/dist/handlers/types.d.ts +5 -6
- package/dist/handlers/types.d.ts.map +1 -1
- package/dist/letta/client.d.ts +86 -263
- package/dist/letta/client.d.ts.map +1 -1
- package/dist/letta/client.js +99 -404
- package/dist/letta/client.js.map +1 -1
- package/dist/letta/index.d.ts +6 -8
- package/dist/letta/index.d.ts.map +1 -1
- package/dist/letta/index.js +5 -7
- package/dist/letta/index.js.map +1 -1
- package/dist/letta/sandbox.d.ts +45 -9
- package/dist/letta/sandbox.d.ts.map +1 -1
- package/dist/letta/sandbox.js +123 -11
- package/dist/letta/sandbox.js.map +1 -1
- package/dist/letta/types.d.ts +6 -49
- package/dist/letta/types.d.ts.map +1 -1
- package/dist/letta/types.js +5 -10
- package/dist/letta/types.js.map +1 -1
- package/dist/observability/logger.d.ts.map +1 -1
- package/dist/observability/logger.js +0 -2
- package/dist/observability/logger.js.map +1 -1
- package/dist/routes/admin/agents.d.ts.map +1 -1
- package/dist/routes/admin/agents.js +0 -40
- package/dist/routes/admin/agents.js.map +1 -1
- package/dist/routes/admin/rotatingMessages.d.ts.map +1 -1
- package/dist/routes/admin/rotatingMessages.js +37 -1
- package/dist/routes/admin/rotatingMessages.js.map +1 -1
- package/dist/routes/admin/settings.d.ts +6 -15
- package/dist/routes/admin/settings.d.ts.map +1 -1
- package/dist/routes/admin/settings.js +9 -107
- package/dist/routes/admin/settings.js.map +1 -1
- package/dist/routes/auth.d.ts +0 -4
- package/dist/routes/auth.d.ts.map +1 -1
- package/dist/routes/auth.js +1 -5
- package/dist/routes/auth.js.map +1 -1
- package/dist/routes/sessions.d.ts.map +1 -1
- package/dist/routes/sessions.js +9 -30
- package/dist/routes/sessions.js.map +1 -1
- package/dist/state/rotationRunner.d.ts +6 -0
- package/dist/state/rotationRunner.d.ts.map +1 -1
- package/dist/state/rotationRunner.js +19 -2
- package/dist/state/rotationRunner.js.map +1 -1
- package/dist/state/rotationScheduler.d.ts +2 -0
- package/dist/state/rotationScheduler.d.ts.map +1 -1
- package/dist/state/rotationScheduler.js.map +1 -1
- package/dist/state/turnRunner.d.ts.map +1 -1
- package/dist/state/turnRunner.js +1 -75
- package/dist/state/turnRunner.js.map +1 -1
- package/package.json +4 -4
- package/src/auth/encryption.ts +5 -5
- package/src/auth/userView.ts +9 -22
- package/src/bootstrap.ts +4 -43
- package/src/db/migrate.ts +6 -17
- package/src/db/schema.ts +8 -68
- package/src/db/seed.ts +6 -47
- package/src/handlers/fetch.ts +7 -10
- package/src/handlers/types.ts +5 -6
- package/src/letta/client.ts +170 -634
- package/src/letta/index.ts +8 -21
- package/src/letta/sandbox.ts +151 -11
- package/src/letta/types.ts +9 -60
- package/src/observability/logger.ts +0 -2
- package/src/routes/admin/agents.ts +0 -49
- package/src/routes/admin/rotatingMessages.ts +47 -1
- package/src/routes/admin/settings.ts +9 -113
- package/src/routes/auth.ts +1 -5
- package/src/routes/sessions.ts +11 -32
- package/src/state/rotationRunner.ts +37 -1
- package/src/state/rotationScheduler.ts +2 -0
- package/src/state/turnRunner.ts +1 -77
- package/src/letta/lettaCliShim.mjs +0 -40
- package/src/letta/settingsFileSeed.ts +0 -254
|
@@ -1,254 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Seeds Letta Code's global agent-settings file (`~/.letta/settings.json`)
|
|
3
|
-
* with `{toolset: "none"}` for each ai-hub-registered Letta agent.
|
|
4
|
-
*
|
|
5
|
-
* **Why this matters.** Letta Code's bundled CLI auto-attaches a "toolset"
|
|
6
|
-
* (a set of file-edit / shell / search tools — `Read`, `Write`, `Edit`,
|
|
7
|
-
* `Bash`, etc.) to every agent at session start, based on the model handle.
|
|
8
|
-
* ai-hub doesn't want those tools — we want only the tools the ADE admin
|
|
9
|
-
* explicitly attached to the agent. The CLI honors a per-agent
|
|
10
|
-
* `toolset: "none"` preference stored in its global settings file, which
|
|
11
|
-
* suppresses the entire auto-toolset.
|
|
12
|
-
*
|
|
13
|
-
* **Why global, not project-local.** Letta Code's `SettingsManager` reads
|
|
14
|
-
* the toolset preference from `~/.letta/settings.json` (the global file),
|
|
15
|
-
* not `<cwd>/.letta/settings.local.json` (the project file). The global
|
|
16
|
-
* settings carry agent records keyed by `(agentId, normalizedBaseUrl)`
|
|
17
|
-
* where `normalizedBaseUrl` is the value of `LETTA_BASE_URL` with the
|
|
18
|
-
* scheme and trailing slash stripped, or `undefined` when the agent lives
|
|
19
|
-
* on Letta Cloud. Self-hosted Letta deployments always have a non-default
|
|
20
|
-
* `LETTA_BASE_URL` so the agent record always has the `baseUrl` field set.
|
|
21
|
-
*
|
|
22
|
-
* The `LETTA_CLI_PATH` shim (which injects `--tools ""`) is the primary
|
|
23
|
-
* mechanism that forces an empty tool registry; this settings-file seed
|
|
24
|
-
* is the defense-in-depth fallback the TUI also honors.
|
|
25
|
-
*/
|
|
26
|
-
|
|
27
|
-
import {
|
|
28
|
-
existsSync,
|
|
29
|
-
mkdirSync,
|
|
30
|
-
readFileSync,
|
|
31
|
-
renameSync,
|
|
32
|
-
writeFileSync,
|
|
33
|
-
} from "node:fs";
|
|
34
|
-
import { homedir } from "node:os";
|
|
35
|
-
import { dirname, join } from "node:path";
|
|
36
|
-
|
|
37
|
-
import type { Logger } from "../observability/logger.js";
|
|
38
|
-
|
|
39
|
-
/* ────────────────────────────────────────────────────────────────────────── */
|
|
40
|
-
/* Settings file shape */
|
|
41
|
-
/* ────────────────────────────────────────────────────────────────────────── */
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Toolset preference values accepted by Letta Code. `"none"` is the
|
|
45
|
-
* documented-but-not-help-listed value that suppresses every auto-attached
|
|
46
|
-
* tool; the named toolsets (`codex`, `gemini`, `default`) attach specific
|
|
47
|
-
* sets of file/shell tools that ai-hub doesn't want.
|
|
48
|
-
*
|
|
49
|
-
* The string is treated as an opaque scalar by Letta Code's persistence
|
|
50
|
-
* layer; we still narrow the TypeScript type here so a typo in this file
|
|
51
|
-
* fails at compile time.
|
|
52
|
-
*/
|
|
53
|
-
export type ToolsetPreference = "none" | "auto" | "codex" | "codex_snake" | "gemini" | "gemini_snake" | "default";
|
|
54
|
-
|
|
55
|
-
/** One agent entry inside the global settings file. Mirrors Letta Code's
|
|
56
|
-
* internal shape so our writes round-trip with its own writes. Optional
|
|
57
|
-
* fields are intentionally absent when unset, matching Letta Code's
|
|
58
|
-
* delete-when-falsy convention. */
|
|
59
|
-
export interface AgentSettingsEntry {
|
|
60
|
-
agentId: string;
|
|
61
|
-
/** Normalized base URL ("localhost:8283/v1" style — no scheme, no
|
|
62
|
-
* trailing slash). Omitted for Letta Cloud agents. */
|
|
63
|
-
baseUrl?: string;
|
|
64
|
-
pinned?: boolean;
|
|
65
|
-
memfs?: boolean;
|
|
66
|
-
toolset?: ToolsetPreference;
|
|
67
|
-
systemPromptPreset?: string;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/** Shape of `~/.letta/settings.json` that we touch. We pass through every
|
|
71
|
-
* unknown top-level field unchanged so concurrent Letta Code edits don't
|
|
72
|
-
* lose data. */
|
|
73
|
-
export interface LettaCodeSettingsFile {
|
|
74
|
-
agents?: AgentSettingsEntry[];
|
|
75
|
-
/** Any other fields Letta Code writes (oauth state, env vars, …). We
|
|
76
|
-
* treat them as opaque on read + write. */
|
|
77
|
-
[other: string]: unknown;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/* ────────────────────────────────────────────────────────────────────────── */
|
|
81
|
-
/* Path resolution */
|
|
82
|
-
/* ────────────────────────────────────────────────────────────────────────── */
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Returns the absolute path to Letta Code's global settings file. Tests
|
|
86
|
-
* override `HOME` to point at a tmp dir.
|
|
87
|
-
*
|
|
88
|
-
* @returns the path. (Doesn't check existence — caller does.)
|
|
89
|
-
*/
|
|
90
|
-
export function resolveGlobalSettingsPath(): string {
|
|
91
|
-
return join(homedir(), ".letta", "settings.json");
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Normalizes `LETTA_BASE_URL` to match the key Letta Code's CLI uses to
|
|
96
|
-
* look up agent settings AFTER ai-hub-server's `bootstrap.ts` runs its
|
|
97
|
-
* own `/v1` stripping. The CLI itself only strips scheme + trailing
|
|
98
|
-
* slash (so `http://host:p/v1` → `host:p/v1`), but bootstrap.ts mutates
|
|
99
|
-
* `process.env.LETTA_BASE_URL` at boot to drop the `/v1` (because the
|
|
100
|
-
* Letta Client SDK that the CLI uses internally appends `/v1` itself —
|
|
101
|
-
* leaving it in the env produces double-`/v1` requests that 404).
|
|
102
|
-
*
|
|
103
|
-
* So by the time the spawned CLI looks up the agent settings, its
|
|
104
|
-
* `getCurrentServerKey` reads `http://host:p` from env and produces
|
|
105
|
-
* `host:p`. The settings file entry must use the same key — hence the
|
|
106
|
-
* extra `/v1` strip here. If `bootstrap.ts` changes its policy, this
|
|
107
|
-
* helper has to change in lockstep.
|
|
108
|
-
*
|
|
109
|
-
* Returns `undefined` for the Letta Cloud default URL (so the agent
|
|
110
|
-
* record omits the `baseUrl` field, matching Letta Code's behavior on
|
|
111
|
-
* Cloud).
|
|
112
|
-
*
|
|
113
|
-
* @param baseUrl - raw `LETTA_BASE_URL` value.
|
|
114
|
-
* @returns the normalized form, or `undefined` for Letta Cloud.
|
|
115
|
-
*/
|
|
116
|
-
export function normalizeLettaBaseUrl(baseUrl: string | undefined): string | undefined {
|
|
117
|
-
if (!baseUrl) return undefined;
|
|
118
|
-
const stripped = baseUrl
|
|
119
|
-
.replace(/^https?:\/\//, "")
|
|
120
|
-
.replace(/\/v1\/?$/i, "")
|
|
121
|
-
.replace(/\/$/, "");
|
|
122
|
-
if (stripped === "api.letta.com") return undefined;
|
|
123
|
-
return stripped;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/* ────────────────────────────────────────────────────────────────────────── */
|
|
127
|
-
/* Read + write */
|
|
128
|
-
/* ────────────────────────────────────────────────────────────────────────── */
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Reads the settings file from disk. Returns an empty object if the file
|
|
132
|
-
* doesn't exist or is unparseable — both cases are recoverable by an
|
|
133
|
-
* idempotent upsert that recreates the file.
|
|
134
|
-
*
|
|
135
|
-
* @param path - the resolved settings path.
|
|
136
|
-
* @returns the parsed settings (or `{}`).
|
|
137
|
-
*/
|
|
138
|
-
export function readSettingsFile(path: string): LettaCodeSettingsFile {
|
|
139
|
-
if (!existsSync(path)) return {};
|
|
140
|
-
try {
|
|
141
|
-
const raw = readFileSync(path, "utf8");
|
|
142
|
-
if (!raw.trim()) return {};
|
|
143
|
-
const parsed = JSON.parse(raw);
|
|
144
|
-
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
145
|
-
return parsed as LettaCodeSettingsFile;
|
|
146
|
-
}
|
|
147
|
-
return {};
|
|
148
|
-
} catch {
|
|
149
|
-
// Malformed file (concurrent write, disk corruption) — treat as empty
|
|
150
|
-
// so the seed proceeds. Worst case the operator's other settings (if
|
|
151
|
-
// any) are clobbered, which is acceptable when the file was already
|
|
152
|
-
// broken.
|
|
153
|
-
return {};
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Writes the settings file atomically: write to `<path>.tmp` then rename.
|
|
159
|
-
* The rename is atomic on every filesystem the ai-hub-server supports
|
|
160
|
-
* (ext4, xfs, btrfs, apfs). Creates `~/.letta/` if missing.
|
|
161
|
-
*
|
|
162
|
-
* @param path - the resolved settings path.
|
|
163
|
-
* @param settings - the new contents.
|
|
164
|
-
*/
|
|
165
|
-
export function writeSettingsFile(path: string, settings: LettaCodeSettingsFile): void {
|
|
166
|
-
mkdirSync(dirname(path), { recursive: true });
|
|
167
|
-
const tmp = `${path}.tmp`;
|
|
168
|
-
writeFileSync(tmp, JSON.stringify(settings, null, 2), { encoding: "utf8", mode: 0o600 });
|
|
169
|
-
renameSync(tmp, path);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/* ────────────────────────────────────────────────────────────────────────── */
|
|
173
|
-
/* Upsert */
|
|
174
|
-
/* ────────────────────────────────────────────────────────────────────────── */
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Outcome of a single seed call. Useful for tests and observability.
|
|
178
|
-
*/
|
|
179
|
-
export type SeedOutcome =
|
|
180
|
-
| { kind: "created"; previousToolset: undefined }
|
|
181
|
-
| { kind: "updated"; previousToolset: ToolsetPreference | undefined }
|
|
182
|
-
| { kind: "noop"; previousToolset: ToolsetPreference };
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* Idempotent upsert of `{toolset: "none"}` for a single agent in the
|
|
186
|
-
* global settings file.
|
|
187
|
-
*
|
|
188
|
-
* Matching is by `(agentId, baseUrl)` — same composite key Letta Code
|
|
189
|
-
* uses. If the agent record exists with a different toolset (`"auto"`,
|
|
190
|
-
* `"codex"`, etc.), it's replaced. If it exists already with `"none"`,
|
|
191
|
-
* we no-op (don't churn the file's mtime).
|
|
192
|
-
*
|
|
193
|
-
* @param opts.agentId - the Letta agent id (e.g. `agent-xxx`).
|
|
194
|
-
* @param opts.lettaBaseUrl - the raw `LETTA_BASE_URL` value (so the
|
|
195
|
-
* helper can normalize it the same way Letta Code does). Pass
|
|
196
|
-
* `process.env.LETTA_BASE_URL` from the caller.
|
|
197
|
-
* @param opts.settingsPath - override the settings-file path. Defaults to
|
|
198
|
-
* `~/.letta/settings.json`. Tests inject a tmp path.
|
|
199
|
-
* @param opts.logger - optional pino logger for observability lines.
|
|
200
|
-
* @returns the outcome (created / updated / noop) so the caller can log.
|
|
201
|
-
*/
|
|
202
|
-
export function seedAgentToolsetNone(opts: {
|
|
203
|
-
agentId: string;
|
|
204
|
-
lettaBaseUrl: string | undefined;
|
|
205
|
-
settingsPath?: string;
|
|
206
|
-
logger?: Logger;
|
|
207
|
-
}): SeedOutcome {
|
|
208
|
-
const path = opts.settingsPath ?? resolveGlobalSettingsPath();
|
|
209
|
-
const normalizedBaseUrl = normalizeLettaBaseUrl(opts.lettaBaseUrl);
|
|
210
|
-
const settings = readSettingsFile(path);
|
|
211
|
-
const agents: AgentSettingsEntry[] = Array.isArray(settings.agents) ? [...settings.agents] : [];
|
|
212
|
-
|
|
213
|
-
const matchIdx = agents.findIndex(
|
|
214
|
-
(a) => a.agentId === opts.agentId && (a.baseUrl ?? undefined) === normalizedBaseUrl,
|
|
215
|
-
);
|
|
216
|
-
|
|
217
|
-
let outcome: SeedOutcome;
|
|
218
|
-
|
|
219
|
-
if (matchIdx >= 0) {
|
|
220
|
-
const existing = agents[matchIdx]!;
|
|
221
|
-
const prev = existing.toolset;
|
|
222
|
-
if (prev === "none") {
|
|
223
|
-
outcome = { kind: "noop", previousToolset: "none" };
|
|
224
|
-
opts.logger?.debug({ agentId: opts.agentId, baseUrl: normalizedBaseUrl }, "letta_code_settings_seed_noop");
|
|
225
|
-
return outcome;
|
|
226
|
-
}
|
|
227
|
-
agents[matchIdx] = { ...existing, toolset: "none" };
|
|
228
|
-
outcome = { kind: "updated", previousToolset: prev };
|
|
229
|
-
} else {
|
|
230
|
-
const entry: AgentSettingsEntry = {
|
|
231
|
-
agentId: opts.agentId,
|
|
232
|
-
toolset: "none",
|
|
233
|
-
};
|
|
234
|
-
if (normalizedBaseUrl !== undefined) entry.baseUrl = normalizedBaseUrl;
|
|
235
|
-
agents.push(entry);
|
|
236
|
-
outcome = { kind: "created", previousToolset: undefined };
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
const next: LettaCodeSettingsFile = { ...settings, agents };
|
|
240
|
-
writeSettingsFile(path, next);
|
|
241
|
-
|
|
242
|
-
opts.logger?.info(
|
|
243
|
-
{
|
|
244
|
-
agentId: opts.agentId,
|
|
245
|
-
baseUrl: normalizedBaseUrl,
|
|
246
|
-
outcome: outcome.kind,
|
|
247
|
-
previousToolset: outcome.previousToolset,
|
|
248
|
-
settingsPath: path,
|
|
249
|
-
},
|
|
250
|
-
"letta_code_settings_seed",
|
|
251
|
-
);
|
|
252
|
-
|
|
253
|
-
return outcome;
|
|
254
|
-
}
|