@zenera/server 0.0.0-stage → 1.2.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/README.md +245 -2
- package/dist/agui.d.ts +29 -0
- package/dist/agui.js +333 -0
- package/dist/auth.d.ts +16 -0
- package/dist/auth.js +79 -0
- package/dist/config.d.ts +71 -0
- package/dist/config.js +44 -0
- package/dist/history.d.ts +8 -0
- package/dist/history.js +73 -0
- package/dist/http.d.ts +9 -0
- package/dist/http.js +26 -0
- package/dist/identity.d.ts +18 -0
- package/dist/identity.js +55 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +20 -0
- package/dist/layout.d.ts +15 -0
- package/dist/layout.js +47 -0
- package/dist/localFileCors.d.ts +10 -0
- package/dist/localFileCors.js +34 -0
- package/dist/memory.d.ts +81 -0
- package/dist/memory.js +471 -0
- package/dist/plugins.d.ts +5 -0
- package/dist/plugins.js +29 -0
- package/dist/projectEnv.d.ts +3 -0
- package/dist/projectEnv.js +37 -0
- package/dist/runLog.d.ts +27 -0
- package/dist/runLog.js +153 -0
- package/dist/runRecords.d.ts +38 -0
- package/dist/runRecords.js +154 -0
- package/dist/runs.d.ts +12 -0
- package/dist/runs.js +376 -0
- package/dist/server.d.ts +28 -0
- package/dist/server.js +105 -0
- package/dist/sessions.d.ts +13 -0
- package/dist/sessions.js +61 -0
- package/dist/state.d.ts +24 -0
- package/dist/state.js +55 -0
- package/dist/status.d.ts +56 -0
- package/dist/status.js +127 -0
- package/dist/store.d.ts +52 -0
- package/dist/store.js +203 -0
- package/dist/token.d.ts +14 -0
- package/dist/token.js +30 -0
- package/dist/trace.d.ts +84 -0
- package/dist/trace.js +389 -0
- package/package.json +56 -5
package/dist/trace.js
ADDED
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
// A recorded run, step by step: the trajectory saved with each engine run, flattened (fork branches
|
|
2
|
+
// nested under their join) and listed without payloads; one step's payloads are read on request.
|
|
3
|
+
// GET /:tid/runs/:runId/trace - the steps of this turn (scope=turn) or the session
|
|
4
|
+
// GET /:tid/runs/:runId/trace/:step - one step in full; the recorded model request, which
|
|
5
|
+
// can be the whole conversation, only with ?part=request
|
|
6
|
+
// Steps are addressed by their index in the whole session, flattened: node ids are not unique
|
|
7
|
+
// across fork branches, and an index from one scope stays valid in the other. Each step also
|
|
8
|
+
// carries its `zen inspect` id (n1, n2, ...), which `zen inspect node|ask --dir <run>` take.
|
|
9
|
+
// traceRouter(store) - the routes, for a ChatStore (sessions.ts)
|
|
10
|
+
// openTrace - a request's recorded run: its record, run directory, steps and payloads
|
|
11
|
+
import { assertState, FilePayloadStore, PayloadResolver, } from '@zenera/neo';
|
|
12
|
+
import { runPaths } from '@zenera/engine';
|
|
13
|
+
import { Router } from 'express';
|
|
14
|
+
import { readFile } from 'node:fs/promises';
|
|
15
|
+
import { HttpError } from "./http.js";
|
|
16
|
+
import { recordedRun } from "./runRecords.js";
|
|
17
|
+
export const MAX_PART_CHARS = 256 * 1024;
|
|
18
|
+
export const MAX_REQUEST_CHARS = 1024 * 1024;
|
|
19
|
+
const DEFAULT_LIMIT = 200;
|
|
20
|
+
const MAX_LIMIT = 500;
|
|
21
|
+
const STEP_TYPES = new Set([
|
|
22
|
+
'user_input',
|
|
23
|
+
'system_prompt',
|
|
24
|
+
'load_skills',
|
|
25
|
+
'memory_recall',
|
|
26
|
+
'memory_op',
|
|
27
|
+
'llm_call',
|
|
28
|
+
'tool_call',
|
|
29
|
+
'tool_result',
|
|
30
|
+
'handoff',
|
|
31
|
+
'fork',
|
|
32
|
+
'join',
|
|
33
|
+
'compaction',
|
|
34
|
+
'final_output',
|
|
35
|
+
]);
|
|
36
|
+
// `zen inspect` numbers nodes in the order the run appended them: a join's branches ran before
|
|
37
|
+
// the join, so their nodes are numbered first (ZeneraNeo packages/cli/src/trace.ts, flatten).
|
|
38
|
+
function inspectKeys(trajectory) {
|
|
39
|
+
const keys = new Map();
|
|
40
|
+
const walk = (nodes) => {
|
|
41
|
+
for (const node of nodes) {
|
|
42
|
+
if (node.type === 'join')
|
|
43
|
+
for (const b of node.branches)
|
|
44
|
+
walk(b.nodes);
|
|
45
|
+
keys.set(node, `n${keys.size + 1}`);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
walk(trajectory);
|
|
49
|
+
return keys;
|
|
50
|
+
}
|
|
51
|
+
export function flatten(trajectory) {
|
|
52
|
+
const keys = inspectKeys(trajectory);
|
|
53
|
+
const out = [];
|
|
54
|
+
const walk = (nodes, depth, branch, top) => {
|
|
55
|
+
nodes.forEach((node, i) => {
|
|
56
|
+
const at = top ?? i;
|
|
57
|
+
out.push({ node, depth, branch, top: at, key: keys.get(node) });
|
|
58
|
+
if (node.type === 'join') {
|
|
59
|
+
for (const b of node.branches) {
|
|
60
|
+
walk(b.nodes, depth + 1, branch ? `${branch} › ${b.name}` : b.name, at);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
walk(trajectory, 0, undefined);
|
|
66
|
+
return out;
|
|
67
|
+
}
|
|
68
|
+
function title(n) {
|
|
69
|
+
switch (n.type) {
|
|
70
|
+
case 'user_input':
|
|
71
|
+
return n.synthetic ? 'Runtime input' : 'User input';
|
|
72
|
+
case 'system_prompt':
|
|
73
|
+
return 'System prompt';
|
|
74
|
+
case 'load_skills':
|
|
75
|
+
return `Skills · ${n.skills.map((s) => s.name).join(', ')}`;
|
|
76
|
+
case 'memory_recall':
|
|
77
|
+
return `Memory recall · ${n.nodes.length} nodes`;
|
|
78
|
+
case 'memory_op':
|
|
79
|
+
return `Memory ${n.op} · ${n.nodes.length} nodes`;
|
|
80
|
+
case 'llm_call':
|
|
81
|
+
return `LLM call · ${n.model}`;
|
|
82
|
+
case 'tool_call':
|
|
83
|
+
return `Tool call · ${n.name}`;
|
|
84
|
+
case 'tool_result':
|
|
85
|
+
return `Tool result · ${n.name}`;
|
|
86
|
+
case 'handoff':
|
|
87
|
+
return `Handoff · ${n.from} → ${n.to}`;
|
|
88
|
+
case 'fork':
|
|
89
|
+
return `Fork · ${n.branches.map((b) => b.name).join(', ')}`;
|
|
90
|
+
case 'join':
|
|
91
|
+
return `Join · ${n.branches.map((b) => `${b.name} ${b.status}`).join(', ')}`;
|
|
92
|
+
case 'compaction':
|
|
93
|
+
return `Compaction · ${n.covers.length} nodes`;
|
|
94
|
+
case 'final_output':
|
|
95
|
+
return 'Final output';
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
export function toStep(f, index) {
|
|
99
|
+
const n = f.node;
|
|
100
|
+
const step = {
|
|
101
|
+
index,
|
|
102
|
+
id: n.id,
|
|
103
|
+
type: n.type,
|
|
104
|
+
agent: n.agent,
|
|
105
|
+
ts: n.ts,
|
|
106
|
+
depth: f.depth,
|
|
107
|
+
...(f.branch ? { branch: f.branch } : {}),
|
|
108
|
+
node: f.key,
|
|
109
|
+
title: title(n),
|
|
110
|
+
};
|
|
111
|
+
if (n.type === 'llm_call') {
|
|
112
|
+
step.model = n.model;
|
|
113
|
+
step.usage = n.usage;
|
|
114
|
+
step.stopReason = n.stopReason;
|
|
115
|
+
if (n.toolCalls.length)
|
|
116
|
+
step.tools = n.toolCalls.map((c) => c.name);
|
|
117
|
+
}
|
|
118
|
+
else if (n.type === 'compaction') {
|
|
119
|
+
step.usage = n.usage;
|
|
120
|
+
}
|
|
121
|
+
else if (n.type === 'tool_result') {
|
|
122
|
+
step.isError = n.isError;
|
|
123
|
+
if (n.durationMs !== undefined)
|
|
124
|
+
step.durationMs = n.durationMs;
|
|
125
|
+
}
|
|
126
|
+
else if (n.type === 'join') {
|
|
127
|
+
step.usage = n.usage;
|
|
128
|
+
step.isError = n.branches.some((b) => b.status !== 'ok');
|
|
129
|
+
}
|
|
130
|
+
else if (n.type === 'user_input' && n.synthetic) {
|
|
131
|
+
step.synthetic = true;
|
|
132
|
+
}
|
|
133
|
+
return step;
|
|
134
|
+
}
|
|
135
|
+
async function loadState(statePath) {
|
|
136
|
+
try {
|
|
137
|
+
return assertState(JSON.parse(await readFile(statePath, 'utf8')));
|
|
138
|
+
}
|
|
139
|
+
catch (err) {
|
|
140
|
+
throw new HttpError(500, `the recorded run state cannot be read: ${err.message}`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
function int(req, key, fallback, min, max) {
|
|
144
|
+
const raw = req.query[key];
|
|
145
|
+
if (raw === undefined)
|
|
146
|
+
return fallback;
|
|
147
|
+
const n = typeof raw === 'string' && /^\d+$/.test(raw) ? Number(raw) : NaN;
|
|
148
|
+
if (!Number.isInteger(n) || n < min || n > max) {
|
|
149
|
+
throw new HttpError(400, `${key} must be a whole number from ${min} to ${max}`);
|
|
150
|
+
}
|
|
151
|
+
return n;
|
|
152
|
+
}
|
|
153
|
+
function only(req, allowed) {
|
|
154
|
+
for (const [key, value] of Object.entries(req.query)) {
|
|
155
|
+
if (!allowed.includes(key))
|
|
156
|
+
throw new HttpError(400, `unsupported query parameter: ${key}`);
|
|
157
|
+
if (typeof value !== 'string')
|
|
158
|
+
throw new HttpError(400, `${key} must be given once`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
export async function openTrace(store, req) {
|
|
162
|
+
const t = store.thread(req);
|
|
163
|
+
const { record, session, statePath } = recordedRun(store.runsDir(t), store.existingSession(t), String(req.params.runId));
|
|
164
|
+
const state = await loadState(statePath);
|
|
165
|
+
const payloads = new PayloadResolver(new FilePayloadStore({ dir: session.blobs, id: 'file' }));
|
|
166
|
+
const runDir = runPaths(session, record.engineRunId).dir;
|
|
167
|
+
return { thread: t, record, runDir, state, payloads, flat: flatten(state.trajectory) };
|
|
168
|
+
}
|
|
169
|
+
/** The step a route names by its index, or 404. */
|
|
170
|
+
export function stepParam(flat, raw) {
|
|
171
|
+
if (!/^\d{1,7}$/.test(raw))
|
|
172
|
+
throw new HttpError(400, 'invalid step');
|
|
173
|
+
const index = Number(raw);
|
|
174
|
+
const f = flat[index];
|
|
175
|
+
if (!f)
|
|
176
|
+
throw new HttpError(404, 'no such step');
|
|
177
|
+
return { f, index };
|
|
178
|
+
}
|
|
179
|
+
async function payloadPart(payloads, key, label, p, max = MAX_PART_CHARS) {
|
|
180
|
+
try {
|
|
181
|
+
const text = await payloads.get(p);
|
|
182
|
+
return {
|
|
183
|
+
key,
|
|
184
|
+
label,
|
|
185
|
+
kind: 'text',
|
|
186
|
+
text: text.length > max ? text.slice(0, max) : text,
|
|
187
|
+
bytes: p.size,
|
|
188
|
+
...(text.length > max ? { truncated: true } : {}),
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
catch (err) {
|
|
192
|
+
return {
|
|
193
|
+
key,
|
|
194
|
+
label,
|
|
195
|
+
kind: 'text',
|
|
196
|
+
bytes: p.size,
|
|
197
|
+
error: `payload unavailable: ${err.message}`,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
const json = (key, label, value) => ({
|
|
202
|
+
key,
|
|
203
|
+
label,
|
|
204
|
+
kind: 'json',
|
|
205
|
+
json: value,
|
|
206
|
+
});
|
|
207
|
+
export async function stepParts(n, payloads) {
|
|
208
|
+
const parts = [];
|
|
209
|
+
const add = async (key, label, p) => {
|
|
210
|
+
if (p)
|
|
211
|
+
parts.push(await payloadPart(payloads, key, label, p));
|
|
212
|
+
};
|
|
213
|
+
switch (n.type) {
|
|
214
|
+
case 'user_input':
|
|
215
|
+
for (const [i, c] of n.content.entries()) {
|
|
216
|
+
if (c.type === 'text')
|
|
217
|
+
await add(`content.${i}`, 'Input', c.text);
|
|
218
|
+
else
|
|
219
|
+
parts.push({
|
|
220
|
+
key: `content.${i}`,
|
|
221
|
+
label: `Attached ${c.type}`,
|
|
222
|
+
kind: 'text',
|
|
223
|
+
// An inline data: url can be megabytes of base64; name it, do not send it.
|
|
224
|
+
text: c.url.startsWith('data:')
|
|
225
|
+
? `${c.mimeType ?? c.type} (inline data, ${c.url.length} characters)`
|
|
226
|
+
: c.url,
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
break;
|
|
230
|
+
case 'system_prompt':
|
|
231
|
+
await add('prompt', 'System prompt', n.prompt);
|
|
232
|
+
if (n.sources?.length)
|
|
233
|
+
parts.push(json('sources', 'Prompt sources', n.sources.map((s) => s.path)));
|
|
234
|
+
break;
|
|
235
|
+
case 'load_skills':
|
|
236
|
+
parts.push(json('skills', 'Skills', {
|
|
237
|
+
provider: n.provider,
|
|
238
|
+
skills: n.skills,
|
|
239
|
+
tools: n.toolNames,
|
|
240
|
+
}));
|
|
241
|
+
await add('content', 'Instructions', n.content);
|
|
242
|
+
break;
|
|
243
|
+
case 'memory_recall':
|
|
244
|
+
parts.push(json('query', 'Query', n.query));
|
|
245
|
+
await add('content', 'Recalled block', n.content);
|
|
246
|
+
parts.push(json('nodes', 'Nodes', { seeds: n.seeds, nodes: n.nodes, edges: n.edges }));
|
|
247
|
+
break;
|
|
248
|
+
case 'memory_op':
|
|
249
|
+
parts.push(json('op', 'Operation', {
|
|
250
|
+
op: n.op,
|
|
251
|
+
nodes: n.nodes,
|
|
252
|
+
edges: n.edges,
|
|
253
|
+
files: n.files,
|
|
254
|
+
}));
|
|
255
|
+
break;
|
|
256
|
+
case 'llm_call':
|
|
257
|
+
parts.push(json('call', 'Call', { model: n.model, stopReason: n.stopReason, usage: n.usage }));
|
|
258
|
+
await add('thinking', 'Thinking', n.thinking);
|
|
259
|
+
await add('text', 'Response', n.text);
|
|
260
|
+
for (const [i, c] of n.toolCalls.entries()) {
|
|
261
|
+
await add(`toolCalls.${i}`, `Tool call · ${c.name} (${c.callId})`, c.args);
|
|
262
|
+
}
|
|
263
|
+
if (n.request) {
|
|
264
|
+
parts.push({
|
|
265
|
+
key: 'request',
|
|
266
|
+
label: 'Recorded request',
|
|
267
|
+
kind: 'text',
|
|
268
|
+
bytes: n.request.size,
|
|
269
|
+
deferred: true,
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
break;
|
|
273
|
+
case 'tool_call':
|
|
274
|
+
await add('args', `Arguments · ${n.name} (${n.callId})`, n.args);
|
|
275
|
+
break;
|
|
276
|
+
case 'tool_result':
|
|
277
|
+
parts.push(json('result.meta', 'Result', {
|
|
278
|
+
callId: n.callId,
|
|
279
|
+
isError: n.isError,
|
|
280
|
+
durationMs: n.durationMs,
|
|
281
|
+
}));
|
|
282
|
+
await add('result', n.isError ? 'Error output' : 'Output', n.result);
|
|
283
|
+
break;
|
|
284
|
+
case 'handoff':
|
|
285
|
+
parts.push(json('handoff', 'Handoff', { from: n.from, to: n.to, reason: n.reason }));
|
|
286
|
+
break;
|
|
287
|
+
case 'fork':
|
|
288
|
+
parts.push(json('fork', 'Fork', { callId: n.callId, contextMode: n.contextMode }));
|
|
289
|
+
for (const [i, b] of n.branches.entries()) {
|
|
290
|
+
await add(`branches.${i}`, `Instructions · ${b.name} (${b.agent})`, b.instructions);
|
|
291
|
+
}
|
|
292
|
+
break;
|
|
293
|
+
case 'join':
|
|
294
|
+
for (const [i, b] of n.branches.entries()) {
|
|
295
|
+
parts.push(json(`branches.${i}.meta`, `Branch · ${b.name}`, {
|
|
296
|
+
agent: b.agent,
|
|
297
|
+
status: b.status,
|
|
298
|
+
error: b.error,
|
|
299
|
+
usage: b.usage,
|
|
300
|
+
steps: b.nodes.length,
|
|
301
|
+
}));
|
|
302
|
+
await add(`branches.${i}`, `Output · ${b.name}`, b.output);
|
|
303
|
+
}
|
|
304
|
+
break;
|
|
305
|
+
case 'compaction':
|
|
306
|
+
parts.push(json('compaction', 'Compaction', {
|
|
307
|
+
reason: n.reason,
|
|
308
|
+
covers: n.covers.length,
|
|
309
|
+
usage: n.usage,
|
|
310
|
+
}));
|
|
311
|
+
await add('summary', 'Summary', n.summary);
|
|
312
|
+
break;
|
|
313
|
+
case 'final_output':
|
|
314
|
+
await add('output', 'Output', n.output);
|
|
315
|
+
if (n.parsed !== undefined)
|
|
316
|
+
parts.push(json('parsed', 'Parsed output', n.parsed));
|
|
317
|
+
break;
|
|
318
|
+
}
|
|
319
|
+
return parts;
|
|
320
|
+
}
|
|
321
|
+
export function traceRouter(store) {
|
|
322
|
+
const router = Router();
|
|
323
|
+
router.get('/:tid/runs/:runId/trace', async (req, res) => {
|
|
324
|
+
only(req, ['scope', 'offset', 'limit', 'types']);
|
|
325
|
+
const scopeParam = req.query.scope ?? 'turn';
|
|
326
|
+
if (scopeParam !== 'turn' && scopeParam !== 'session') {
|
|
327
|
+
throw new HttpError(400, 'scope must be turn or session');
|
|
328
|
+
}
|
|
329
|
+
const types = typeof req.query.types === 'string' && req.query.types
|
|
330
|
+
? req.query.types.split(',')
|
|
331
|
+
: [];
|
|
332
|
+
for (const t of types) {
|
|
333
|
+
if (!STEP_TYPES.has(t))
|
|
334
|
+
throw new HttpError(400, `unknown step type: ${t}`);
|
|
335
|
+
}
|
|
336
|
+
const offset = int(req, 'offset', 0, 0, 1_000_000);
|
|
337
|
+
const limit = int(req, 'limit', DEFAULT_LIMIT, 1, MAX_LIMIT);
|
|
338
|
+
const { record, flat } = await openTrace(store, req);
|
|
339
|
+
const start = record.trajectoryStart;
|
|
340
|
+
const turnAvailable = start !== undefined;
|
|
341
|
+
const scope = turnAvailable ? scopeParam : 'session';
|
|
342
|
+
const inScope = flat
|
|
343
|
+
.map((f, index) => ({ f, index }))
|
|
344
|
+
.filter(({ f }) => scope === 'session' || f.top >= start);
|
|
345
|
+
const counts = {};
|
|
346
|
+
for (const { f } of inScope)
|
|
347
|
+
counts[f.node.type] = (counts[f.node.type] ?? 0) + 1;
|
|
348
|
+
const shown = types.length
|
|
349
|
+
? inScope.filter(({ f }) => types.includes(f.node.type))
|
|
350
|
+
: inScope;
|
|
351
|
+
const page = {
|
|
352
|
+
runId: record.runId,
|
|
353
|
+
engineRunId: record.engineRunId,
|
|
354
|
+
scope,
|
|
355
|
+
turnAvailable,
|
|
356
|
+
total: shown.length,
|
|
357
|
+
offset,
|
|
358
|
+
limit,
|
|
359
|
+
counts,
|
|
360
|
+
steps: shown.slice(offset, offset + limit).map(({ f, index }) => toStep(f, index)),
|
|
361
|
+
};
|
|
362
|
+
res.setHeader('Cache-Control', 'no-store');
|
|
363
|
+
res.json(page);
|
|
364
|
+
});
|
|
365
|
+
router.get('/:tid/runs/:runId/trace/:step', async (req, res) => {
|
|
366
|
+
only(req, ['part']);
|
|
367
|
+
const { flat, payloads } = await openTrace(store, req);
|
|
368
|
+
const { f, index } = stepParam(flat, String(req.params.step));
|
|
369
|
+
res.setHeader('Cache-Control', 'no-store');
|
|
370
|
+
if (req.query.part !== undefined) {
|
|
371
|
+
if (req.query.part !== 'request')
|
|
372
|
+
throw new HttpError(400, 'only the request part is fetched separately');
|
|
373
|
+
if (f.node.type !== 'llm_call' || !f.node.request) {
|
|
374
|
+
throw new HttpError(404, 'this step has no recorded request');
|
|
375
|
+
}
|
|
376
|
+
res.json({
|
|
377
|
+
part: await payloadPart(payloads, 'request', 'Recorded request', f.node.request, MAX_REQUEST_CHARS),
|
|
378
|
+
});
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
const detail = {
|
|
382
|
+
step: toStep(f, index),
|
|
383
|
+
parts: await stepParts(f.node, payloads),
|
|
384
|
+
};
|
|
385
|
+
res.json(detail);
|
|
386
|
+
});
|
|
387
|
+
return router;
|
|
388
|
+
}
|
|
389
|
+
//# sourceMappingURL=trace.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,57 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
"name": "@zenera/server",
|
|
3
|
+
"version": "1.2.0",
|
|
4
|
+
"description": "One user's chats with a project over HTTP: the server in the agent image, commands isolated with bubblewrap. Every user its host vouches for with a signed JWT, each in a folder of their own.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"agents",
|
|
7
|
+
"ai-agents",
|
|
8
|
+
"agent-runtime",
|
|
9
|
+
"ag-ui",
|
|
10
|
+
"server"
|
|
11
|
+
],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"publishConfig": {
|
|
14
|
+
"access": "public"
|
|
15
|
+
},
|
|
16
|
+
"author": "Andrey Ryabov",
|
|
17
|
+
"homepage": "https://github.com/zenera-ai/ZeneraNeo#readme",
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/zenera-ai/ZeneraNeo.git",
|
|
21
|
+
"directory": "packages/server"
|
|
22
|
+
},
|
|
23
|
+
"bugs": "https://github.com/zenera-ai/ZeneraNeo/issues",
|
|
24
|
+
"type": "module",
|
|
25
|
+
"main": "./dist/index.js",
|
|
26
|
+
"types": "./dist/index.d.ts",
|
|
27
|
+
"exports": {
|
|
28
|
+
".": {
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"default": "./dist/index.js"
|
|
31
|
+
},
|
|
32
|
+
"./package.json": "./package.json"
|
|
33
|
+
},
|
|
34
|
+
"files": [
|
|
35
|
+
"dist",
|
|
36
|
+
"!dist/**/*.map"
|
|
37
|
+
],
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=24"
|
|
40
|
+
},
|
|
41
|
+
"scripts": {
|
|
42
|
+
"build": "tsc -b",
|
|
43
|
+
"clean": "tsc -b --clean && rm -rf dist",
|
|
44
|
+
"prepack": "tsc -b"
|
|
45
|
+
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@ag-ui/core": "^1.0.3",
|
|
48
|
+
"@zenera/engine": "^1.2.0",
|
|
49
|
+
"@zenera/neo": "^1.2.0",
|
|
50
|
+
"@zenera/sandbox": "^1.2.0",
|
|
51
|
+
"express": "^5.3.0",
|
|
52
|
+
"jose": "^6.2.13"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@types/express": "^5.0.6"
|
|
56
|
+
}
|
|
57
|
+
}
|