@ai-sdk-letta/server 0.1.0
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/CHANGELOG.md +12 -0
- package/LICENSE +202 -0
- package/NOTICE +9 -0
- package/README.md +37 -0
- package/dist/http.d.ts +33 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +114 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/runtime.d.ts +154 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +438 -0
- package/dist/runtime.js.map +1 -0
- package/dist/serve.d.ts +40 -0
- package/dist/serve.d.ts.map +1 -0
- package/dist/serve.js +128 -0
- package/dist/serve.js.map +1 -0
- package/package.json +68 -0
- package/src/http.ts +108 -0
- package/src/index.ts +9 -0
- package/src/runtime.ts +341 -0
- package/src/serve.ts +128 -0
package/dist/runtime.js
ADDED
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, renameSync, existsSync, openSync, closeSync, fsyncSync } from 'node:fs';
|
|
2
|
+
import { dirname } from 'node:path';
|
|
3
|
+
import { IMAGE_PLACEHOLDER, ImageInputError, MAX_INPUT_CHARACTERS, validateImages, validateResponse } from 'ai-sdk-letta';
|
|
4
|
+
/** A client-visible failure with a fixed code and HTTP status. */
|
|
5
|
+
export class RuntimeFault extends Error {
|
|
6
|
+
code;
|
|
7
|
+
status;
|
|
8
|
+
constructor(code, status = 409) {
|
|
9
|
+
super(code);
|
|
10
|
+
this.code = code;
|
|
11
|
+
this.status = status;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
const uuid = /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i;
|
|
15
|
+
/** Only app-defined, fixed failure codes (e.g. user_denied) are surfaced; never free-form error text. */
|
|
16
|
+
const failureReasons = new Set(['user_denied', 'approval_cancelled', 'tool_denied', 'tool_cancelled', 'tool_timeout', 'tool_failed', 'invalid_arguments', 'interaction_unavailable', 'permission_denied', 'duplicate_or_limit', 'tool_output_limit']);
|
|
17
|
+
export function toolFailureReason(error) {
|
|
18
|
+
let value = error;
|
|
19
|
+
if (typeof value === 'string') {
|
|
20
|
+
try {
|
|
21
|
+
value = JSON.parse(value);
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return {};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
const reason = value && typeof value === 'object' && !Array.isArray(value) ? value.error : undefined;
|
|
28
|
+
return typeof reason === 'string' && failureReasons.has(reason) ? { reason } : {};
|
|
29
|
+
}
|
|
30
|
+
/** Transport observations for reconnects/failed-turn inspection only, never agent input. */
|
|
31
|
+
export function displayRun(run) {
|
|
32
|
+
const parts = [];
|
|
33
|
+
for (const event of run.events) {
|
|
34
|
+
const data = event.data;
|
|
35
|
+
if (event.type === 'text') {
|
|
36
|
+
const last = parts.at(-1);
|
|
37
|
+
if (last?.type === 'text')
|
|
38
|
+
last.text += String(data.text);
|
|
39
|
+
else
|
|
40
|
+
parts.push({ type: 'text', text: String(data.text) });
|
|
41
|
+
}
|
|
42
|
+
else if (event.type === 'tool_started')
|
|
43
|
+
parts.push({ type: 'dynamic-tool', toolName: String(data.name), toolCallId: String(data.toolCallId), state: 'input-available', input: data.input });
|
|
44
|
+
else if (event.type === 'tool_completed' || event.type === 'tool_failed') {
|
|
45
|
+
const index = parts.findIndex(p => p.type === 'dynamic-tool' && p.toolCallId === data.toolCallId);
|
|
46
|
+
const part = parts[index];
|
|
47
|
+
if (part?.type === 'dynamic-tool' && part.state === 'input-available')
|
|
48
|
+
parts[index] = event.type === 'tool_completed'
|
|
49
|
+
? { ...part, state: 'output-available', output: data.output }
|
|
50
|
+
: { ...part, state: 'output-error', errorText: typeof data.reason === 'string' ? JSON.stringify({ error: data.reason }) : String(data.code) };
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (run.status !== 'completed' && run.status !== 'running')
|
|
54
|
+
for (let i = 0; i < parts.length; i++) {
|
|
55
|
+
const part = parts[i];
|
|
56
|
+
if (part.type === 'dynamic-tool' && part.state === 'input-available')
|
|
57
|
+
parts[i] = { ...part, state: 'output-error', errorText: `Turn ${run.status}; execution not confirmed.` };
|
|
58
|
+
}
|
|
59
|
+
const metadata = run.startedAt ? { metadata: { createdAt: run.startedAt } } : {};
|
|
60
|
+
// Runtime state never stores image bytes; failed/reconnecting runs show a placeholder.
|
|
61
|
+
const user = [...(run.input.trim() ? [{ type: 'text', text: run.input }] : []), ...(run.images ?? []).map(() => ({ type: 'text', text: IMAGE_PLACEHOLDER }))];
|
|
62
|
+
return [{ id: `${run.id}-user`, role: 'user', parts: user, ...metadata }, { id: `${run.id}-assistant`, role: 'assistant', parts }];
|
|
63
|
+
}
|
|
64
|
+
const sameImages = (a = [], b = []) => a.length === b.length && a.every((image, index) => image.sha256 === b[index].sha256);
|
|
65
|
+
/**
|
|
66
|
+
* Single-owner, single-turn thread service over one agent.
|
|
67
|
+
*
|
|
68
|
+
* Runs are recorded durably before delivery; a run that was in flight when the
|
|
69
|
+
* process stopped is marked `interrupted` and blocks further turns on that
|
|
70
|
+
* thread (uncertain delivery is never replayed). Human answers are validated
|
|
71
|
+
* and accepted exactly once.
|
|
72
|
+
*/
|
|
73
|
+
export class ThreadRuntime {
|
|
74
|
+
host;
|
|
75
|
+
filename;
|
|
76
|
+
owner;
|
|
77
|
+
deadlineMs;
|
|
78
|
+
humanWaitMs;
|
|
79
|
+
state;
|
|
80
|
+
locked = false;
|
|
81
|
+
current;
|
|
82
|
+
active;
|
|
83
|
+
pending;
|
|
84
|
+
listeners = new Map();
|
|
85
|
+
constructor(host, filename, owner, deadlineMs = 180_000, humanWaitMs = 4 * 60_000) {
|
|
86
|
+
this.host = host;
|
|
87
|
+
this.filename = filename;
|
|
88
|
+
this.owner = owner;
|
|
89
|
+
this.deadlineMs = deadlineMs;
|
|
90
|
+
this.humanWaitMs = humanWaitMs;
|
|
91
|
+
this.state = existsSync(filename) ? JSON.parse(readFileSync(filename, 'utf8')) : { version: 1, threads: [], runs: [] };
|
|
92
|
+
if (this.state.version !== 1 || !Array.isArray(this.state.threads) || !Array.isArray(this.state.runs))
|
|
93
|
+
throw new Error('Invalid runtime state');
|
|
94
|
+
for (const thread of this.state.threads)
|
|
95
|
+
thread.archived ??= false;
|
|
96
|
+
for (const run of this.state.runs)
|
|
97
|
+
if (run.status === 'running') {
|
|
98
|
+
run.status = 'interrupted';
|
|
99
|
+
run.events.push({ sequence: run.events.length + 1, type: 'failed', data: { code: 'delivery_uncertain' } });
|
|
100
|
+
}
|
|
101
|
+
this.save();
|
|
102
|
+
}
|
|
103
|
+
save() {
|
|
104
|
+
// A leftover temporary file is an uncertain write, not permission to overwrite it.
|
|
105
|
+
const fd = openSync(`${this.filename}.tmp`, 'wx', 0o600);
|
|
106
|
+
try {
|
|
107
|
+
writeFileSync(fd, JSON.stringify(this.state));
|
|
108
|
+
fsyncSync(fd);
|
|
109
|
+
}
|
|
110
|
+
finally {
|
|
111
|
+
closeSync(fd);
|
|
112
|
+
}
|
|
113
|
+
renameSync(`${this.filename}.tmp`, this.filename);
|
|
114
|
+
const directory = openSync(dirname(this.filename), 'r');
|
|
115
|
+
try {
|
|
116
|
+
fsyncSync(directory);
|
|
117
|
+
}
|
|
118
|
+
finally {
|
|
119
|
+
closeSync(directory);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
authorize(owner) { if (owner !== this.owner)
|
|
123
|
+
throw new RuntimeFault('forbidden', 403); }
|
|
124
|
+
thread(owner, id) {
|
|
125
|
+
this.authorize(owner);
|
|
126
|
+
const thread = this.state.threads.find(t => t.id === id && t.owner === owner);
|
|
127
|
+
if (!thread)
|
|
128
|
+
throw new RuntimeFault('not_found', 404);
|
|
129
|
+
if (thread.state !== 'ready')
|
|
130
|
+
throw new RuntimeFault('creation_uncertain');
|
|
131
|
+
return thread;
|
|
132
|
+
}
|
|
133
|
+
run(owner, id) {
|
|
134
|
+
this.authorize(owner);
|
|
135
|
+
const run = this.state.runs.find(r => r.id === id);
|
|
136
|
+
if (!run)
|
|
137
|
+
throw new RuntimeFault('not_found', 404);
|
|
138
|
+
this.thread(owner, run.threadId);
|
|
139
|
+
return run;
|
|
140
|
+
}
|
|
141
|
+
async exclusive(fn) {
|
|
142
|
+
if (this.locked || this.active)
|
|
143
|
+
throw new RuntimeFault('runtime_busy');
|
|
144
|
+
this.locked = true;
|
|
145
|
+
try {
|
|
146
|
+
return await fn();
|
|
147
|
+
}
|
|
148
|
+
finally {
|
|
149
|
+
this.locked = false;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
async open(thread) {
|
|
153
|
+
if (this.current && this.current.conversationId === thread.conversationId)
|
|
154
|
+
return this.current;
|
|
155
|
+
await this.host.close();
|
|
156
|
+
this.current = undefined;
|
|
157
|
+
const session = await this.host.open(thread.conversationId ? { conversationId: thread.conversationId } : { newTitle: thread.title });
|
|
158
|
+
const identity = this.state.threads.find(t => t.agentId)?.agentId;
|
|
159
|
+
if (identity && session.agentId !== identity) {
|
|
160
|
+
await this.host.close();
|
|
161
|
+
throw new RuntimeFault('identity_mismatch');
|
|
162
|
+
}
|
|
163
|
+
this.current = session;
|
|
164
|
+
return session;
|
|
165
|
+
}
|
|
166
|
+
/** Display metadata only; timestamps are omitted for legacy threads that never recorded them. */
|
|
167
|
+
summary({ id, title, state, archived, createdAt, lastActivityAt }) {
|
|
168
|
+
return { id, title, state, archived, ...(createdAt ? { createdAt } : {}), ...(lastActivityAt ? { lastActivityAt } : {}) };
|
|
169
|
+
}
|
|
170
|
+
list(owner) {
|
|
171
|
+
this.authorize(owner);
|
|
172
|
+
return this.state.threads.filter(t => t.owner === owner).map(t => this.summary(t));
|
|
173
|
+
}
|
|
174
|
+
/** Local display metadata only: never opens a session or edits backend history. */
|
|
175
|
+
updateMetadata(owner, id, input) {
|
|
176
|
+
const thread = this.thread(owner, id);
|
|
177
|
+
if (!input || typeof input !== 'object' || Array.isArray(input))
|
|
178
|
+
throw new RuntimeFault('invalid_input', 400);
|
|
179
|
+
const fields = Object.keys(input);
|
|
180
|
+
if (!fields.length || fields.some(key => key !== 'title' && key !== 'archived'))
|
|
181
|
+
throw new RuntimeFault('invalid_input', 400);
|
|
182
|
+
const patch = input;
|
|
183
|
+
let title = thread.title;
|
|
184
|
+
if (fields.includes('title')) {
|
|
185
|
+
// Reject terminal controls and invisible formatting/bidi controls before trimming.
|
|
186
|
+
if (typeof patch.title !== 'string' || /[\p{Cc}\p{Cf}\p{Zl}\p{Zp}]/u.test(patch.title))
|
|
187
|
+
throw new RuntimeFault('invalid_input', 400);
|
|
188
|
+
title = patch.title.trim();
|
|
189
|
+
if (!title || title.length > 120)
|
|
190
|
+
throw new RuntimeFault('invalid_input', 400);
|
|
191
|
+
}
|
|
192
|
+
if (fields.includes('archived') && typeof patch.archived !== 'boolean')
|
|
193
|
+
throw new RuntimeFault('invalid_input', 400);
|
|
194
|
+
// locked covers session opening before start() has installed its active run.
|
|
195
|
+
if (patch.archived === true && (this.locked || this.active?.run.threadId === id))
|
|
196
|
+
throw new RuntimeFault('runtime_busy');
|
|
197
|
+
thread.title = title;
|
|
198
|
+
if (typeof patch.archived === 'boolean')
|
|
199
|
+
thread.archived = patch.archived;
|
|
200
|
+
this.save();
|
|
201
|
+
return this.summary(thread);
|
|
202
|
+
}
|
|
203
|
+
async create(owner, id, title) {
|
|
204
|
+
this.authorize(owner);
|
|
205
|
+
if (!uuid.test(id) || typeof title !== 'string' || !title.trim() || title.length > 120)
|
|
206
|
+
throw new RuntimeFault('invalid_input', 400);
|
|
207
|
+
const previous = this.state.threads.find(t => t.id === id);
|
|
208
|
+
if (previous) {
|
|
209
|
+
if (previous.owner !== owner || previous.title !== title)
|
|
210
|
+
throw new RuntimeFault('id_conflict');
|
|
211
|
+
this.thread(owner, id);
|
|
212
|
+
return { id, title };
|
|
213
|
+
}
|
|
214
|
+
if (this.state.threads.length >= 200)
|
|
215
|
+
throw new RuntimeFault('capacity_reached');
|
|
216
|
+
return this.exclusive(async () => {
|
|
217
|
+
const now = new Date().toISOString();
|
|
218
|
+
const thread = { id, owner, title, archived: false, state: 'creating', createdAt: now, lastActivityAt: now };
|
|
219
|
+
this.state.threads.push(thread);
|
|
220
|
+
this.save();
|
|
221
|
+
const session = await this.open(thread);
|
|
222
|
+
thread.agentId = session.agentId;
|
|
223
|
+
thread.conversationId = session.conversationId;
|
|
224
|
+
thread.state = 'ready';
|
|
225
|
+
this.save();
|
|
226
|
+
return { id, title };
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
async history(owner, id) {
|
|
230
|
+
const thread = this.thread(owner, id);
|
|
231
|
+
return this.exclusive(async () => {
|
|
232
|
+
// Refresh through backend history, not a display transcript replay into the agent.
|
|
233
|
+
await this.host.close();
|
|
234
|
+
this.current = undefined;
|
|
235
|
+
const session = await this.open(thread);
|
|
236
|
+
return { messages: session.history.filter(m => m.id !== 'session-status'), lastRunId: this.state.runs.filter(r => r.threadId === id).at(-1)?.id ?? null };
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
async view(owner, id) {
|
|
240
|
+
this.thread(owner, id);
|
|
241
|
+
const latest = this.state.runs.filter(r => r.threadId === id).at(-1);
|
|
242
|
+
if (this.active?.run.threadId === id && this.current)
|
|
243
|
+
return {
|
|
244
|
+
messages: this.current.history.filter(m => m.id !== 'session-status'),
|
|
245
|
+
lastRunId: latest?.id ?? null,
|
|
246
|
+
live: { id: this.active.run.id, input: this.active.run.input, ...(this.active.run.images?.length ? { images: this.active.run.images.length } : {}) },
|
|
247
|
+
status: 'running',
|
|
248
|
+
};
|
|
249
|
+
if (latest && !['running', 'completed'].includes(latest.status))
|
|
250
|
+
return {
|
|
251
|
+
messages: this.state.runs.filter(r => r.threadId === id).flatMap(displayRun),
|
|
252
|
+
lastRunId: latest.id, live: null, status: latest.status, source: 'transport-observations',
|
|
253
|
+
};
|
|
254
|
+
return { ...await this.history(owner, id), live: null, status: latest?.status ?? null, source: 'backend-history' };
|
|
255
|
+
}
|
|
256
|
+
emit(run, type, data) {
|
|
257
|
+
const event = { sequence: run.events.length + 1, type, data };
|
|
258
|
+
run.events.push(event);
|
|
259
|
+
this.save();
|
|
260
|
+
for (const listener of this.listeners.get(run.id) ?? [])
|
|
261
|
+
listener(event);
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Start one turn. Text, images or both; images are validated (type by
|
|
265
|
+
* content, size, count, total) and fail with a fixed `image_*` code.
|
|
266
|
+
* Only image metadata (type, size, SHA-256) is recorded in runtime state.
|
|
267
|
+
*/
|
|
268
|
+
async start(owner, input) {
|
|
269
|
+
this.authorize(owner);
|
|
270
|
+
if (!input || typeof input !== 'object' || !uuid.test(input.id) || typeof input.text !== 'string' || input.text.length > MAX_INPUT_CHARACTERS || (input.parentRunId !== null && !uuid.test(input.parentRunId)) || (input.images !== undefined && !Array.isArray(input.images)))
|
|
271
|
+
throw new RuntimeFault('invalid_input', 400);
|
|
272
|
+
let images = [];
|
|
273
|
+
try {
|
|
274
|
+
images = validateImages(input.images ?? []);
|
|
275
|
+
}
|
|
276
|
+
catch (error) {
|
|
277
|
+
throw error instanceof ImageInputError ? new RuntimeFault(error.code, error.code === 'image_too_large' || error.code === 'images_too_large' ? 413 : 400) : error;
|
|
278
|
+
}
|
|
279
|
+
if (!input.text.trim() && !images.length)
|
|
280
|
+
throw new RuntimeFault('invalid_input', 400);
|
|
281
|
+
const imageMetadata = images.map(({ mediaType, bytes, sha256 }) => ({ mediaType, bytes, sha256 }));
|
|
282
|
+
const thread = this.thread(owner, input.threadId);
|
|
283
|
+
const previous = this.state.runs.find(r => r.id === input.id);
|
|
284
|
+
if (previous) {
|
|
285
|
+
if (previous.threadId !== input.threadId || previous.input !== input.text || !sameImages(previous.images, imageMetadata) || previous.parentRunId !== input.parentRunId)
|
|
286
|
+
throw new RuntimeFault('id_conflict');
|
|
287
|
+
return { id: previous.id, status: previous.status };
|
|
288
|
+
}
|
|
289
|
+
if (thread.archived)
|
|
290
|
+
throw new RuntimeFault('thread_archived');
|
|
291
|
+
const latest = this.state.runs.filter(r => r.threadId === thread.id).at(-1);
|
|
292
|
+
if (input.parentRunId !== (latest?.id ?? null))
|
|
293
|
+
throw new RuntimeFault('history_conflict');
|
|
294
|
+
if (latest && latest.status !== 'completed')
|
|
295
|
+
throw new RuntimeFault('delivery_uncertain');
|
|
296
|
+
if (this.state.runs.length >= 200)
|
|
297
|
+
throw new RuntimeFault('capacity_reached');
|
|
298
|
+
return this.exclusive(async () => {
|
|
299
|
+
const session = await this.open(thread);
|
|
300
|
+
const startedAt = new Date().toISOString();
|
|
301
|
+
const run = { id: input.id, threadId: input.threadId, input: input.text, ...(imageMetadata.length ? { images: imageMetadata } : {}), parentRunId: input.parentRunId, status: 'running', events: [], startedAt };
|
|
302
|
+
thread.lastActivityAt = startedAt;
|
|
303
|
+
this.state.runs.push(run);
|
|
304
|
+
this.save();
|
|
305
|
+
const control = new AbortController();
|
|
306
|
+
this.active = { run, control };
|
|
307
|
+
// Exactly the new turn: text (if any) followed by the images, in the order given.
|
|
308
|
+
const content = images.length
|
|
309
|
+
? [...(input.text.trim() ? [{ type: 'text', text: input.text }] : []), ...images.map(image => ({ type: 'image', image: image.base64, mediaType: image.mediaType }))]
|
|
310
|
+
: input.text;
|
|
311
|
+
void this.drive(session, run, control, content);
|
|
312
|
+
return { id: run.id, status: run.status };
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
async drive(session, run, control, content) {
|
|
316
|
+
let timedOut = false;
|
|
317
|
+
const expire = () => { timedOut = true; control.abort(); };
|
|
318
|
+
let remaining = this.deadlineMs;
|
|
319
|
+
// The installed harness caps external tools at five minutes. Finish human
|
|
320
|
+
// waits explicitly before that limit, rather than accepting a detached result.
|
|
321
|
+
let remainingWait = this.humanWaitMs;
|
|
322
|
+
let resumedAt = Date.now();
|
|
323
|
+
let timer = setTimeout(expire, remaining);
|
|
324
|
+
// Human reading time does not consume inference time, but the whole turn
|
|
325
|
+
// remains bounded even if the browser is abandoned or prompts repeat.
|
|
326
|
+
const hardTimer = setTimeout(expire, this.deadlineMs + this.humanWaitMs);
|
|
327
|
+
let disconnect = () => { };
|
|
328
|
+
try {
|
|
329
|
+
disconnect = session.agent.interactions.connect((request, signal) => new Promise((resolve, reject) => {
|
|
330
|
+
clearTimeout(timer);
|
|
331
|
+
remaining = Math.max(1, remaining - (Date.now() - resumedAt));
|
|
332
|
+
const waitingAt = Date.now();
|
|
333
|
+
timer = setTimeout(expire, Math.max(1, remainingWait));
|
|
334
|
+
const resume = () => {
|
|
335
|
+
clearTimeout(timer);
|
|
336
|
+
remainingWait -= Date.now() - waitingAt;
|
|
337
|
+
resumedAt = Date.now();
|
|
338
|
+
timer = setTimeout(expire, remaining);
|
|
339
|
+
};
|
|
340
|
+
const abort = () => {
|
|
341
|
+
if (this.pending?.request.id === request.id) {
|
|
342
|
+
this.pending = undefined;
|
|
343
|
+
this.emit(run, 'interaction_ended', { id: request.id, code: timedOut ? 'timed_out' : 'cancelled' });
|
|
344
|
+
resume();
|
|
345
|
+
}
|
|
346
|
+
reject(new RuntimeFault('interaction_cancelled'));
|
|
347
|
+
};
|
|
348
|
+
signal.addEventListener('abort', abort, { once: true });
|
|
349
|
+
this.pending = { runId: run.id, request, resolve: value => {
|
|
350
|
+
signal.removeEventListener('abort', abort);
|
|
351
|
+
if (this.pending?.request.id === request.id)
|
|
352
|
+
this.pending = undefined;
|
|
353
|
+
resume();
|
|
354
|
+
resolve(value);
|
|
355
|
+
} };
|
|
356
|
+
if (signal.aborted) {
|
|
357
|
+
abort();
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
this.emit(run, 'interaction', request);
|
|
361
|
+
}));
|
|
362
|
+
this.emit(run, 'started', { threadId: run.threadId });
|
|
363
|
+
const result = await session.agent.stream(typeof content === 'string'
|
|
364
|
+
? { prompt: content, abortSignal: control.signal }
|
|
365
|
+
: { messages: [...session.agent.transcript, { role: 'user', content }], abortSignal: control.signal });
|
|
366
|
+
for await (const part of result.fullStream) {
|
|
367
|
+
if (part.type === 'text-delta')
|
|
368
|
+
this.emit(run, 'text', { text: part.text });
|
|
369
|
+
else if (part.type === 'tool-call')
|
|
370
|
+
this.emit(run, 'tool_started', { toolCallId: part.toolCallId, name: part.toolName, input: part.input, execution: 'external' });
|
|
371
|
+
else if (part.type === 'tool-result')
|
|
372
|
+
this.emit(run, 'tool_completed', { toolCallId: part.toolCallId, name: part.toolName, output: part.output, execution: 'external' });
|
|
373
|
+
else if (part.type === 'tool-error')
|
|
374
|
+
this.emit(run, 'tool_failed', { toolCallId: part.toolCallId, name: part.toolName, code: 'tool_failed', ...toolFailureReason(part.error), execution: 'external' });
|
|
375
|
+
else if (part.type === 'error' || part.type === 'abort')
|
|
376
|
+
throw new RuntimeFault('runtime_failed');
|
|
377
|
+
}
|
|
378
|
+
if (this.pending?.runId === run.id)
|
|
379
|
+
throw new RuntimeFault('interaction_incomplete');
|
|
380
|
+
if (control.signal.aborted || await result.finishReason !== 'stop')
|
|
381
|
+
throw new RuntimeFault('runtime_failed');
|
|
382
|
+
run.status = 'completed';
|
|
383
|
+
this.emit(run, 'completed', {});
|
|
384
|
+
}
|
|
385
|
+
catch (error) {
|
|
386
|
+
run.status = control.signal.aborted ? 'cancelled' : 'failed';
|
|
387
|
+
const code = timedOut ? 'timed_out' : run.status === 'cancelled' ? 'cancelled' : error instanceof RuntimeFault && error.message === 'interaction_incomplete' ? 'interaction_incomplete' : 'runtime_failed';
|
|
388
|
+
if (this.pending?.runId === run.id)
|
|
389
|
+
this.emit(run, 'interaction_ended', { id: this.pending.request.id, code });
|
|
390
|
+
this.emit(run, 'failed', { code });
|
|
391
|
+
}
|
|
392
|
+
finally {
|
|
393
|
+
// Keep the pre-run display snapshot current for browser reconnects without
|
|
394
|
+
// closing a running SDK session or replaying any transcript into the agent.
|
|
395
|
+
session.history = [...session.history, ...displayRun(run)];
|
|
396
|
+
this.pending = undefined;
|
|
397
|
+
disconnect();
|
|
398
|
+
clearTimeout(timer);
|
|
399
|
+
clearTimeout(hardTimer);
|
|
400
|
+
this.active = undefined;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
events(owner, id, after) {
|
|
404
|
+
const run = this.run(owner, id);
|
|
405
|
+
if (!Number.isSafeInteger(after) || after < 0 || after > run.events.length)
|
|
406
|
+
throw new RuntimeFault('invalid_cursor', 400);
|
|
407
|
+
return { events: run.events.slice(after), status: run.status };
|
|
408
|
+
}
|
|
409
|
+
subscribe(id, listener) {
|
|
410
|
+
const listeners = this.listeners.get(id) ?? new Set();
|
|
411
|
+
listeners.add(listener);
|
|
412
|
+
this.listeners.set(id, listeners);
|
|
413
|
+
return () => { listeners.delete(listener); if (!listeners.size)
|
|
414
|
+
this.listeners.delete(id); };
|
|
415
|
+
}
|
|
416
|
+
answer(owner, runId, response) {
|
|
417
|
+
const run = this.run(owner, runId);
|
|
418
|
+
const pending = this.pending;
|
|
419
|
+
if (!pending || pending.runId !== runId || run.status !== 'running')
|
|
420
|
+
throw new RuntimeFault('stale_interaction');
|
|
421
|
+
let value;
|
|
422
|
+
try {
|
|
423
|
+
value = validateResponse(pending.request, response);
|
|
424
|
+
}
|
|
425
|
+
catch {
|
|
426
|
+
throw new RuntimeFault('invalid_response', 400);
|
|
427
|
+
}
|
|
428
|
+
this.emit(run, 'interaction_resolved', { id: value.id });
|
|
429
|
+
pending.resolve(value);
|
|
430
|
+
}
|
|
431
|
+
cancel(owner, id) {
|
|
432
|
+
this.run(owner, id);
|
|
433
|
+
if (this.active?.run.id === id)
|
|
434
|
+
this.active.control.abort();
|
|
435
|
+
}
|
|
436
|
+
async close() { this.active?.control.abort(); await this.host.close(); }
|
|
437
|
+
}
|
|
438
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"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"}
|
package/dist/serve.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { ToolSet } from 'ai';
|
|
2
|
+
import { type AgentDefinition } from 'ai-sdk-letta';
|
|
3
|
+
/** Default GUI port (the token API uses the next one). */
|
|
4
|
+
export declare const DEFAULT_PORT = 4400;
|
|
5
|
+
/** Options shared by {@link startGuiServer} and {@link startApiServer}. */
|
|
6
|
+
export interface ServeOptions {
|
|
7
|
+
/** Loopback port. `0` picks a free port. @default 4400 */
|
|
8
|
+
port?: number;
|
|
9
|
+
/** State root; see `resolveStateDirectory`. */
|
|
10
|
+
stateDirectory?: string;
|
|
11
|
+
/** Log sink for startup and shutdown lines. @default console.log */
|
|
12
|
+
log?: (line: string) => void;
|
|
13
|
+
}
|
|
14
|
+
/** A running server. */
|
|
15
|
+
export interface RunningServer {
|
|
16
|
+
url: string;
|
|
17
|
+
port: number;
|
|
18
|
+
/** Stop accepting requests, close the agent, then release locks. Idempotent. */
|
|
19
|
+
close(): Promise<void>;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Serve the assistant-ui web app for one agent on 127.0.0.1.
|
|
23
|
+
*
|
|
24
|
+
* No agent session is opened until the browser creates or opens a thread.
|
|
25
|
+
* @param assets Directory of the built web app (for example `@ai-sdk-letta/web`'s `dist`).
|
|
26
|
+
*/
|
|
27
|
+
export declare function startGuiServer<TOOLS extends ToolSet>(definition: AgentDefinition<TOOLS>, assets: string, options?: ServeOptions): Promise<RunningServer>;
|
|
28
|
+
/**
|
|
29
|
+
* Serve the token-authenticated server-to-server API for one agent on 127.0.0.1.
|
|
30
|
+
* The token is created once (0600) in the state directory and printed by path only.
|
|
31
|
+
*/
|
|
32
|
+
export declare function startApiServer<TOOLS extends ToolSet>(definition: AgentDefinition<TOOLS>, options?: ServeOptions & {
|
|
33
|
+
owner?: string;
|
|
34
|
+
}): Promise<RunningServer & {
|
|
35
|
+
tokenPath: string;
|
|
36
|
+
owner: string;
|
|
37
|
+
}>;
|
|
38
|
+
/** Close `server` on SIGINT/SIGTERM and set a non-zero exit code if shutdown fails. */
|
|
39
|
+
export declare function closeOnSignals(server: Pick<RunningServer, 'close'>): void;
|
|
40
|
+
//# sourceMappingURL=serve.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../src/serve.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,EAAuD,KAAK,eAAe,EAAqB,MAAM,cAAc,CAAC;AAI5H,0DAA0D;AAC1D,eAAO,MAAM,YAAY,OAAO,CAAC;AAEjC,2EAA2E;AAC3E,MAAM,WAAW,YAAY;IAC3B,0DAA0D;IAC1D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,+CAA+C;IAC/C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oEAAoE;IACpE,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B;AAED,wBAAwB;AACxB,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,gFAAgF;IAChF,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AA4CD;;;;;GAKG;AACH,wBAAsB,cAAc,CAAC,KAAK,SAAS,OAAO,EAAE,UAAU,EAAE,eAAe,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,aAAa,CAAC,CAgBlK;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAAC,KAAK,SAAS,OAAO,EAAE,UAAU,EAAE,eAAe,CAAC,KAAK,CAAC,EAAE,OAAO,GAAE,YAAY,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,OAAO,CAAC,aAAa,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAoB9M;AAED,uFAAuF;AACvF,wBAAgB,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,aAAa,EAAE,OAAO,CAAC,GAAG,IAAI,CAIzE"}
|
package/dist/serve.js
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { closeSync, existsSync, mkdirSync, openSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { randomBytes } from 'node:crypto';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { createLettaAgent, resolveStateDirectory, statePaths } from 'ai-sdk-letta';
|
|
5
|
+
import { ThreadRuntime } from './runtime.js';
|
|
6
|
+
import { guiApp, tokenApiApp } from './http.js';
|
|
7
|
+
/** Default GUI port (the token API uses the next one). */
|
|
8
|
+
export const DEFAULT_PORT = 4400;
|
|
9
|
+
function host(definition, stateDirectory) {
|
|
10
|
+
let runtime;
|
|
11
|
+
return {
|
|
12
|
+
open: async (options) => {
|
|
13
|
+
runtime = await createLettaAgent(definition, { ...options, stateDirectory, foregroundExternalTools: true });
|
|
14
|
+
const { agent } = runtime;
|
|
15
|
+
if (!agent.lettaAgentId || !agent.presentation)
|
|
16
|
+
throw new Error('Runtime identity unavailable');
|
|
17
|
+
return { agent, agentId: agent.lettaAgentId, conversationId: agent.presentation.conversationId, history: agent.presentation.initialMessages };
|
|
18
|
+
},
|
|
19
|
+
close: async () => { const current = runtime; runtime = undefined; await current?.close(); },
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function serviceLock(directory) {
|
|
23
|
+
mkdirSync(directory, { recursive: true, mode: 0o700 });
|
|
24
|
+
const lock = join(directory, 'service.lock');
|
|
25
|
+
let fd;
|
|
26
|
+
try {
|
|
27
|
+
fd = openSync(lock, 'wx', 0o600);
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
throw new Error(`Server already running or stale lock: ${lock}. Verify the recorded PID is not running before removing it.`);
|
|
31
|
+
}
|
|
32
|
+
writeFileSync(fd, String(process.pid));
|
|
33
|
+
closeSync(fd);
|
|
34
|
+
return () => unlinkSync(lock);
|
|
35
|
+
}
|
|
36
|
+
async function listen(server, port) {
|
|
37
|
+
await new Promise((resolve, reject) => { server.once('error', reject); server.once('listening', () => { server.off('error', reject); resolve(); }); });
|
|
38
|
+
const address = server.address();
|
|
39
|
+
if (!address || typeof address === 'string')
|
|
40
|
+
throw new Error('Listener unavailable');
|
|
41
|
+
return address.port || port;
|
|
42
|
+
}
|
|
43
|
+
function lifecycle(server, runtime, unlock, log, label) {
|
|
44
|
+
let closing;
|
|
45
|
+
return () => closing ??= (async () => {
|
|
46
|
+
// SDK shutdown can await unref'ed resources; keep Node alive until locks release.
|
|
47
|
+
const keepAlive = setInterval(() => { }, 1000);
|
|
48
|
+
server.close();
|
|
49
|
+
server.closeAllConnections?.();
|
|
50
|
+
try {
|
|
51
|
+
await runtime.close();
|
|
52
|
+
unlock();
|
|
53
|
+
log(`${label} stopped cleanly.`);
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
log(`${label} shutdown incomplete; inspect the recorded locks before restarting.`);
|
|
57
|
+
throw error;
|
|
58
|
+
}
|
|
59
|
+
finally {
|
|
60
|
+
clearInterval(keepAlive);
|
|
61
|
+
}
|
|
62
|
+
})();
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Serve the assistant-ui web app for one agent on 127.0.0.1.
|
|
66
|
+
*
|
|
67
|
+
* No agent session is opened until the browser creates or opens a thread.
|
|
68
|
+
* @param assets Directory of the built web app (for example `@ai-sdk-letta/web`'s `dist`).
|
|
69
|
+
*/
|
|
70
|
+
export async function startGuiServer(definition, assets, options = {}) {
|
|
71
|
+
const log = options.log ?? console.log;
|
|
72
|
+
const stateDirectory = resolveStateDirectory(options.stateDirectory);
|
|
73
|
+
const directory = join(statePaths(stateDirectory).server(definition.id), 'gui');
|
|
74
|
+
if (!existsSync(join(assets, 'index.html')))
|
|
75
|
+
throw new Error(`Web assets not found in ${assets}; build @ai-sdk-letta/web first`);
|
|
76
|
+
const unlock = serviceLock(directory);
|
|
77
|
+
try {
|
|
78
|
+
const port = options.port ?? DEFAULT_PORT;
|
|
79
|
+
const owner = 'local-gui';
|
|
80
|
+
const runtime = new ThreadRuntime(host(definition, stateDirectory), join(directory, 'state.json'), owner);
|
|
81
|
+
const server = guiApp(runtime, owner, port, assets, { id: definition.id, name: definition.name, approvalTools: Object.keys(definition.permissions).filter(name => definition.permissions[name] === 'ask') }).listen(port, '127.0.0.1');
|
|
82
|
+
const bound = await listen(server, port);
|
|
83
|
+
const url = `http://127.0.0.1:${bound}`;
|
|
84
|
+
log(`${definition.name} GUI: ${url}\nDefinition: ${definition.id} · state: ${stateDirectory}\nPID ${process.pid}. Stop with Ctrl-C or SIGTERM.`);
|
|
85
|
+
return { url, port: bound, close: lifecycle(server, runtime, unlock, log, 'GUI') };
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
unlock();
|
|
89
|
+
throw error;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Serve the token-authenticated server-to-server API for one agent on 127.0.0.1.
|
|
94
|
+
* The token is created once (0600) in the state directory and printed by path only.
|
|
95
|
+
*/
|
|
96
|
+
export async function startApiServer(definition, options = {}) {
|
|
97
|
+
const log = options.log ?? console.log;
|
|
98
|
+
const stateDirectory = resolveStateDirectory(options.stateDirectory);
|
|
99
|
+
const directory = join(statePaths(stateDirectory).server(definition.id), 'api');
|
|
100
|
+
const unlock = serviceLock(directory);
|
|
101
|
+
try {
|
|
102
|
+
const tokenPath = join(directory, 'token');
|
|
103
|
+
if (!existsSync(tokenPath))
|
|
104
|
+
writeFileSync(tokenPath, randomBytes(32).toString('hex'), { mode: 0o600, flag: 'wx' });
|
|
105
|
+
const token = readFileSync(tokenPath, 'utf8').trim();
|
|
106
|
+
const owner = options.owner ?? 'local-api';
|
|
107
|
+
const port = options.port ?? DEFAULT_PORT + 1;
|
|
108
|
+
const runtime = new ThreadRuntime(host(definition, stateDirectory), join(directory, 'state.json'), owner);
|
|
109
|
+
let stop;
|
|
110
|
+
const server = tokenApiApp(runtime, token, owner, port, () => stop()).listen(port, '127.0.0.1');
|
|
111
|
+
const bound = await listen(server, port);
|
|
112
|
+
stop = lifecycle(server, runtime, unlock, log, 'API');
|
|
113
|
+
const url = `http://127.0.0.1:${bound}`;
|
|
114
|
+
log(`${definition.name} API: ${url} (bearer token required)\nDefinition: ${definition.id} · owner: ${owner} · token file: ${tokenPath}`);
|
|
115
|
+
return { url, port: bound, tokenPath, owner, close: stop };
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
unlock();
|
|
119
|
+
throw error;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/** Close `server` on SIGINT/SIGTERM and set a non-zero exit code if shutdown fails. */
|
|
123
|
+
export function closeOnSignals(server) {
|
|
124
|
+
const stop = () => { server.close().catch(() => { process.exitCode = 1; }); };
|
|
125
|
+
process.once('SIGINT', stop);
|
|
126
|
+
process.once('SIGTERM', stop);
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=serve.js.map
|