@amaster.ai/pi-storage 0.1.0-beta.0 → 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/README.md +1 -1
- package/dist/artifact-stores.d.ts +1 -1
- package/dist/artifact-stores.d.ts.map +1 -1
- package/dist/artifact-stores.js +2 -2
- package/dist/artifact-stores.js.map +1 -1
- package/dist/db-migrations.js +24 -24
- package/dist/db-migrations.js.map +1 -1
- package/dist/db-runtime-storage.d.ts +1 -1
- package/dist/db-runtime-storage.d.ts.map +1 -1
- package/dist/db-runtime-storage.js +175 -123
- package/dist/db-runtime-storage.js.map +1 -1
- package/dist/db.d.ts +3 -2
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +3 -2
- package/dist/db.js.map +1 -1
- package/dist/event-stores.d.ts +1 -1
- package/dist/event-stores.d.ts.map +1 -1
- package/dist/event-stores.js +22 -5
- package/dist/event-stores.js.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/internal.d.ts +3 -3
- package/dist/internal.js +3 -3
- package/dist/json-file.d.ts +7 -0
- package/dist/json-file.d.ts.map +1 -1
- package/dist/json-file.js +6 -6
- package/dist/json-file.js.map +1 -1
- package/dist/json.d.ts +5 -4
- package/dist/json.d.ts.map +1 -1
- package/dist/json.js +5 -4
- package/dist/json.js.map +1 -1
- package/dist/migration-main.js +4 -4
- package/dist/redis-locks.js +7 -7
- package/dist/runtime-scope.d.ts +1 -1
- package/dist/runtime-scope.d.ts.map +1 -1
- package/dist/runtime-storage-json.d.ts +18 -0
- package/dist/runtime-storage-json.d.ts.map +1 -0
- package/dist/runtime-storage-json.js +19 -0
- package/dist/runtime-storage-json.js.map +1 -0
- package/dist/{scheduled-task-stores.d.ts → scheduler-db.d.ts} +2 -24
- package/dist/scheduler-db.d.ts.map +1 -0
- package/dist/{scheduled-task-stores.js → scheduler-db.js} +32 -171
- package/dist/scheduler-db.js.map +1 -0
- package/dist/scheduler-json.d.ts +24 -0
- package/dist/scheduler-json.d.ts.map +1 -0
- package/dist/scheduler-json.js +134 -0
- package/dist/scheduler-json.js.map +1 -0
- package/dist/session-stores.d.ts +2 -1
- package/dist/session-stores.d.ts.map +1 -1
- package/dist/session-stores.js +41 -24
- package/dist/session-stores.js.map +1 -1
- package/dist/session-workspaces.d.ts +22 -0
- package/dist/session-workspaces.d.ts.map +1 -0
- package/dist/session-workspaces.js +75 -0
- package/dist/session-workspaces.js.map +1 -0
- package/dist/subagent-store.d.ts +2 -2
- package/dist/subagent-store.d.ts.map +1 -1
- package/dist/subagent-store.js +18 -18
- package/dist/subagent-store.js.map +1 -1
- package/package.json +21 -8
- package/dist/runtime-storage.d.ts +0 -30
- package/dist/runtime-storage.d.ts.map +0 -1
- package/dist/runtime-storage.js +0 -60
- package/dist/runtime-storage.js.map +0 -1
- package/dist/scheduled-task-stores.d.ts.map +0 -1
- package/dist/scheduled-task-stores.js.map +0 -1
- package/dist/scheduler.d.ts +0 -2
- package/dist/scheduler.d.ts.map +0 -1
- package/dist/scheduler.js +0 -2
- package/dist/scheduler.js.map +0 -1
|
@@ -5,23 +5,23 @@
|
|
|
5
5
|
* packages/storage/prisma/schema.prisma. JSON mode remains the local developer
|
|
6
6
|
* adapter; DB mode uses these stores directly and never falls back silently.
|
|
7
7
|
*/
|
|
8
|
-
import { createHash, randomUUID } from
|
|
9
|
-
import { Prisma, PrismaClient } from
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
8
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
9
|
+
import { Prisma, PrismaClient } from '@prisma/client';
|
|
10
|
+
import { RedisLockManager } from './redis-locks.js';
|
|
11
|
+
import { isTerminalSubagentStatus } from './subagent-store.js';
|
|
12
12
|
const REQUIRED_DB_TABLES = [
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
13
|
+
'pi_agent_sessions',
|
|
14
|
+
'pi_agent_turns',
|
|
15
|
+
'pi_agent_messages',
|
|
16
|
+
'pi_agent_turn_queue',
|
|
17
|
+
'pi_agent_turn_signals',
|
|
18
|
+
'pi_agent_events',
|
|
19
|
+
'pi_agent_subagent_runs',
|
|
20
|
+
'pi_agent_approvals',
|
|
21
|
+
'pi_agent_memory',
|
|
22
|
+
'pi_agent_scheduled_tasks',
|
|
23
|
+
'pi_agent_task_runs',
|
|
24
|
+
'pi_agent_artifacts',
|
|
25
25
|
];
|
|
26
26
|
export function createDbRuntimeStores(databaseUrl, redisUrl) {
|
|
27
27
|
const context = new DbRuntimeContext(databaseUrl, redisUrl);
|
|
@@ -48,8 +48,8 @@ export async function verifyDbRuntimeSchema(databaseUrl) {
|
|
|
48
48
|
const found = new Set(rows.map((row) => row.table_name));
|
|
49
49
|
const missing = REQUIRED_DB_TABLES.filter((table) => !found.has(table));
|
|
50
50
|
if (missing.length > 0) {
|
|
51
|
-
throw new Error(`STORAGE_MODE=db schema is missing required table(s): ${missing.join(
|
|
52
|
-
|
|
51
|
+
throw new Error(`STORAGE_MODE=db schema is missing required table(s): ${missing.join(', ')}. ` +
|
|
52
|
+
'Apply the pi runtime DB migration before starting server.');
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
finally {
|
|
@@ -70,18 +70,18 @@ class DbRuntimeContext {
|
|
|
70
70
|
async resolveIdentity(sessionId, tx = this.prisma) {
|
|
71
71
|
const row = await tx.piAgentSession.findFirst({
|
|
72
72
|
where: { sessionId: { in: identityLookupSessionIds(sessionId) }, deletedAt: null },
|
|
73
|
-
orderBy: { updatedAt:
|
|
73
|
+
orderBy: { updatedAt: 'desc' },
|
|
74
74
|
select: { tenantId: true, userId: true, workspaceId: true },
|
|
75
75
|
});
|
|
76
76
|
return {
|
|
77
|
-
tenantId: row?.tenantId ??
|
|
78
|
-
userId: row?.userId ??
|
|
77
|
+
tenantId: row?.tenantId ?? 'default',
|
|
78
|
+
userId: row?.userId ?? 'system',
|
|
79
79
|
...(row?.workspaceId ? { workspaceId: row.workspaceId } : {}),
|
|
80
80
|
};
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
83
|
function identityLookupSessionIds(sessionId) {
|
|
84
|
-
const subagentMarker =
|
|
84
|
+
const subagentMarker = ':subagent:';
|
|
85
85
|
const markerIndex = sessionId.indexOf(subagentMarker);
|
|
86
86
|
if (markerIndex <= 0) {
|
|
87
87
|
return [sessionId];
|
|
@@ -96,15 +96,15 @@ class DbRuntimeSessionStore {
|
|
|
96
96
|
async getRuntimeSession(scope, sessionId) {
|
|
97
97
|
const row = await this.db.prisma.piAgentSession.findFirst({
|
|
98
98
|
where: { sessionId, deletedAt: null, ...sessionScopeWhere(scope) },
|
|
99
|
-
orderBy: { updatedAt:
|
|
99
|
+
orderBy: { updatedAt: 'desc' },
|
|
100
100
|
});
|
|
101
101
|
return row ? sessionFromPrisma(row) : undefined;
|
|
102
102
|
}
|
|
103
103
|
async saveRuntimeSession(session) {
|
|
104
104
|
const now = new Date().toISOString();
|
|
105
|
-
const tenantId = session.tenantId ??
|
|
106
|
-
const userId = session.userId ??
|
|
107
|
-
const rowId = stableRowId(
|
|
105
|
+
const tenantId = session.tenantId ?? 'default';
|
|
106
|
+
const userId = session.userId ?? 'system';
|
|
107
|
+
const rowId = stableRowId('session', tenantId, session.sessionId);
|
|
108
108
|
await this.db.prisma.piAgentSession.upsert({
|
|
109
109
|
where: { id: rowId },
|
|
110
110
|
create: {
|
|
@@ -119,8 +119,8 @@ class DbRuntimeSessionStore {
|
|
|
119
119
|
taskRunId: session.taskRunId ?? null,
|
|
120
120
|
runId: session.runId ?? null,
|
|
121
121
|
spawnBatchId: session.spawnBatchId ?? null,
|
|
122
|
-
triggerType:
|
|
123
|
-
status:
|
|
122
|
+
triggerType: 'user',
|
|
123
|
+
status: 'active',
|
|
124
124
|
modelProvider: session.model.provider,
|
|
125
125
|
modelName: session.model.model,
|
|
126
126
|
thinkingLevel: session.model.thinkingLevel ?? null,
|
|
@@ -159,7 +159,7 @@ class DbRuntimeSessionStore {
|
|
|
159
159
|
async listRuntimeSessions(scope) {
|
|
160
160
|
const rows = await this.db.prisma.piAgentSession.findMany({
|
|
161
161
|
where: { deletedAt: null, ...sessionScopeWhere(scope) },
|
|
162
|
-
orderBy: [{ lastMessageAt:
|
|
162
|
+
orderBy: [{ lastMessageAt: 'desc' }, { updatedAt: 'desc' }],
|
|
163
163
|
});
|
|
164
164
|
return rows.map(sessionFromPrisma);
|
|
165
165
|
}
|
|
@@ -181,11 +181,11 @@ class DbTranscriptStore {
|
|
|
181
181
|
nextBigIntSeq(tx.piAgentTurn.aggregate({
|
|
182
182
|
where: { tenantId: identity.tenantId, sessionId: turn.sessionId },
|
|
183
183
|
_max: { turnSeq: true },
|
|
184
|
-
}),
|
|
184
|
+
}), 'turnSeq'),
|
|
185
185
|
nextBigIntSeq(tx.piAgentMessage.aggregate({
|
|
186
186
|
where: { tenantId: identity.tenantId, sessionId: turn.sessionId },
|
|
187
187
|
_max: { messageSeq: true },
|
|
188
|
-
}),
|
|
188
|
+
}), 'messageSeq'),
|
|
189
189
|
]);
|
|
190
190
|
await tx.piAgentTurn.create({
|
|
191
191
|
data: {
|
|
@@ -197,8 +197,8 @@ class DbTranscriptStore {
|
|
|
197
197
|
conversationId: turn.conversationId,
|
|
198
198
|
traceId: turn.traceId ?? null,
|
|
199
199
|
turnSeq,
|
|
200
|
-
sourceType:
|
|
201
|
-
status:
|
|
200
|
+
sourceType: 'user',
|
|
201
|
+
status: 'completed',
|
|
202
202
|
inputText: turn.userMessage,
|
|
203
203
|
outputText: turn.assistantMessage,
|
|
204
204
|
modelJson: jsonInput(turn.model),
|
|
@@ -209,8 +209,8 @@ class DbTranscriptStore {
|
|
|
209
209
|
});
|
|
210
210
|
await tx.piAgentMessage.createMany({
|
|
211
211
|
data: [
|
|
212
|
-
messageCreateInput(identity, turn, `${turn.id}:user`,
|
|
213
|
-
messageCreateInput(identity, turn, `${turn.id}:assistant`,
|
|
212
|
+
messageCreateInput(identity, turn, `${turn.id}:user`, 'user', turn.userMessage, messageSeq),
|
|
213
|
+
messageCreateInput(identity, turn, `${turn.id}:assistant`, 'assistant', turn.assistantMessage, messageSeq + 1n),
|
|
214
214
|
],
|
|
215
215
|
});
|
|
216
216
|
await tx.piAgentSession.updateMany({
|
|
@@ -233,7 +233,7 @@ class DbTranscriptStore {
|
|
|
233
233
|
async listTurns(scope, sessionId) {
|
|
234
234
|
const rows = await this.db.prisma.piAgentTurn.findMany({
|
|
235
235
|
where: { ...(sessionId ? { sessionId } : {}), ...sessionScopeWhere(scope) },
|
|
236
|
-
orderBy: [{ createdAt:
|
|
236
|
+
orderBy: [{ createdAt: 'asc' }, { turnSeq: 'asc' }],
|
|
237
237
|
});
|
|
238
238
|
return rows.map(turnFromPrisma);
|
|
239
239
|
}
|
|
@@ -241,16 +241,14 @@ class DbTranscriptStore {
|
|
|
241
241
|
const [rows, turns] = await Promise.all([
|
|
242
242
|
this.db.prisma.piAgentMessage.findMany({
|
|
243
243
|
where: { sessionId, deletedAt: null, ...sessionScopeWhere(scope) },
|
|
244
|
-
orderBy: { messageSeq:
|
|
244
|
+
orderBy: { messageSeq: 'asc' },
|
|
245
245
|
}),
|
|
246
246
|
this.db.prisma.piAgentTurn.findMany({
|
|
247
247
|
where: { sessionId, ...sessionScopeWhere(scope) },
|
|
248
248
|
select: { id: true, traceId: true },
|
|
249
249
|
}),
|
|
250
250
|
]);
|
|
251
|
-
const traceIdsByTurnId = new Map(turns
|
|
252
|
-
.filter((turn) => Boolean(turn.traceId))
|
|
253
|
-
.map((turn) => [turn.id, turn.traceId]));
|
|
251
|
+
const traceIdsByTurnId = new Map(turns.filter((turn) => Boolean(turn.traceId)).map((turn) => [turn.id, turn.traceId]));
|
|
254
252
|
return rows.map((row) => messageFromPrisma(row, traceIdsByTurnId));
|
|
255
253
|
}
|
|
256
254
|
async listSessionSummaries(scope, sessions) {
|
|
@@ -264,6 +262,12 @@ class DbTranscriptStore {
|
|
|
264
262
|
const bySessionId = new Map(rows.map((row) => [row.sessionId, row]));
|
|
265
263
|
return sessions.map((session) => summaryFromPrismaSession(session, bySessionId.get(session.sessionId)));
|
|
266
264
|
}
|
|
265
|
+
async updateSessionTitle(scope, sessionId, title) {
|
|
266
|
+
await this.db.prisma.piAgentSession.updateMany({
|
|
267
|
+
where: { sessionId, deletedAt: null, ...sessionScopeWhere(scope) },
|
|
268
|
+
data: { title, updatedAt: new Date() },
|
|
269
|
+
});
|
|
270
|
+
}
|
|
267
271
|
}
|
|
268
272
|
class DbRuntimeTimelineEventStore {
|
|
269
273
|
db;
|
|
@@ -278,7 +282,10 @@ class DbRuntimeTimelineEventStore {
|
|
|
278
282
|
timeoutMs: 5_000,
|
|
279
283
|
task: async () => {
|
|
280
284
|
await this.db.prisma.$transaction(async (tx) => {
|
|
281
|
-
const existing = await tx.piAgentEvent.findUnique({
|
|
285
|
+
const existing = await tx.piAgentEvent.findUnique({
|
|
286
|
+
where: { id: event.eventId },
|
|
287
|
+
select: { id: true },
|
|
288
|
+
});
|
|
282
289
|
if (existing) {
|
|
283
290
|
return;
|
|
284
291
|
}
|
|
@@ -299,7 +306,7 @@ class DbRuntimeTimelineEventStore {
|
|
|
299
306
|
eventSource: event.eventSource,
|
|
300
307
|
eventType: event.eventType,
|
|
301
308
|
eventName: event.eventName,
|
|
302
|
-
severity:
|
|
309
|
+
severity: 'info',
|
|
303
310
|
payloadJson: jsonInput(event.payload),
|
|
304
311
|
createdAt: toDate(event.createdAt),
|
|
305
312
|
},
|
|
@@ -310,13 +317,23 @@ class DbRuntimeTimelineEventStore {
|
|
|
310
317
|
}
|
|
311
318
|
async list(input) {
|
|
312
319
|
const limit = positiveLimit(input.limit);
|
|
320
|
+
const cursorEventSeq = input.cursor
|
|
321
|
+
? await this.findCursorEventSeq(input.cursor.eventId)
|
|
322
|
+
: undefined;
|
|
313
323
|
const rows = await this.db.prisma.piAgentEvent.findMany({
|
|
314
|
-
where: timelineWhere(input),
|
|
315
|
-
orderBy: [{ createdAt:
|
|
324
|
+
where: timelineWhere(input, cursorEventSeq),
|
|
325
|
+
orderBy: [{ createdAt: 'desc' }, { eventSeq: 'desc' }, { id: 'desc' }],
|
|
316
326
|
take: limit,
|
|
317
327
|
});
|
|
318
328
|
return rows.map(timelineEventFromPrisma).reverse();
|
|
319
329
|
}
|
|
330
|
+
async findCursorEventSeq(eventId) {
|
|
331
|
+
const row = await this.db.prisma.piAgentEvent.findUnique({
|
|
332
|
+
where: { id: eventId },
|
|
333
|
+
select: { eventSeq: true },
|
|
334
|
+
});
|
|
335
|
+
return row?.eventSeq;
|
|
336
|
+
}
|
|
320
337
|
async listBySource(eventSource, input = {}) {
|
|
321
338
|
const rows = await this.db.prisma.piAgentEvent.findMany({
|
|
322
339
|
where: {
|
|
@@ -324,7 +341,7 @@ class DbRuntimeTimelineEventStore {
|
|
|
324
341
|
...timelineWhere(input),
|
|
325
342
|
...(input.eventType ? { eventType: input.eventType } : {}),
|
|
326
343
|
},
|
|
327
|
-
orderBy: [{ eventSeq:
|
|
344
|
+
orderBy: [{ createdAt: 'desc' }, { eventSeq: 'desc' }, { id: 'desc' }],
|
|
328
345
|
take: positiveLimit(input.limit),
|
|
329
346
|
});
|
|
330
347
|
return rows.map(timelineEventFromPrisma).reverse();
|
|
@@ -339,7 +356,7 @@ class DbRuntimeEventStore {
|
|
|
339
356
|
await this.timeline.append(runtimeEventToTimeline(event));
|
|
340
357
|
}
|
|
341
358
|
async list(input = {}) {
|
|
342
|
-
const events = await this.timeline.listBySource(
|
|
359
|
+
const events = await this.timeline.listBySource('runtime', runtimeListInput(input));
|
|
343
360
|
return events.map((event) => event.payload);
|
|
344
361
|
}
|
|
345
362
|
}
|
|
@@ -352,7 +369,7 @@ class DbToolEventStore {
|
|
|
352
369
|
await this.timeline.append(toolEventToTimeline(event));
|
|
353
370
|
}
|
|
354
371
|
async list(input = {}) {
|
|
355
|
-
const events = await this.timeline.listBySource(
|
|
372
|
+
const events = await this.timeline.listBySource('tool', timelineListInput(input));
|
|
356
373
|
return events.map((event) => event.payload);
|
|
357
374
|
}
|
|
358
375
|
}
|
|
@@ -365,7 +382,7 @@ class DbLlmGenerationEventStore {
|
|
|
365
382
|
await this.timeline.append(llmEventToTimeline(event));
|
|
366
383
|
}
|
|
367
384
|
async list(input = {}) {
|
|
368
|
-
const events = await this.timeline.listBySource(
|
|
385
|
+
const events = await this.timeline.listBySource('llm', timelineListInput(input));
|
|
369
386
|
return events.map((event) => event.payload);
|
|
370
387
|
}
|
|
371
388
|
}
|
|
@@ -391,7 +408,7 @@ class DbMemoryStore {
|
|
|
391
408
|
userId: identity.userId,
|
|
392
409
|
workspaceId: identity.workspaceId ?? null,
|
|
393
410
|
sessionId: input.sessionId,
|
|
394
|
-
scope:
|
|
411
|
+
scope: 'session',
|
|
395
412
|
text: input.text,
|
|
396
413
|
tagsJson: jsonInput(input.tags ?? []),
|
|
397
414
|
metadataJson: jsonInput(input.metadata ?? {}),
|
|
@@ -411,7 +428,7 @@ class DbMemoryStore {
|
|
|
411
428
|
deletedAt: null,
|
|
412
429
|
...(query ? { text: { contains: query } } : {}),
|
|
413
430
|
},
|
|
414
|
-
orderBy: { createdAt:
|
|
431
|
+
orderBy: { createdAt: 'desc' },
|
|
415
432
|
take: positiveLimit(input.limit),
|
|
416
433
|
});
|
|
417
434
|
return rows.map(memoryFromPrisma);
|
|
@@ -442,7 +459,7 @@ class DbSubagentRunStore {
|
|
|
442
459
|
task: input.task,
|
|
443
460
|
...(input.agent ? { agent: input.agent } : {}),
|
|
444
461
|
...(input.label ? { label: input.label } : {}),
|
|
445
|
-
status:
|
|
462
|
+
status: 'pending',
|
|
446
463
|
depth: input.depth,
|
|
447
464
|
model: input.model,
|
|
448
465
|
toolPolicyProfile: input.toolPolicyProfile,
|
|
@@ -450,13 +467,13 @@ class DbSubagentRunStore {
|
|
|
450
467
|
createdAt: now,
|
|
451
468
|
updatedAt: now,
|
|
452
469
|
events: [
|
|
453
|
-
{ type:
|
|
454
|
-
{ type:
|
|
470
|
+
{ type: 'subagent_spawning', at: now },
|
|
471
|
+
{ type: 'subagent_spawned', at: now },
|
|
455
472
|
],
|
|
456
473
|
};
|
|
457
474
|
await this.db.prisma.piAgentSubagentRun.create({
|
|
458
475
|
data: {
|
|
459
|
-
id: stableRowId(
|
|
476
|
+
id: stableRowId('subagent', identity.tenantId, runId),
|
|
460
477
|
tenantId: identity.tenantId,
|
|
461
478
|
userId: identity.userId,
|
|
462
479
|
workspaceId: identity.workspaceId ?? null,
|
|
@@ -483,81 +500,85 @@ class DbSubagentRunStore {
|
|
|
483
500
|
async list(scope, parentSessionId) {
|
|
484
501
|
const rows = await this.db.prisma.piAgentSubagentRun.findMany({
|
|
485
502
|
where: { ...sessionScopeWhere(scope), ...(parentSessionId ? { parentSessionId } : {}) },
|
|
486
|
-
orderBy: { createdAt:
|
|
503
|
+
orderBy: { createdAt: 'asc' },
|
|
487
504
|
});
|
|
488
505
|
return rows.map(subagentFromPrisma);
|
|
489
506
|
}
|
|
490
507
|
async get(scope, runId) {
|
|
491
508
|
const row = await this.db.prisma.piAgentSubagentRun.findFirst({
|
|
492
509
|
where: { runId, ...sessionScopeWhere(scope) },
|
|
493
|
-
orderBy: { updatedAt:
|
|
510
|
+
orderBy: { updatedAt: 'desc' },
|
|
494
511
|
});
|
|
495
512
|
return row ? subagentFromPrisma(row) : undefined;
|
|
496
513
|
}
|
|
497
514
|
async getDepthForSession(scope, sessionId) {
|
|
498
515
|
const row = await this.db.prisma.piAgentSubagentRun.findFirst({
|
|
499
516
|
where: { childSessionId: sessionId, ...sessionScopeWhere(scope) },
|
|
500
|
-
orderBy: { updatedAt:
|
|
517
|
+
orderBy: { updatedAt: 'desc' },
|
|
501
518
|
select: { depth: true },
|
|
502
519
|
});
|
|
503
520
|
return row?.depth ?? 0;
|
|
504
521
|
}
|
|
505
522
|
async countActiveChildren(scope, parentSessionId) {
|
|
506
523
|
return await this.db.prisma.piAgentSubagentRun.count({
|
|
507
|
-
where: {
|
|
524
|
+
where: {
|
|
525
|
+
parentSessionId,
|
|
526
|
+
status: { in: ['pending', 'running'] },
|
|
527
|
+
...sessionScopeWhere(scope),
|
|
528
|
+
},
|
|
508
529
|
});
|
|
509
530
|
}
|
|
510
531
|
async markRunning(scope, runId) {
|
|
511
532
|
return await this.patch(scope, runId, (run, now) => ({
|
|
512
533
|
...run,
|
|
513
|
-
status:
|
|
534
|
+
status: 'running',
|
|
514
535
|
startedAt: run.startedAt ?? now,
|
|
515
536
|
updatedAt: now,
|
|
516
|
-
events: [...run.events, { type:
|
|
537
|
+
events: [...run.events, { type: 'subagent_started', at: now }],
|
|
517
538
|
}));
|
|
518
539
|
}
|
|
519
540
|
async markCompleted(scope, runId, result) {
|
|
520
541
|
return await this.patch(scope, runId, (run, now) => {
|
|
521
|
-
if (run.status ===
|
|
542
|
+
if (run.status === 'cancelled') {
|
|
522
543
|
return run;
|
|
523
544
|
}
|
|
524
545
|
return {
|
|
525
546
|
...omitSubagentError(run),
|
|
526
|
-
status:
|
|
547
|
+
status: 'completed',
|
|
527
548
|
result,
|
|
528
549
|
endedAt: now,
|
|
529
550
|
updatedAt: now,
|
|
530
|
-
events: [...run.events, { type:
|
|
551
|
+
events: [...run.events, { type: 'subagent_ended', at: now, reason: 'completed' }],
|
|
531
552
|
};
|
|
532
553
|
});
|
|
533
554
|
}
|
|
534
555
|
async markFailed(scope, runId, error) {
|
|
535
556
|
return await this.patch(scope, runId, (run, now) => {
|
|
536
|
-
if (run.status ===
|
|
557
|
+
if (run.status === 'cancelled') {
|
|
537
558
|
return run;
|
|
538
559
|
}
|
|
539
560
|
return {
|
|
540
561
|
...run,
|
|
541
|
-
status:
|
|
562
|
+
status: 'failed',
|
|
542
563
|
error,
|
|
543
564
|
endedAt: now,
|
|
544
565
|
updatedAt: now,
|
|
545
|
-
events: [...run.events, { type:
|
|
566
|
+
events: [...run.events, { type: 'subagent_ended', at: now, reason: 'failed' }],
|
|
546
567
|
};
|
|
547
568
|
});
|
|
548
569
|
}
|
|
549
|
-
async markCancelled(scope, runId, reason =
|
|
570
|
+
async markCancelled(scope, runId, reason = 'cancelled') {
|
|
550
571
|
return await this.patch(scope, runId, (run, now) => {
|
|
551
572
|
if (isTerminalSubagentStatus(run.status)) {
|
|
552
573
|
return run;
|
|
553
574
|
}
|
|
554
575
|
return {
|
|
555
576
|
...run,
|
|
556
|
-
status:
|
|
577
|
+
status: 'cancelled',
|
|
557
578
|
error: reason,
|
|
558
579
|
endedAt: now,
|
|
559
580
|
updatedAt: now,
|
|
560
|
-
events: [...run.events, { type:
|
|
581
|
+
events: [...run.events, { type: 'subagent_ended', at: now, reason: 'cancelled' }],
|
|
561
582
|
};
|
|
562
583
|
});
|
|
563
584
|
}
|
|
@@ -592,7 +613,9 @@ class DbArtifactStore {
|
|
|
592
613
|
id: input.id ?? randomUUID(),
|
|
593
614
|
tenantId: input.tenantId ?? identity.tenantId,
|
|
594
615
|
userId: input.userId ?? identity.userId,
|
|
595
|
-
...(input.workspaceId ?? identity.workspaceId
|
|
616
|
+
...((input.workspaceId ?? identity.workspaceId)
|
|
617
|
+
? { workspaceId: input.workspaceId ?? identity.workspaceId }
|
|
618
|
+
: {}),
|
|
596
619
|
sessionId: input.sessionId,
|
|
597
620
|
...(input.turnId ? { turnId: input.turnId } : {}),
|
|
598
621
|
...(input.toolCallId ? { toolCallId: input.toolCallId } : {}),
|
|
@@ -609,8 +632,8 @@ class DbArtifactStore {
|
|
|
609
632
|
await this.db.prisma.piAgentArtifact.create({
|
|
610
633
|
data: {
|
|
611
634
|
id: artifact.id,
|
|
612
|
-
tenantId: artifact.tenantId ??
|
|
613
|
-
userId: artifact.userId ??
|
|
635
|
+
tenantId: artifact.tenantId ?? 'default',
|
|
636
|
+
userId: artifact.userId ?? 'system',
|
|
614
637
|
workspaceId: artifact.workspaceId ?? null,
|
|
615
638
|
sessionId: artifact.sessionId,
|
|
616
639
|
turnId: artifact.turnId ?? null,
|
|
@@ -643,7 +666,7 @@ class DbArtifactStore {
|
|
|
643
666
|
...(input.turnId ? { turnId: input.turnId } : {}),
|
|
644
667
|
...(input.toolCallId ? { toolCallId: input.toolCallId } : {}),
|
|
645
668
|
},
|
|
646
|
-
orderBy: { createdAt:
|
|
669
|
+
orderBy: { createdAt: 'desc' },
|
|
647
670
|
take: positiveLimit(input.limit),
|
|
648
671
|
});
|
|
649
672
|
return rows.map(artifactFromPrisma).reverse();
|
|
@@ -657,7 +680,7 @@ class DbArtifactStore {
|
|
|
657
680
|
}
|
|
658
681
|
}
|
|
659
682
|
async function nextBigIntSeq(aggregatePromise, key) {
|
|
660
|
-
const aggregate = await aggregatePromise;
|
|
683
|
+
const aggregate = (await aggregatePromise);
|
|
661
684
|
return (aggregate._max?.[key] ?? 0n) + 1n;
|
|
662
685
|
}
|
|
663
686
|
function messageCreateInput(identity, turn, id, role, text, messageSeq) {
|
|
@@ -677,7 +700,7 @@ function messageCreateInput(identity, turn, id, role, text, messageSeq) {
|
|
|
677
700
|
createdAt: toDate(turn.createdAt),
|
|
678
701
|
};
|
|
679
702
|
}
|
|
680
|
-
function timelineWhere(input) {
|
|
703
|
+
function timelineWhere(input, cursorEventSeq) {
|
|
681
704
|
const clauses = [];
|
|
682
705
|
if (input.tenantId)
|
|
683
706
|
clauses.push({ tenantId: input.tenantId });
|
|
@@ -685,8 +708,8 @@ function timelineWhere(input) {
|
|
|
685
708
|
clauses.push({
|
|
686
709
|
OR: [
|
|
687
710
|
{ sessionId: input.sessionId },
|
|
688
|
-
{ payloadJson: { path:
|
|
689
|
-
{ payloadJson: { path:
|
|
711
|
+
{ payloadJson: { path: '$.parentSessionId', equals: input.sessionId } },
|
|
712
|
+
{ payloadJson: { path: '$.childSessionId', equals: input.sessionId } },
|
|
690
713
|
],
|
|
691
714
|
});
|
|
692
715
|
}
|
|
@@ -701,12 +724,25 @@ function timelineWhere(input) {
|
|
|
701
724
|
});
|
|
702
725
|
}
|
|
703
726
|
if (input.cursor) {
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
727
|
+
const cursorCreatedAt = toDate(input.cursor.createdAt);
|
|
728
|
+
clauses.push(cursorEventSeq === undefined
|
|
729
|
+
? {
|
|
730
|
+
OR: [
|
|
731
|
+
{ createdAt: { lt: cursorCreatedAt } },
|
|
732
|
+
{ createdAt: cursorCreatedAt, id: { lt: input.cursor.eventId } },
|
|
733
|
+
],
|
|
734
|
+
}
|
|
735
|
+
: {
|
|
736
|
+
OR: [
|
|
737
|
+
{ createdAt: { lt: cursorCreatedAt } },
|
|
738
|
+
{ createdAt: cursorCreatedAt, eventSeq: { lt: cursorEventSeq } },
|
|
739
|
+
{
|
|
740
|
+
createdAt: cursorCreatedAt,
|
|
741
|
+
eventSeq: cursorEventSeq,
|
|
742
|
+
id: { lt: input.cursor.eventId },
|
|
743
|
+
},
|
|
744
|
+
],
|
|
745
|
+
});
|
|
710
746
|
}
|
|
711
747
|
return clauses.length > 0 ? { AND: clauses } : {};
|
|
712
748
|
}
|
|
@@ -744,7 +780,9 @@ function sessionFromPrisma(row) {
|
|
|
744
780
|
provider: row.modelProvider,
|
|
745
781
|
model: row.modelName,
|
|
746
782
|
...(row.thinkingLevel ? { thinkingLevel: row.thinkingLevel } : {}),
|
|
747
|
-
...(typeof metadataModel.authProfileId ===
|
|
783
|
+
...(typeof metadataModel.authProfileId === 'string'
|
|
784
|
+
? { authProfileId: metadataModel.authProfileId }
|
|
785
|
+
: {}),
|
|
748
786
|
...(metadataModel.reasoning === true ? { reasoning: true } : {}),
|
|
749
787
|
},
|
|
750
788
|
...(row.piSessionRef ? { piSessionFile: row.piSessionRef } : {}),
|
|
@@ -769,8 +807,8 @@ function turnFromPrisma(row) {
|
|
|
769
807
|
id: row.id,
|
|
770
808
|
sessionId: row.sessionId,
|
|
771
809
|
conversationId: row.conversationId,
|
|
772
|
-
userMessage: row.inputText ??
|
|
773
|
-
assistantMessage: row.outputText ??
|
|
810
|
+
userMessage: row.inputText ?? '',
|
|
811
|
+
assistantMessage: row.outputText ?? '',
|
|
774
812
|
model: parseModel(row.modelJson),
|
|
775
813
|
...(row.traceId ? { traceId: row.traceId } : {}),
|
|
776
814
|
createdAt: toIso(row.createdAt),
|
|
@@ -788,7 +826,7 @@ function messageFromPrisma(row, traceIdsByTurnId = new Map()) {
|
|
|
788
826
|
conversationId: row.conversationId,
|
|
789
827
|
...(row.turnId ? { turnId: row.turnId } : {}),
|
|
790
828
|
role: row.role,
|
|
791
|
-
text: row.contentText ??
|
|
829
|
+
text: row.contentText ?? '',
|
|
792
830
|
...(model ? { model } : {}),
|
|
793
831
|
...(traceId ? { traceId } : {}),
|
|
794
832
|
createdAt: toIso(row.createdAt),
|
|
@@ -807,13 +845,23 @@ function timelineEventFromPrisma(row) {
|
|
|
807
845
|
sessionId: row.sessionId,
|
|
808
846
|
...(row.turnId ? { turnId: row.turnId } : {}),
|
|
809
847
|
...(row.traceId ? { traceId: row.traceId } : {}),
|
|
810
|
-
...(typeof payloadObject.conversationId ===
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
...(typeof payloadObject.
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
...(typeof payloadObject.
|
|
848
|
+
...(typeof payloadObject.conversationId === 'string'
|
|
849
|
+
? { conversationId: payloadObject.conversationId }
|
|
850
|
+
: {}),
|
|
851
|
+
...(typeof payloadObject.toolCallId === 'string'
|
|
852
|
+
? { toolCallId: payloadObject.toolCallId }
|
|
853
|
+
: {}),
|
|
854
|
+
...(typeof payloadObject.parentSessionId === 'string'
|
|
855
|
+
? { parentSessionId: payloadObject.parentSessionId }
|
|
856
|
+
: {}),
|
|
857
|
+
...(typeof payloadObject.childSessionId === 'string'
|
|
858
|
+
? { childSessionId: payloadObject.childSessionId }
|
|
859
|
+
: {}),
|
|
860
|
+
...(typeof payloadObject.runId === 'string' ? { runId: payloadObject.runId } : {}),
|
|
861
|
+
...(typeof payloadObject.spawnBatchId === 'string'
|
|
862
|
+
? { spawnBatchId: payloadObject.spawnBatchId }
|
|
863
|
+
: {}),
|
|
864
|
+
...(typeof payloadObject.taskRunId === 'string' ? { taskRunId: payloadObject.taskRunId } : {}),
|
|
817
865
|
createdAt: toIso(row.createdAt),
|
|
818
866
|
payload,
|
|
819
867
|
};
|
|
@@ -845,14 +893,14 @@ function subagentFromPrisma(row) {
|
|
|
845
893
|
status: row.status,
|
|
846
894
|
depth: row.depth,
|
|
847
895
|
model: parseModel(row.modelJson),
|
|
848
|
-
toolPolicyProfile: row.toolPolicyProfile ??
|
|
849
|
-
context:
|
|
896
|
+
toolPolicyProfile: row.toolPolicyProfile ?? 'default',
|
|
897
|
+
context: 'isolated',
|
|
850
898
|
createdAt: toIso(row.createdAt),
|
|
851
899
|
updatedAt: toIso(row.updatedAt),
|
|
852
900
|
...(row.startedAt ? { startedAt: toIso(row.startedAt) } : {}),
|
|
853
901
|
...(row.endedAt ? { endedAt: toIso(row.endedAt) } : {}),
|
|
854
902
|
...(row.resultText ? { result: row.resultText } : {}),
|
|
855
|
-
...(typeof error.message ===
|
|
903
|
+
...(typeof error.message === 'string' ? { error: error.message } : {}),
|
|
856
904
|
events: subagentLifecycleEvents(row.status, row.createdAt, row.startedAt, row.endedAt),
|
|
857
905
|
};
|
|
858
906
|
}
|
|
@@ -869,7 +917,9 @@ function artifactFromPrisma(row) {
|
|
|
869
917
|
artifactType: row.artifactType,
|
|
870
918
|
...(row.name ? { name: row.name } : {}),
|
|
871
919
|
...(row.mimeType ? { mimeType: row.mimeType } : {}),
|
|
872
|
-
...(row.sizeBytes !== null && row.sizeBytes !== undefined
|
|
920
|
+
...(row.sizeBytes !== null && row.sizeBytes !== undefined
|
|
921
|
+
? { sizeBytes: Number(row.sizeBytes) }
|
|
922
|
+
: {}),
|
|
873
923
|
...(row.sha256 ? { sha256: row.sha256 } : {}),
|
|
874
924
|
storageUri: row.storageUri,
|
|
875
925
|
...(row.previewUri ? { previewUri: row.previewUri } : {}),
|
|
@@ -880,24 +930,24 @@ function artifactFromPrisma(row) {
|
|
|
880
930
|
function subagentLifecycleEvents(status, createdAt, startedAt, endedAt) {
|
|
881
931
|
const created = toIso(createdAt);
|
|
882
932
|
const events = [
|
|
883
|
-
{ type:
|
|
884
|
-
{ type:
|
|
933
|
+
{ type: 'subagent_spawning', at: created },
|
|
934
|
+
{ type: 'subagent_spawned', at: created },
|
|
885
935
|
];
|
|
886
936
|
if (startedAt) {
|
|
887
|
-
events.push({ type:
|
|
937
|
+
events.push({ type: 'subagent_started', at: toIso(startedAt) });
|
|
888
938
|
}
|
|
889
939
|
if (endedAt) {
|
|
890
|
-
const reason = isTerminalSubagentStatus(status) ? status :
|
|
891
|
-
events.push({ type:
|
|
940
|
+
const reason = isTerminalSubagentStatus(status) ? status : 'completed';
|
|
941
|
+
events.push({ type: 'subagent_ended', at: toIso(endedAt), reason });
|
|
892
942
|
}
|
|
893
943
|
return events;
|
|
894
944
|
}
|
|
895
945
|
function runtimeEventToTimeline(event) {
|
|
896
946
|
return {
|
|
897
947
|
eventId: event.id,
|
|
898
|
-
eventName:
|
|
948
|
+
eventName: 'runtime_event',
|
|
899
949
|
eventType: event.type,
|
|
900
|
-
eventSource:
|
|
950
|
+
eventSource: 'runtime',
|
|
901
951
|
sessionId: event.sessionId,
|
|
902
952
|
...(event.conversationId ? { conversationId: event.conversationId } : {}),
|
|
903
953
|
...(event.traceId ? { traceId: event.traceId } : {}),
|
|
@@ -915,7 +965,7 @@ function toolEventToTimeline(event) {
|
|
|
915
965
|
eventId: event.id,
|
|
916
966
|
eventName: `tool_call_${event.status}`,
|
|
917
967
|
eventType: event.status,
|
|
918
|
-
eventSource:
|
|
968
|
+
eventSource: 'tool',
|
|
919
969
|
sessionId: event.sessionId,
|
|
920
970
|
conversationId: event.conversationId,
|
|
921
971
|
...(event.traceId ? { traceId: event.traceId } : {}),
|
|
@@ -934,7 +984,7 @@ function llmEventToTimeline(event) {
|
|
|
934
984
|
eventId: event.id,
|
|
935
985
|
eventName: `llm_generation_${event.status}`,
|
|
936
986
|
eventType: event.status,
|
|
937
|
-
eventSource:
|
|
987
|
+
eventSource: 'llm',
|
|
938
988
|
sessionId: event.sessionId,
|
|
939
989
|
conversationId: event.conversationId,
|
|
940
990
|
...(event.traceId ? { traceId: event.traceId } : {}),
|
|
@@ -965,27 +1015,27 @@ function runtimeListInput(input) {
|
|
|
965
1015
|
function parseModel(value) {
|
|
966
1016
|
const model = parseJsonObject(value);
|
|
967
1017
|
return {
|
|
968
|
-
provider: typeof model.provider ===
|
|
969
|
-
model: typeof model.model ===
|
|
1018
|
+
provider: typeof model.provider === 'string' ? model.provider : 'unknown',
|
|
1019
|
+
model: typeof model.model === 'string' ? model.model : 'unknown',
|
|
970
1020
|
...(isThinkingLevel(model.thinkingLevel) ? { thinkingLevel: model.thinkingLevel } : {}),
|
|
971
|
-
...(typeof model.authProfileId ===
|
|
1021
|
+
...(typeof model.authProfileId === 'string' ? { authProfileId: model.authProfileId } : {}),
|
|
972
1022
|
...(model.reasoning === true ? { reasoning: true } : {}),
|
|
973
1023
|
};
|
|
974
1024
|
}
|
|
975
1025
|
function isThinkingLevel(value) {
|
|
976
|
-
return (value ===
|
|
977
|
-
value ===
|
|
978
|
-
value ===
|
|
979
|
-
value ===
|
|
980
|
-
value ===
|
|
981
|
-
value ===
|
|
1026
|
+
return (value === 'off' ||
|
|
1027
|
+
value === 'minimal' ||
|
|
1028
|
+
value === 'low' ||
|
|
1029
|
+
value === 'medium' ||
|
|
1030
|
+
value === 'high' ||
|
|
1031
|
+
value === 'xhigh');
|
|
982
1032
|
}
|
|
983
1033
|
function parseJsonObject(value) {
|
|
984
1034
|
const parsed = parseJsonValue(value);
|
|
985
1035
|
return isJsonObject(parsed) ? parsed : {};
|
|
986
1036
|
}
|
|
987
1037
|
function parseJsonValue(value) {
|
|
988
|
-
if (typeof value ===
|
|
1038
|
+
if (typeof value === 'string') {
|
|
989
1039
|
try {
|
|
990
1040
|
return JSON.parse(value);
|
|
991
1041
|
}
|
|
@@ -997,24 +1047,26 @@ function parseJsonValue(value) {
|
|
|
997
1047
|
}
|
|
998
1048
|
function parseStringArray(value) {
|
|
999
1049
|
const parsed = parseJsonValue(value);
|
|
1000
|
-
return Array.isArray(parsed)
|
|
1050
|
+
return Array.isArray(parsed)
|
|
1051
|
+
? parsed.filter((entry) => typeof entry === 'string')
|
|
1052
|
+
: [];
|
|
1001
1053
|
}
|
|
1002
1054
|
function parseStringRecord(value) {
|
|
1003
1055
|
const parsed = parseJsonValue(value);
|
|
1004
1056
|
if (!isJsonObject(parsed)) {
|
|
1005
1057
|
return {};
|
|
1006
1058
|
}
|
|
1007
|
-
return Object.fromEntries(Object.entries(parsed).filter((entry) => typeof entry[1] ===
|
|
1059
|
+
return Object.fromEntries(Object.entries(parsed).filter((entry) => typeof entry[1] === 'string'));
|
|
1008
1060
|
}
|
|
1009
1061
|
function isJsonObject(value) {
|
|
1010
|
-
return typeof value ===
|
|
1062
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
1011
1063
|
}
|
|
1012
1064
|
function isJsonValue(value) {
|
|
1013
1065
|
if (value === null) {
|
|
1014
1066
|
return true;
|
|
1015
1067
|
}
|
|
1016
1068
|
const type = typeof value;
|
|
1017
|
-
if (type ===
|
|
1069
|
+
if (type === 'string' || type === 'number' || type === 'boolean') {
|
|
1018
1070
|
return true;
|
|
1019
1071
|
}
|
|
1020
1072
|
if (Array.isArray(value)) {
|
|
@@ -1035,10 +1087,10 @@ function toIso(value) {
|
|
|
1035
1087
|
return value instanceof Date ? value.toISOString() : value;
|
|
1036
1088
|
}
|
|
1037
1089
|
function firstLine(value) {
|
|
1038
|
-
return value.trim().split(/\r?\n/, 1)[0]?.slice(0, 120) ??
|
|
1090
|
+
return value.trim().split(/\r?\n/, 1)[0]?.slice(0, 120) ?? '';
|
|
1039
1091
|
}
|
|
1040
1092
|
function stableRowId(prefix, ...parts) {
|
|
1041
|
-
const hash = createHash(
|
|
1093
|
+
const hash = createHash('sha256').update(parts.join('\0')).digest('hex').slice(0, 48);
|
|
1042
1094
|
return `${prefix}_${hash}`.slice(0, 64);
|
|
1043
1095
|
}
|
|
1044
1096
|
function positiveLimit(limit) {
|