@undefineds.co/xpod 0.3.46 → 0.3.49
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/bin/xpod.js +0 -0
- package/dist/api/chatkit/pod-store.d.ts +16 -17
- package/dist/api/chatkit/pod-store.js +299 -231
- package/dist/api/chatkit/pod-store.js.map +1 -1
- package/dist/api/chatkit/schema.d.ts +2 -2
- package/dist/api/chatkit/service.js +13 -11
- package/dist/api/chatkit/service.js.map +1 -1
- package/dist/api/chatkit/store.d.ts +1 -0
- package/dist/api/chatkit/store.js +23 -11
- package/dist/api/chatkit/store.js.map +1 -1
- package/dist/api/chatkit/types.d.ts +17 -10
- package/dist/api/chatkit/types.js +97 -14
- package/dist/api/chatkit/types.js.map +1 -1
- package/dist/api/container/common.js +16 -2
- package/dist/api/container/common.js.map +1 -1
- package/dist/api/container/routes.js +3 -0
- package/dist/api/container/routes.js.map +1 -1
- package/dist/api/container/types.d.ts +3 -0
- package/dist/api/container/types.js.map +1 -1
- package/dist/api/handlers/ChatKitV1Handler.js +1 -2
- package/dist/api/handlers/ChatKitV1Handler.js.map +1 -1
- package/dist/api/handlers/CoordinationHandler.d.ts +6 -0
- package/dist/api/handlers/CoordinationHandler.js +115 -0
- package/dist/api/handlers/CoordinationHandler.js.map +1 -0
- package/dist/api/handlers/MatrixHandler.d.ts +11 -0
- package/dist/api/handlers/MatrixHandler.js +120 -2
- package/dist/api/handlers/MatrixHandler.js.map +1 -1
- package/dist/api/handlers/RunHandler.js +33 -15
- package/dist/api/handlers/RunHandler.js.map +1 -1
- package/dist/api/handlers/index.d.ts +1 -0
- package/dist/api/handlers/index.js +1 -0
- package/dist/api/handlers/index.js.map +1 -1
- package/dist/api/index.d.ts +1 -0
- package/dist/api/index.js +1 -0
- package/dist/api/index.js.map +1 -1
- package/dist/api/matrix/PodMatrixStore.d.ts +25 -1
- package/dist/api/matrix/PodMatrixStore.js +243 -38
- package/dist/api/matrix/PodMatrixStore.js.map +1 -1
- package/dist/api/matrix/index.d.ts +1 -1
- package/dist/api/matrix/index.js.map +1 -1
- package/dist/api/matrix/types.d.ts +23 -2
- package/dist/api/matrix/types.js.map +1 -1
- package/dist/api/protocol-metadata.d.ts +4 -0
- package/dist/api/protocol-metadata.js +54 -0
- package/dist/api/protocol-metadata.js.map +1 -0
- package/dist/api/reconciler/ClientReconcilerCoordinator.d.ts +42 -0
- package/dist/api/reconciler/ClientReconcilerCoordinator.js +250 -0
- package/dist/api/reconciler/ClientReconcilerCoordinator.js.map +1 -0
- package/dist/api/reconciler/ClientReconcilerCoordinator.jsonld +186 -0
- package/dist/api/reconciler/ServerGroupReconcilerService.d.ts +39 -0
- package/dist/api/reconciler/ServerGroupReconcilerService.js +91 -0
- package/dist/api/reconciler/ServerGroupReconcilerService.js.map +1 -0
- package/dist/api/reconciler/ServerGroupReconcilerService.jsonld +146 -0
- package/dist/api/reconciler/WakeAgentQueue.d.ts +23 -0
- package/dist/api/reconciler/WakeAgentQueue.js +123 -0
- package/dist/api/reconciler/WakeAgentQueue.js.map +1 -0
- package/dist/api/reconciler/WakeAgentQueue.jsonld +91 -0
- package/dist/api/reconciler/coordination.d.ts +61 -0
- package/dist/api/reconciler/coordination.js +109 -0
- package/dist/api/reconciler/coordination.js.map +1 -0
- package/dist/api/reconciler/coordination.jsonld +186 -0
- package/dist/api/reconciler/index.d.ts +4 -0
- package/dist/api/reconciler/index.js +21 -0
- package/dist/api/reconciler/index.js.map +1 -0
- package/dist/api/runs/ManagedRunWorker.js +0 -5
- package/dist/api/runs/ManagedRunWorker.js.map +1 -1
- package/dist/api/runs/RunStateCenter.d.ts +1 -1
- package/dist/api/runs/RunStateCenter.js +12 -28
- package/dist/api/runs/RunStateCenter.js.map +1 -1
- package/dist/api/runs/store.d.ts +12 -15
- package/dist/api/runs/store.js +24 -15
- package/dist/api/runs/store.js.map +1 -1
- package/dist/api/tasks/TaskMaterializer.d.ts +1 -0
- package/dist/api/tasks/TaskMaterializer.js +10 -13
- package/dist/api/tasks/TaskMaterializer.js.map +1 -1
- package/dist/api/tasks/TaskService.d.ts +0 -2
- package/dist/api/tasks/TaskService.js +6 -16
- package/dist/api/tasks/TaskService.js.map +1 -1
- package/dist/api/tasks/schema.d.ts +0 -1
- package/dist/api/tasks/store.d.ts +0 -2
- package/dist/api/tasks/store.js.map +1 -1
- package/dist/cli/commands/auth.d.ts +1 -1
- package/dist/cli/commands/auth.js +4 -5
- package/dist/cli/commands/auth.js.map +1 -1
- package/dist/cli/commands/backup.js +1 -1
- package/dist/cli/commands/backup.js.map +1 -1
- package/dist/cli/commands/login.js +1 -1
- package/dist/cli/commands/login.js.map +1 -1
- package/dist/cli/commands/pod.js +1 -1
- package/dist/cli/commands/pod.js.map +1 -1
- package/dist/cli/lib/auth-helper.d.ts +5 -3
- package/dist/cli/lib/auth-helper.js +5 -3
- package/dist/cli/lib/auth-helper.js.map +1 -1
- package/dist/cli/lib/credentials-store.d.ts +22 -4
- package/dist/cli/lib/credentials-store.js +68 -51
- package/dist/cli/lib/credentials-store.js.map +1 -1
- package/dist/components/components.jsonld +5 -1
- package/dist/components/context.jsonld +103 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -1
- package/dist/provision/LocalPodProvisioningService.d.ts +1 -0
- package/dist/provision/LocalPodProvisioningService.js +9 -0
- package/dist/provision/LocalPodProvisioningService.js.map +1 -1
- package/dist/provision/LocalPodProvisioningService.jsonld +4 -0
- package/package.json +2 -2
|
@@ -7,10 +7,10 @@ exports.PodChatKitStore = void 0;
|
|
|
7
7
|
* 将 ChatKit 数据存储到 Solid Pod。
|
|
8
8
|
*
|
|
9
9
|
* 存储结构:
|
|
10
|
-
* /.data/{chat|task}/{
|
|
10
|
+
* /.data/{chat|task}/{parent-derived-id}/
|
|
11
11
|
* index.ttl
|
|
12
|
-
* #this # Chat (meeting:LongChat)
|
|
13
|
-
* #{threadId} # Thread (sioc:Thread)
|
|
12
|
+
* #this # Chat parent (meeting:LongChat)
|
|
13
|
+
* #{threadId} # Thread (sioc:Thread, sioc:has_parent)
|
|
14
14
|
* {yyyy}/{MM}/{dd}/messages.ttl # Messages (meeting:Message)
|
|
15
15
|
*/
|
|
16
16
|
const drizzle_solid_1 = require("@undefineds.co/drizzle-solid");
|
|
@@ -28,6 +28,8 @@ const model_1 = require("../../ai/schema/model");
|
|
|
28
28
|
const tables_1 = require("../../credential/schema/tables");
|
|
29
29
|
const types_2 = require("../../credential/schema/types");
|
|
30
30
|
const models_1 = require("@undefineds.co/models");
|
|
31
|
+
const reconciler_1 = require("../reconciler");
|
|
32
|
+
const protocol_metadata_1 = require("../protocol-metadata");
|
|
31
33
|
const schema = {
|
|
32
34
|
chat: schema_1.Chat,
|
|
33
35
|
thread: schema_1.Thread,
|
|
@@ -45,9 +47,8 @@ const schema = {
|
|
|
45
47
|
* 数据模型映射:
|
|
46
48
|
* - ChatKit thread = Thread (sioc:Thread)
|
|
47
49
|
* - ChatKit thread item = Message (meeting:Message)
|
|
48
|
-
* -
|
|
49
|
-
*
|
|
50
|
-
* 每个 Thread 属于一个 Chat 容器。默认使用 'default' Chat。
|
|
50
|
+
* - Thread 通过 sioc:has_parent 归属到 Chat 或 Task command surface。
|
|
51
|
+
* - ChatKit/API 的 opaque 字段不进入 Pod 持久 metadata;内部存储路径从 parent/id 派生。
|
|
51
52
|
*/
|
|
52
53
|
class PodChatKitStore {
|
|
53
54
|
constructor(options) {
|
|
@@ -55,6 +56,7 @@ class PodChatKitStore {
|
|
|
55
56
|
// Track recently created message IDs to avoid SELECT cache timing issues
|
|
56
57
|
this.recentlyCreatedIds = new Set();
|
|
57
58
|
this.tokenEndpoint = options.tokenEndpoint;
|
|
59
|
+
this.serverGroupReconcilerService = options.serverGroupReconcilerService;
|
|
58
60
|
}
|
|
59
61
|
// =========================================================================
|
|
60
62
|
// Private Helpers
|
|
@@ -337,17 +339,9 @@ class PodChatKitStore {
|
|
|
337
339
|
return { type: 'active' };
|
|
338
340
|
}
|
|
339
341
|
}
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
getSurfaceIdFromMetadata(metadata) {
|
|
344
|
-
if (metadata && typeof metadata.surface_id === 'string') {
|
|
345
|
-
return metadata.surface_id;
|
|
346
|
-
}
|
|
347
|
-
if (metadata && typeof metadata.chat_id === 'string') {
|
|
348
|
-
return metadata.chat_id;
|
|
349
|
-
}
|
|
350
|
-
return PodChatKitStore.DEFAULT_CHAT_ID;
|
|
342
|
+
readMetadataString(metadata, key) {
|
|
343
|
+
const value = metadata?.[key];
|
|
344
|
+
return typeof value === 'string' && value.trim() ? value.trim() : undefined;
|
|
351
345
|
}
|
|
352
346
|
isBaseRelativeChatResourceId(value) {
|
|
353
347
|
return typeof value === 'string'
|
|
@@ -361,6 +355,12 @@ class PodChatKitStore {
|
|
|
361
355
|
}
|
|
362
356
|
return `${chatId.replace(/^#/, '')}/index.ttl#this`;
|
|
363
357
|
}
|
|
358
|
+
buildMessageParentResourceId(surface) {
|
|
359
|
+
if (surface.commandKind === 'task') {
|
|
360
|
+
return `task/index.ttl#${surface.surfaceId}`;
|
|
361
|
+
}
|
|
362
|
+
return `chat/${surface.surfaceId}/index.ttl#this`;
|
|
363
|
+
}
|
|
364
364
|
chatSurfaceIdFromResourceId(chatId) {
|
|
365
365
|
if (!chatId) {
|
|
366
366
|
return undefined;
|
|
@@ -384,6 +384,136 @@ class PodChatKitStore {
|
|
|
384
384
|
}
|
|
385
385
|
return this.chatSurfaceIdFromResourceId(chat);
|
|
386
386
|
}
|
|
387
|
+
commandSurfaceFromResourceRef(resource) {
|
|
388
|
+
if (!resource) {
|
|
389
|
+
return undefined;
|
|
390
|
+
}
|
|
391
|
+
const parseRef = (ref, hash) => {
|
|
392
|
+
const normalizedHash = hash?.startsWith('#') ? hash.slice(1) : hash;
|
|
393
|
+
const trimmed = ref.replace(/^\/+/, '');
|
|
394
|
+
const dataIndex = trimmed.indexOf('.data/');
|
|
395
|
+
const dataRef = dataIndex >= 0 ? trimmed.slice(dataIndex + '.data/'.length) : trimmed;
|
|
396
|
+
const [pathPart, fragmentPart] = dataRef.split('#', 2);
|
|
397
|
+
const fragment = decodeURIComponent(normalizedHash || fragmentPart || '');
|
|
398
|
+
let match = pathPart.match(/^chat\/([^/]+)\/index\.ttl$/);
|
|
399
|
+
if (match && (!fragment || fragment === 'this')) {
|
|
400
|
+
return {
|
|
401
|
+
commandKind: 'chat',
|
|
402
|
+
surfaceId: decodeURIComponent(match[1]),
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
match = pathPart.match(/^task\/index\.ttl$/);
|
|
406
|
+
if (match && fragment) {
|
|
407
|
+
return {
|
|
408
|
+
commandKind: 'task',
|
|
409
|
+
surfaceId: fragment,
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
match = pathPart.match(/^(chat|task)\/([^/]+)(?:\/|$)/);
|
|
413
|
+
if (match) {
|
|
414
|
+
return {
|
|
415
|
+
commandKind: match[1] === 'task' ? 'task' : 'chat',
|
|
416
|
+
surfaceId: decodeURIComponent(match[2]),
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
return undefined;
|
|
420
|
+
};
|
|
421
|
+
try {
|
|
422
|
+
const url = new URL(resource);
|
|
423
|
+
return parseRef(url.pathname, url.hash);
|
|
424
|
+
}
|
|
425
|
+
catch {
|
|
426
|
+
return parseRef(resource);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
resolveTaskParentResource(taskRef, context) {
|
|
430
|
+
if (/^https?:\/\//.test(taskRef)) {
|
|
431
|
+
return taskRef;
|
|
432
|
+
}
|
|
433
|
+
if (taskRef.startsWith('task/')) {
|
|
434
|
+
return this.resolveDataResource(taskRef, context);
|
|
435
|
+
}
|
|
436
|
+
const podBaseUrl = this.ensurePodBaseUrlCache(context);
|
|
437
|
+
if (!podBaseUrl) {
|
|
438
|
+
throw new Error(`Cannot resolve Pod base URL for task parent: ${taskRef}`);
|
|
439
|
+
}
|
|
440
|
+
return (0, store_2.resolveTaskResource)(podBaseUrl, (0, store_2.buildTaskResourceId)(taskRef));
|
|
441
|
+
}
|
|
442
|
+
resolveExplicitThreadParentResource(parentRef, commandKind, context) {
|
|
443
|
+
if (/^https?:\/\//.test(parentRef)) {
|
|
444
|
+
return parentRef;
|
|
445
|
+
}
|
|
446
|
+
if (parentRef.startsWith('chat/') || parentRef.startsWith('task/')) {
|
|
447
|
+
return this.resolveDataResource(parentRef, context);
|
|
448
|
+
}
|
|
449
|
+
if (commandKind === 'task') {
|
|
450
|
+
return this.resolveTaskParentResource(parentRef, context);
|
|
451
|
+
}
|
|
452
|
+
return this.resolveDataResource(`chat/${parentRef}/index.ttl#this`, context);
|
|
453
|
+
}
|
|
454
|
+
resolveThreadParent(thread, context) {
|
|
455
|
+
const metadata = thread.metadata;
|
|
456
|
+
const explicitParent = thread.parent ?? this.readMetadataString(metadata, 'parent');
|
|
457
|
+
const taskRef = this.readMetadataString(metadata, 'task') ?? this.readMetadataString(metadata, 'taskId');
|
|
458
|
+
if (explicitParent) {
|
|
459
|
+
const derived = (0, types_1.getThreadParent)({ id: thread.id, parent: explicitParent });
|
|
460
|
+
const requestedCommandKind = derived?.kind ?? (taskRef ? 'task' : 'chat');
|
|
461
|
+
const parent = this.resolveExplicitThreadParentResource(explicitParent, requestedCommandKind, context);
|
|
462
|
+
const surface = this.commandSurfaceFromResourceRef(parent) ?? (derived
|
|
463
|
+
? { commandKind: derived.kind, surfaceId: derived.key }
|
|
464
|
+
: undefined);
|
|
465
|
+
if (surface) {
|
|
466
|
+
return { ...surface, parent };
|
|
467
|
+
}
|
|
468
|
+
return {
|
|
469
|
+
commandKind: requestedCommandKind,
|
|
470
|
+
surfaceId: PodChatKitStore.DEFAULT_CHAT_ID,
|
|
471
|
+
parent,
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
if (taskRef) {
|
|
475
|
+
const parent = this.resolveTaskParentResource(taskRef, context);
|
|
476
|
+
const surface = this.commandSurfaceFromResourceRef(parent);
|
|
477
|
+
return {
|
|
478
|
+
commandKind: 'task',
|
|
479
|
+
surfaceId: surface?.surfaceId ?? (0, store_1.extractResourceLocalId)(taskRef),
|
|
480
|
+
parent,
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
const derived = (0, types_1.getThreadParent)(thread);
|
|
484
|
+
if (derived) {
|
|
485
|
+
const parent = this.resolveExplicitThreadParentResource(derived.parent, derived.kind, context);
|
|
486
|
+
const surface = this.commandSurfaceFromResourceRef(parent);
|
|
487
|
+
return {
|
|
488
|
+
commandKind: surface?.commandKind ?? derived.kind,
|
|
489
|
+
surfaceId: surface?.surfaceId ?? derived.key,
|
|
490
|
+
parent,
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
const parent = this.resolveDataResource(`chat/${PodChatKitStore.DEFAULT_CHAT_ID}/index.ttl#this`, context);
|
|
494
|
+
return {
|
|
495
|
+
commandKind: 'chat',
|
|
496
|
+
surfaceId: PodChatKitStore.DEFAULT_CHAT_ID,
|
|
497
|
+
parent,
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
threadStoredMetadata(metadata) {
|
|
501
|
+
if (!metadata) {
|
|
502
|
+
return undefined;
|
|
503
|
+
}
|
|
504
|
+
const stored = { ...metadata };
|
|
505
|
+
delete stored.parent;
|
|
506
|
+
delete stored.chat_id;
|
|
507
|
+
delete stored.commandKind;
|
|
508
|
+
delete stored.surface_id;
|
|
509
|
+
delete stored.conversationKind;
|
|
510
|
+
return Object.keys(stored).length > 0 ? stored : undefined;
|
|
511
|
+
}
|
|
512
|
+
mentionsFromUserMessageContent(content) {
|
|
513
|
+
return (0, reconciler_1.normalizeAgentUris)(content
|
|
514
|
+
.filter((entry) => entry.type === 'input_tag')
|
|
515
|
+
.map((entry) => entry.tag));
|
|
516
|
+
}
|
|
387
517
|
/**
|
|
388
518
|
* 确保 Chat 容器存在,如果不存在则创建
|
|
389
519
|
*/
|
|
@@ -405,6 +535,7 @@ class PodChatKitStore {
|
|
|
405
535
|
title: surfaceId === PodChatKitStore.DEFAULT_CHAT_ID ? 'Default Chat' : surfaceId,
|
|
406
536
|
author: webId || null,
|
|
407
537
|
status: 'active',
|
|
538
|
+
metadata: (0, reconciler_1.reconcilerCoordinationMetadata)('client'),
|
|
408
539
|
createdAt: now,
|
|
409
540
|
updatedAt: now,
|
|
410
541
|
});
|
|
@@ -412,29 +543,28 @@ class PodChatKitStore {
|
|
|
412
543
|
}
|
|
413
544
|
}
|
|
414
545
|
/**
|
|
415
|
-
* 将 ThreadRecord 转为 ThreadMetadata
|
|
416
|
-
*
|
|
546
|
+
* 将 ThreadRecord 转为 ThreadMetadata。
|
|
547
|
+
* Pod 中以 thread.parent 作为权威归属关系,metadata 只返回业务扩展字段。
|
|
417
548
|
*/
|
|
418
|
-
threadRecordToMetadata(record
|
|
419
|
-
const extra = this.parseJsonObject(record.metadata);
|
|
420
|
-
const
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
549
|
+
threadRecordToMetadata(record) {
|
|
550
|
+
const extra = this.threadStoredMetadata(this.parseJsonObject(record.metadata));
|
|
551
|
+
const parent = record.parent
|
|
552
|
+
?? (0, types_1.getThreadParent)({ id: record.id })?.parent
|
|
553
|
+
?? (this.chatSurfaceIdFromResource(record.chat)
|
|
554
|
+
? `chat/${this.chatSurfaceIdFromResource(record.chat)}/index.ttl#this`
|
|
555
|
+
: undefined);
|
|
556
|
+
const reconcilerOwner = (0, reconciler_1.normalizeReconcilerOwner)(extra?.reconcilerOwner, 'client');
|
|
557
|
+
const coordination = (0, reconciler_1.reconcilerCoordinationMetadata)(reconcilerOwner);
|
|
425
558
|
return {
|
|
426
559
|
id: record.id,
|
|
560
|
+
parent,
|
|
427
561
|
title: record.title || undefined,
|
|
428
562
|
status: this.stringToStatus(record.status),
|
|
429
563
|
workspace: record.workspace || undefined,
|
|
564
|
+
...coordination,
|
|
430
565
|
created_at: record.createdAt ? Math.floor(new Date(record.createdAt).getTime() / 1000) : (0, types_1.nowTimestamp)(),
|
|
431
566
|
updated_at: record.updatedAt ? Math.floor(new Date(record.updatedAt).getTime() / 1000) : (0, types_1.nowTimestamp)(),
|
|
432
|
-
metadata:
|
|
433
|
-
...(extra ?? {}),
|
|
434
|
-
chat_id: surfaceId,
|
|
435
|
-
commandKind,
|
|
436
|
-
surface_id: surfaceId,
|
|
437
|
-
},
|
|
567
|
+
metadata: extra,
|
|
438
568
|
};
|
|
439
569
|
}
|
|
440
570
|
timestampToIso(timestamp) {
|
|
@@ -628,14 +758,11 @@ class PodChatKitStore {
|
|
|
628
758
|
}
|
|
629
759
|
runRecordToData(record) {
|
|
630
760
|
const metadata = this.parseJsonObject(record.metadata);
|
|
631
|
-
const xpod = this.getXpodMetadata(metadata);
|
|
632
761
|
return {
|
|
633
762
|
id: record.id || '',
|
|
634
|
-
surfaceId: record.surfaceId || (typeof xpod?.surfaceId === 'string' ? xpod.surfaceId : 'default'),
|
|
635
763
|
task: record.task || undefined,
|
|
636
764
|
thread: record.thread || '',
|
|
637
765
|
workspace: record.workspace || '',
|
|
638
|
-
commandKind: record.commandKind === 'task' || xpod?.commandKind === 'task' ? 'task' : 'chat',
|
|
639
766
|
status: (record.status || 'queued'),
|
|
640
767
|
runner: record.runner || '',
|
|
641
768
|
prompt: record.prompt || undefined,
|
|
@@ -652,14 +779,13 @@ class PodChatKitStore {
|
|
|
652
779
|
updatedAt: this.isoToTimestamp(record.updatedAt) ?? (0, types_1.nowTimestamp)(),
|
|
653
780
|
};
|
|
654
781
|
}
|
|
655
|
-
runStepRecordToData(record) {
|
|
782
|
+
runStepRecordToData(record, context) {
|
|
656
783
|
const payload = this.parseJsonObject(record.payload) ?? this.parseJsonObject(record.data);
|
|
657
|
-
const
|
|
784
|
+
const runId = record.runId
|
|
785
|
+
|| (record.run ? this.baseRelativeIdFromResource(record.run, context) : '');
|
|
658
786
|
return {
|
|
659
787
|
id: record.id || '',
|
|
660
|
-
|
|
661
|
-
surfaceId: record.surfaceId || (typeof xpod?.surfaceId === 'string' ? xpod.surfaceId : 'default'),
|
|
662
|
-
runId: record.runId || (typeof xpod?.runId === 'string' ? xpod.runId : ''),
|
|
788
|
+
runId,
|
|
663
789
|
run: record.run || '',
|
|
664
790
|
type: record.type || record.stepType || 'runtime.event',
|
|
665
791
|
message: record.message || undefined,
|
|
@@ -672,7 +798,6 @@ class PodChatKitStore {
|
|
|
672
798
|
const xpod = this.getXpodMetadata(metadata);
|
|
673
799
|
return {
|
|
674
800
|
id: record.id || '',
|
|
675
|
-
surfaceId: record.surfaceId || (typeof xpod?.surfaceId === 'string' ? xpod.surfaceId : 'default'),
|
|
676
801
|
title: record.title || undefined,
|
|
677
802
|
prompt: record.prompt || '',
|
|
678
803
|
thread: record.thread || '',
|
|
@@ -734,48 +859,6 @@ class PodChatKitStore {
|
|
|
734
859
|
};
|
|
735
860
|
}
|
|
736
861
|
}
|
|
737
|
-
/**
|
|
738
|
-
* 获取或构建 Chat resource -> surface id 的映射缓存。
|
|
739
|
-
* drizzle-solid 的 link(Chat) 字段返回完整资源引用,通过 Chat 的 @id 比对还原路径槽位。
|
|
740
|
-
*/
|
|
741
|
-
async getChatResourceMap(context) {
|
|
742
|
-
if (context._chatResourceMap) {
|
|
743
|
-
return context._chatResourceMap;
|
|
744
|
-
}
|
|
745
|
-
const db = await this.getDb(context);
|
|
746
|
-
const map = new Map();
|
|
747
|
-
if (db) {
|
|
748
|
-
try {
|
|
749
|
-
const chats = await db.select().from(schema_1.Chat);
|
|
750
|
-
for (const c of chats) {
|
|
751
|
-
const uri = c['@id'];
|
|
752
|
-
const surfaceId = this.chatSurfaceIdFromResourceId(c.id) ?? c.id;
|
|
753
|
-
if (uri)
|
|
754
|
-
map.set(uri, surfaceId);
|
|
755
|
-
}
|
|
756
|
-
}
|
|
757
|
-
catch {
|
|
758
|
-
// ignore
|
|
759
|
-
}
|
|
760
|
-
}
|
|
761
|
-
context._chatResourceMap = map;
|
|
762
|
-
return map;
|
|
763
|
-
}
|
|
764
|
-
/**
|
|
765
|
-
* 从 Chat resource 还原 surface id。
|
|
766
|
-
* 优先通过 @id 映射;若调用方本来给的是裸 ID,则原样使用。
|
|
767
|
-
*/
|
|
768
|
-
resolveChatSurfaceFromResource(chat, chatResourceMap, defaultSurfaceId) {
|
|
769
|
-
if (!chat)
|
|
770
|
-
return defaultSurfaceId;
|
|
771
|
-
const bare = chatResourceMap.get(chat);
|
|
772
|
-
if (bare)
|
|
773
|
-
return bare;
|
|
774
|
-
const parsed = this.chatSurfaceIdFromResource(chat);
|
|
775
|
-
if (parsed)
|
|
776
|
-
return parsed;
|
|
777
|
-
return chat.includes('/') ? defaultSurfaceId : chat;
|
|
778
|
-
}
|
|
779
862
|
isAbsoluteHttpResource(value) {
|
|
780
863
|
try {
|
|
781
864
|
const url = new URL(value);
|
|
@@ -841,24 +924,7 @@ class PodChatKitStore {
|
|
|
841
924
|
thread: threadResource,
|
|
842
925
|
};
|
|
843
926
|
}
|
|
844
|
-
|
|
845
|
-
throw new Error(`chat_id is required when thread_id "${threadRef}" is not a full thread resource id`);
|
|
846
|
-
}
|
|
847
|
-
const surfaceId = thread.chat_id;
|
|
848
|
-
const commandKind = 'chat';
|
|
849
|
-
const threadId = this.generateThreadResourceId({
|
|
850
|
-
key: threadRef,
|
|
851
|
-
commandKind,
|
|
852
|
-
surfaceId,
|
|
853
|
-
});
|
|
854
|
-
const threadResource = this.resolveDataResource(threadId, context);
|
|
855
|
-
this.cacheThreadSurfaceId(context, threadId, surfaceId);
|
|
856
|
-
return {
|
|
857
|
-
threadId,
|
|
858
|
-
commandKind,
|
|
859
|
-
surfaceId,
|
|
860
|
-
thread: threadResource,
|
|
861
|
-
};
|
|
927
|
+
throw new Error(`complete thread resource id is required, got "${threadRef}"`);
|
|
862
928
|
}
|
|
863
929
|
/**
|
|
864
930
|
* 缓存 Thread -> surfaceId 映射
|
|
@@ -903,65 +969,27 @@ class PodChatKitStore {
|
|
|
903
969
|
return binding?.[key]?.value ?? null;
|
|
904
970
|
}
|
|
905
971
|
async selectMessagesForThread(thread, context) {
|
|
906
|
-
await this.getDb(context);
|
|
907
|
-
|
|
908
|
-
const podBaseUrl = this.getCachedPodBaseUrl(context);
|
|
909
|
-
if (!cachedFetch || !podBaseUrl) {
|
|
972
|
+
const db = await this.getDb(context);
|
|
973
|
+
if (!db) {
|
|
910
974
|
return [];
|
|
911
975
|
}
|
|
912
976
|
const resolvedThread = await this.resolveThreadRef(thread, context);
|
|
913
|
-
const
|
|
914
|
-
const query = `
|
|
915
|
-
PREFIX meeting: <http://www.w3.org/ns/pim/meeting#>
|
|
916
|
-
PREFIX sioc: <http://rdfs.org/sioc/ns#>
|
|
917
|
-
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
|
|
918
|
-
PREFIX dcterms: <http://purl.org/dc/terms/>
|
|
919
|
-
PREFIX udfs: <https://undefineds.co/ns#>
|
|
920
|
-
SELECT ?msg ?maker ?messageType ?legacyRole ?content ?messageStatus ?legacyStatus ?createdAt ?legacyCreatedAt ?toolName ?toolCallId ?metadata
|
|
921
|
-
WHERE {
|
|
922
|
-
<${resolvedThread.thread}> sioc:has_member ?msg .
|
|
923
|
-
?msg a meeting:Message .
|
|
924
|
-
OPTIONAL { ?msg foaf:maker ?maker . }
|
|
925
|
-
OPTIONAL { ?msg udfs:messageType ?messageType . }
|
|
926
|
-
OPTIONAL { ?msg udfs:role ?legacyRole . }
|
|
927
|
-
OPTIONAL { ?msg sioc:content ?content . }
|
|
928
|
-
OPTIONAL { ?msg udfs:messageStatus ?messageStatus . }
|
|
929
|
-
OPTIONAL { ?msg udfs:status ?legacyStatus . }
|
|
930
|
-
OPTIONAL { ?msg dcterms:created ?createdAt . }
|
|
931
|
-
OPTIONAL { ?msg udfs:createdAt ?legacyCreatedAt . }
|
|
932
|
-
OPTIONAL { ?msg udfs:toolName ?toolName . }
|
|
933
|
-
OPTIONAL { ?msg udfs:toolCallId ?toolCallId . }
|
|
934
|
-
OPTIONAL { ?msg udfs:metadata ?metadata . }
|
|
935
|
-
}
|
|
936
|
-
ORDER BY ?createdAt
|
|
937
|
-
`.trim();
|
|
938
|
-
const response = await cachedFetch(endpoint, {
|
|
939
|
-
method: 'POST',
|
|
940
|
-
headers: {
|
|
941
|
-
'Content-Type': 'application/sparql-query',
|
|
942
|
-
Accept: 'application/sparql-results+json',
|
|
943
|
-
},
|
|
944
|
-
body: query,
|
|
945
|
-
});
|
|
946
|
-
if (!response.ok) {
|
|
947
|
-
const text = await response.text().catch(() => '');
|
|
948
|
-
throw new Error(`Failed to query thread messages: ${response.status} ${response.statusText} - ${text}`);
|
|
949
|
-
}
|
|
950
|
-
const json = await response.json();
|
|
951
|
-
const bindings = json.results?.bindings ?? [];
|
|
952
|
-
return bindings.map((binding) => ({
|
|
953
|
-
id: this.baseRelativeIdFromResource(this.parseSparqlBindingValue(binding, 'msg') ?? '', context),
|
|
954
|
-
chat: null,
|
|
977
|
+
const records = await models_1.messageRepository.list(db, {
|
|
955
978
|
thread: resolvedThread.thread,
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
979
|
+
});
|
|
980
|
+
return records.map((record) => ({
|
|
981
|
+
id: record.id || '',
|
|
982
|
+
chat: record.chat || null,
|
|
983
|
+
thread: record.thread || resolvedThread.thread,
|
|
984
|
+
maker: record.maker || null,
|
|
985
|
+
role: record.role || null,
|
|
986
|
+
content: record.content || null,
|
|
987
|
+
status: record.status || null,
|
|
988
|
+
createdAt: record.createdAt || null,
|
|
989
|
+
toolName: record.toolName || null,
|
|
990
|
+
toolCallId: record.toolCallId || null,
|
|
991
|
+
metadata: record.metadata || null,
|
|
992
|
+
resource: record.id ? this.resolveDataResource(record.id, context) : null,
|
|
965
993
|
}));
|
|
966
994
|
}
|
|
967
995
|
datePathFromTimestamp(timestamp) {
|
|
@@ -983,12 +1011,13 @@ class PodChatKitStore {
|
|
|
983
1011
|
});
|
|
984
1012
|
}
|
|
985
1013
|
generateItemId(itemType, thread, _context) {
|
|
986
|
-
const
|
|
987
|
-
|
|
1014
|
+
const surface = this.commandSurfaceFromResourceRef(thread.parent)
|
|
1015
|
+
?? this.commandSurfaceFromResourceRef(thread.id)
|
|
1016
|
+
?? { commandKind: 'chat', surfaceId: PodChatKitStore.DEFAULT_CHAT_ID };
|
|
988
1017
|
return this.generateMessageResourceId({
|
|
989
1018
|
key: (0, types_1.generateId)(itemType.replace('_', '-')),
|
|
990
|
-
commandKind,
|
|
991
|
-
surfaceId,
|
|
1019
|
+
commandKind: surface.commandKind,
|
|
1020
|
+
surfaceId: surface.surfaceId,
|
|
992
1021
|
});
|
|
993
1022
|
}
|
|
994
1023
|
// =========================================================================
|
|
@@ -1010,11 +1039,13 @@ class PodChatKitStore {
|
|
|
1010
1039
|
if (!threadRecord) {
|
|
1011
1040
|
throw new Error(`Thread not found: ${resolvedThread.threadId}`);
|
|
1012
1041
|
}
|
|
1013
|
-
const
|
|
1014
|
-
const metadata = this.threadRecordToMetadata(threadRecord, chatResourceMap);
|
|
1042
|
+
const metadata = this.threadRecordToMetadata(threadRecord);
|
|
1015
1043
|
// 缓存结果
|
|
1016
1044
|
this.cacheThreadMetadata(context, metadata);
|
|
1017
|
-
this.
|
|
1045
|
+
const surface = this.commandSurfaceFromResourceRef(metadata.parent) ?? this.commandSurfaceFromResourceRef(metadata.id);
|
|
1046
|
+
if (surface) {
|
|
1047
|
+
this.cacheThreadSurfaceId(context, metadata.id, surface.surfaceId);
|
|
1048
|
+
}
|
|
1018
1049
|
return metadata;
|
|
1019
1050
|
}
|
|
1020
1051
|
async saveThread(thread, context) {
|
|
@@ -1023,15 +1054,16 @@ class PodChatKitStore {
|
|
|
1023
1054
|
throw new Error('Cannot access Pod: invalid credentials');
|
|
1024
1055
|
}
|
|
1025
1056
|
const now = new Date().toISOString();
|
|
1026
|
-
const
|
|
1027
|
-
const
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1057
|
+
const parent = this.resolveThreadParent(thread, context);
|
|
1058
|
+
const commandKind = parent.commandKind;
|
|
1059
|
+
const surfaceId = parent.surfaceId;
|
|
1060
|
+
const reconcilerOwner = (0, reconciler_1.normalizeReconcilerOwner)(thread.metadata?.reconcilerOwner ?? thread.reconcilerOwner, 'client');
|
|
1061
|
+
const coordination = (0, reconciler_1.reconcilerCoordinationMetadata)(reconcilerOwner);
|
|
1062
|
+
const storedMetadata = (0, reconciler_1.withReconcilerCoordinationMetadata)(this.threadStoredMetadata(thread.metadata), reconcilerOwner);
|
|
1063
|
+
thread.parent = parent.parent;
|
|
1064
|
+
thread.reconcilerOwner = coordination.reconcilerOwner;
|
|
1065
|
+
thread.metadata = storedMetadata;
|
|
1066
|
+
const metadataObject = this.jsonObjectOrNull(storedMetadata);
|
|
1035
1067
|
if (commandKind === 'chat') {
|
|
1036
1068
|
await this.ensureChat(surfaceId, context);
|
|
1037
1069
|
}
|
|
@@ -1048,8 +1080,7 @@ class PodChatKitStore {
|
|
|
1048
1080
|
if (existing) {
|
|
1049
1081
|
// Update
|
|
1050
1082
|
await db.updateByIri(schema_1.Thread, threadResource, {
|
|
1051
|
-
|
|
1052
|
-
task: commandKind === 'task' ? (0, store_2.buildTaskResourceId)(`index.ttl#${surfaceId}`) : null,
|
|
1083
|
+
parent: parent.parent,
|
|
1053
1084
|
title: thread.title || null,
|
|
1054
1085
|
status: this.statusToString(thread.status),
|
|
1055
1086
|
workspace: thread.workspace || null,
|
|
@@ -1061,8 +1092,7 @@ class PodChatKitStore {
|
|
|
1061
1092
|
// Insert
|
|
1062
1093
|
await db.insert(schema_1.Thread).values({
|
|
1063
1094
|
id: threadResourceId,
|
|
1064
|
-
|
|
1065
|
-
task: commandKind === 'task' ? (0, store_2.buildTaskResourceId)(`index.ttl#${surfaceId}`) : null,
|
|
1095
|
+
parent: parent.parent,
|
|
1066
1096
|
title: thread.title || null,
|
|
1067
1097
|
status: this.statusToString(thread.status),
|
|
1068
1098
|
workspace: thread.workspace || null,
|
|
@@ -1071,15 +1101,12 @@ class PodChatKitStore {
|
|
|
1071
1101
|
updatedAt: now,
|
|
1072
1102
|
});
|
|
1073
1103
|
}
|
|
1074
|
-
// 缓存完整的 Thread metadata
|
|
1104
|
+
// 缓存完整的 Thread metadata;metadata 不包含协议兼容字段。
|
|
1075
1105
|
const threadMetadata = {
|
|
1076
1106
|
...thread,
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
surface_id: surfaceId,
|
|
1081
|
-
chat_id: surfaceId,
|
|
1082
|
-
},
|
|
1107
|
+
parent: parent.parent,
|
|
1108
|
+
...coordination,
|
|
1109
|
+
metadata: storedMetadata,
|
|
1083
1110
|
};
|
|
1084
1111
|
this.cacheThreadMetadata(context, threadMetadata);
|
|
1085
1112
|
}
|
|
@@ -1089,11 +1116,10 @@ class PodChatKitStore {
|
|
|
1089
1116
|
return { data: [], has_more: false };
|
|
1090
1117
|
}
|
|
1091
1118
|
try {
|
|
1092
|
-
const threads = await
|
|
1093
|
-
const chatResourceMap = await this.getChatResourceMap(context);
|
|
1119
|
+
const threads = await models_1.threadRepository.list(db);
|
|
1094
1120
|
const metadataById = new Map();
|
|
1095
1121
|
for (const thread of threads) {
|
|
1096
|
-
const metadata = this.threadRecordToMetadata(thread
|
|
1122
|
+
const metadata = this.threadRecordToMetadata(thread);
|
|
1097
1123
|
metadataById.set(metadata.id, metadata);
|
|
1098
1124
|
}
|
|
1099
1125
|
for (const cached of this.getCachedThreadMetadataList(context)) {
|
|
@@ -1211,17 +1237,22 @@ class PodChatKitStore {
|
|
|
1211
1237
|
const webId = this.getWebId(context);
|
|
1212
1238
|
let content = '';
|
|
1213
1239
|
let role = schema_1.MessageRole.USER;
|
|
1214
|
-
let status =
|
|
1240
|
+
let status = schema_1.MessageStatus.COMPLETED;
|
|
1215
1241
|
let toolName = null;
|
|
1216
1242
|
let toolCallId = null;
|
|
1217
1243
|
let metadata = null;
|
|
1244
|
+
let mentions = [];
|
|
1245
|
+
const threadMetadata = await this.loadThread({ thread_id: resolvedThread.threadId }, context).catch(() => undefined);
|
|
1246
|
+
const reconcilerOwner = (0, reconciler_1.normalizeReconcilerOwner)(threadMetadata?.metadata?.reconcilerOwner ?? threadMetadata?.reconcilerOwner, 'client');
|
|
1218
1247
|
if (item.type === 'user_message') {
|
|
1219
1248
|
const userItem = item;
|
|
1220
1249
|
content = userItem.content
|
|
1221
1250
|
.filter((c) => c.type === 'input_text')
|
|
1222
1251
|
.map((c) => c.text)
|
|
1223
1252
|
.join('\n');
|
|
1253
|
+
mentions = this.mentionsFromUserMessageContent(userItem.content);
|
|
1224
1254
|
role = schema_1.MessageRole.USER;
|
|
1255
|
+
status = schema_1.MessageStatus.SENT;
|
|
1225
1256
|
}
|
|
1226
1257
|
else if (item.type === 'assistant_message') {
|
|
1227
1258
|
const assistantItem = item;
|
|
@@ -1249,9 +1280,23 @@ class PodChatKitStore {
|
|
|
1249
1280
|
// 其他类型暂时存储为 JSON
|
|
1250
1281
|
content = JSON.stringify(item);
|
|
1251
1282
|
role = schema_1.MessageRole.SYSTEM;
|
|
1252
|
-
|
|
1283
|
+
status = schema_1.MessageStatus.COMPLETED;
|
|
1284
|
+
}
|
|
1285
|
+
const durableMessageMetadata = (0, protocol_metadata_1.withProtocolMetadata)((0, reconciler_1.withReconcilerCoordinationMetadata)((0, protocol_metadata_1.withoutProtocolProjectionKeys)(metadata ?? undefined, [
|
|
1286
|
+
'chat_id',
|
|
1287
|
+
'thread_id',
|
|
1288
|
+
'item_id',
|
|
1289
|
+
'commandKind',
|
|
1290
|
+
'surface_id',
|
|
1291
|
+
'conversationKind',
|
|
1292
|
+
]), reconcilerOwner), 'chatkit', {
|
|
1293
|
+
chat_id: resolvedThread.surfaceId,
|
|
1294
|
+
thread_id: resolvedThread.threadId,
|
|
1295
|
+
item_id: itemResourceId,
|
|
1296
|
+
});
|
|
1253
1297
|
const messageRecord = {
|
|
1254
1298
|
id: itemResourceId,
|
|
1299
|
+
parent: this.resolveDataResource(this.buildMessageParentResourceId(resolvedThread), context),
|
|
1255
1300
|
chat: resolvedThread.commandKind === 'chat' ? this.buildChatResourceId(resolvedThread.surfaceId) : null,
|
|
1256
1301
|
thread: resolvedThread.thread,
|
|
1257
1302
|
maker: role === schema_1.MessageRole.USER ? webId : null,
|
|
@@ -1260,18 +1305,41 @@ class PodChatKitStore {
|
|
|
1260
1305
|
status,
|
|
1261
1306
|
toolName,
|
|
1262
1307
|
toolCallId,
|
|
1263
|
-
metadata: this.jsonObjectOrNull(
|
|
1264
|
-
...(metadata ?? {}),
|
|
1265
|
-
commandKind: resolvedThread.commandKind,
|
|
1266
|
-
surface_id: resolvedThread.surfaceId,
|
|
1267
|
-
chat_id: resolvedThread.surfaceId,
|
|
1268
|
-
}),
|
|
1308
|
+
metadata: this.jsonObjectOrNull(durableMessageMetadata),
|
|
1269
1309
|
createdAt: new Date(item.created_at * 1000).toISOString(),
|
|
1270
1310
|
};
|
|
1271
1311
|
await db.insert(schema_1.Message).values(messageRecord);
|
|
1312
|
+
await this.reconcileGroupUserMessage({
|
|
1313
|
+
thread: resolvedThread.thread,
|
|
1314
|
+
triggerMessage: this.resolveDataResource(itemResourceId, context),
|
|
1315
|
+
actor: String(webId ?? context.userId),
|
|
1316
|
+
role,
|
|
1317
|
+
content,
|
|
1318
|
+
reconcilerOwner,
|
|
1319
|
+
mentions,
|
|
1320
|
+
});
|
|
1272
1321
|
// Track this ID to avoid cache timing issues in saveItem
|
|
1273
1322
|
this.recentlyCreatedIds.add(item.id);
|
|
1274
1323
|
}
|
|
1324
|
+
async reconcileGroupUserMessage(input) {
|
|
1325
|
+
if (!this.serverGroupReconcilerService || input.role !== schema_1.MessageRole.USER) {
|
|
1326
|
+
return;
|
|
1327
|
+
}
|
|
1328
|
+
try {
|
|
1329
|
+
await this.serverGroupReconcilerService.reconcileThreadMessage({
|
|
1330
|
+
thread: input.thread,
|
|
1331
|
+
triggerMessage: input.triggerMessage,
|
|
1332
|
+
actor: input.actor,
|
|
1333
|
+
role: 'user',
|
|
1334
|
+
content: input.content,
|
|
1335
|
+
reconcilerOwner: input.reconcilerOwner,
|
|
1336
|
+
mentions: input.mentions,
|
|
1337
|
+
});
|
|
1338
|
+
}
|
|
1339
|
+
catch (error) {
|
|
1340
|
+
this.logger.warn(`Failed to enqueue ChatKit group Reconciler wake: ${error}`);
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1275
1343
|
async saveItem(thread, item, context) {
|
|
1276
1344
|
const db = await this.getDb(context);
|
|
1277
1345
|
if (!db) {
|
|
@@ -1463,10 +1531,6 @@ WHERE { ${deletePatterns.join(' ')} }
|
|
|
1463
1531
|
}
|
|
1464
1532
|
run.id = (0, store_1.buildRunResourceId)(run);
|
|
1465
1533
|
const existing = await db.findById(schema_2.Run, run.id);
|
|
1466
|
-
const metadata = this.withXpodMetadata(run.metadata, {
|
|
1467
|
-
commandKind: run.commandKind,
|
|
1468
|
-
surfaceId: run.surfaceId,
|
|
1469
|
-
});
|
|
1470
1534
|
const values = {
|
|
1471
1535
|
task: run.task || null,
|
|
1472
1536
|
thread: run.thread,
|
|
@@ -1480,7 +1544,7 @@ WHERE { ${deletePatterns.join(' ')} }
|
|
|
1480
1544
|
heartbeatAt: this.timestampToIso(run.heartbeatAt),
|
|
1481
1545
|
cancelRequestedAt: this.timestampToIso(run.cancelRequestedAt),
|
|
1482
1546
|
error: run.error || null,
|
|
1483
|
-
metadata: this.jsonObjectOrNull(metadata),
|
|
1547
|
+
metadata: this.jsonObjectOrNull(run.metadata),
|
|
1484
1548
|
createdAt: this.timestampToIso(run.createdAt) ?? new Date().toISOString(),
|
|
1485
1549
|
startedAt: this.timestampToIso(run.startedAt),
|
|
1486
1550
|
completedAt: this.timestampToIso(run.completedAt),
|
|
@@ -1528,10 +1592,7 @@ WHERE { ${deletePatterns.join(' ')} }
|
|
|
1528
1592
|
const records = conditions.length > 0
|
|
1529
1593
|
? await query.where((0, drizzle_solid_1.and)(...conditions))
|
|
1530
1594
|
: await query;
|
|
1531
|
-
|
|
1532
|
-
if (options.commandKind) {
|
|
1533
|
-
runs = runs.filter((run) => run.commandKind === options.commandKind);
|
|
1534
|
-
}
|
|
1595
|
+
const runs = records.map((record) => this.runRecordToData(record));
|
|
1535
1596
|
return runs
|
|
1536
1597
|
.sort((a, b) => b.createdAt - a.createdAt || b.id.localeCompare(a.id))
|
|
1537
1598
|
.slice(0, options.limit ?? runs.length);
|
|
@@ -1545,16 +1606,13 @@ WHERE { ${deletePatterns.join(' ')} }
|
|
|
1545
1606
|
throw new Error(`RunStep runId must be a complete Run resource id: ${event.runId}`);
|
|
1546
1607
|
}
|
|
1547
1608
|
event.id = (0, store_1.buildRunStepResourceId)(event);
|
|
1609
|
+
const runResource = event.run || this.resolveDataResource(event.runId, context);
|
|
1548
1610
|
await db.insert(schema_2.RunStep).values({
|
|
1549
1611
|
id: event.id,
|
|
1550
|
-
run: event.run,
|
|
1551
1612
|
stepType: event.type,
|
|
1613
|
+
run: runResource,
|
|
1552
1614
|
message: event.message || null,
|
|
1553
|
-
payload: this.jsonObjectOrNull(
|
|
1554
|
-
commandKind: event.commandKind,
|
|
1555
|
-
surfaceId: event.surfaceId,
|
|
1556
|
-
runId: event.runId,
|
|
1557
|
-
})),
|
|
1615
|
+
payload: this.jsonObjectOrNull(event.data),
|
|
1558
1616
|
createdAt: this.timestampToIso(event.createdAt) ?? new Date().toISOString(),
|
|
1559
1617
|
});
|
|
1560
1618
|
}
|
|
@@ -1566,9 +1624,10 @@ WHERE { ${deletePatterns.join(' ')} }
|
|
|
1566
1624
|
if (!(0, store_1.isRunResourceId)(runId)) {
|
|
1567
1625
|
throw new Error(`loadRunSteps requires a base-relative Run id: ${runId}`);
|
|
1568
1626
|
}
|
|
1569
|
-
const
|
|
1627
|
+
const resolvedRun = this.resolveDataResource(runId, context);
|
|
1628
|
+
const records = await db.select().from(schema_2.RunStep).where((0, drizzle_solid_1.eq)(schema_2.RunStep.run, resolvedRun));
|
|
1570
1629
|
return records
|
|
1571
|
-
.map((record) => this.runStepRecordToData(record))
|
|
1630
|
+
.map((record) => this.runStepRecordToData(record, context))
|
|
1572
1631
|
.sort((a, b) => a.createdAt - b.createdAt || a.id.localeCompare(b.id));
|
|
1573
1632
|
}
|
|
1574
1633
|
async claimRun(input, context) {
|
|
@@ -1595,7 +1654,6 @@ WHERE { ${deletePatterns.join(' ')} }
|
|
|
1595
1654
|
task.id = (0, store_2.buildTaskResourceId)(task.id);
|
|
1596
1655
|
const existing = await db.findById(schema_3.Task, task.id);
|
|
1597
1656
|
const metadata = this.withXpodMetadata(this.withTaskAuthBindingMetadata(task.metadata, task.authBinding), {
|
|
1598
|
-
surfaceId: task.surfaceId,
|
|
1599
1657
|
runner: task.runner,
|
|
1600
1658
|
triggerKind: task.triggerKind,
|
|
1601
1659
|
cron: task.cron ?? null,
|
|
@@ -1859,21 +1917,24 @@ WHERE { ${deletePatterns.join(' ')} }
|
|
|
1859
1917
|
}
|
|
1860
1918
|
const endpoint = `${podBaseUrl.replace(/\/$/, '')}/settings/-/sparql`;
|
|
1861
1919
|
const query = `
|
|
1920
|
+
PREFIX cred: <https://vocab.xpod.dev/credential#>
|
|
1921
|
+
PREFIX ai: <https://vocab.xpod.dev/ai#>
|
|
1862
1922
|
PREFIX udfs: <https://undefineds.co/ns#>
|
|
1863
|
-
SELECT ?cred ?provider ?apiKey ?isDefault ?lastUsedAt ?failCount ?
|
|
1923
|
+
SELECT ?cred ?provider ?apiKey ?isDefault ?lastUsedAt ?failCount ?providerBaseUrl ?credentialBaseUrl ?providerProxyUrl ?credentialProxyUrl ?defaultModel ?hasModel
|
|
1864
1924
|
WHERE {
|
|
1865
|
-
?cred
|
|
1866
|
-
udfs:
|
|
1867
|
-
udfs:
|
|
1868
|
-
|
|
1869
|
-
OPTIONAL { ?cred udfs:
|
|
1870
|
-
OPTIONAL { ?cred udfs:
|
|
1871
|
-
OPTIONAL { ?cred udfs:
|
|
1872
|
-
OPTIONAL { ?cred udfs:
|
|
1873
|
-
OPTIONAL { ?
|
|
1874
|
-
OPTIONAL { ?provider udfs:
|
|
1875
|
-
OPTIONAL { ?provider udfs:
|
|
1876
|
-
OPTIONAL { ?provider udfs:
|
|
1925
|
+
?cred (cred:service|udfs:service) "ai" ;
|
|
1926
|
+
(cred:status|udfs:status) "active" ;
|
|
1927
|
+
(cred:apiKey|udfs:apiKey) ?apiKey .
|
|
1928
|
+
OPTIONAL { ?cred (cred:provider|udfs:provider) ?provider . }
|
|
1929
|
+
OPTIONAL { ?cred (cred:isDefault|udfs:isDefault) ?isDefault . }
|
|
1930
|
+
OPTIONAL { ?cred (cred:lastUsedAt|udfs:lastUsedAt) ?lastUsedAt . }
|
|
1931
|
+
OPTIONAL { ?cred (cred:failCount|udfs:failCount) ?failCount . }
|
|
1932
|
+
OPTIONAL { ?cred (cred:baseUrl|udfs:baseUrl) ?credentialBaseUrl . }
|
|
1933
|
+
OPTIONAL { ?cred (cred:proxyUrl|udfs:proxyUrl) ?credentialProxyUrl . }
|
|
1934
|
+
OPTIONAL { ?provider (ai:baseUrl|udfs:baseUrl) ?providerBaseUrl . }
|
|
1935
|
+
OPTIONAL { ?provider (ai:proxyUrl|udfs:proxyUrl) ?providerProxyUrl . }
|
|
1936
|
+
OPTIONAL { ?provider (ai:defaultModel|udfs:defaultModel) ?defaultModel . }
|
|
1937
|
+
OPTIONAL { ?provider (ai:hasModel|udfs:hasModel) ?hasModel . }
|
|
1877
1938
|
}
|
|
1878
1939
|
`.trim();
|
|
1879
1940
|
const response = await cachedFetch(endpoint, {
|
|
@@ -1900,8 +1961,10 @@ WHERE { ${deletePatterns.join(' ')} }
|
|
|
1900
1961
|
isDefault: this.parseSparqlBindingValue(binding, 'isDefault'),
|
|
1901
1962
|
lastUsedAt: this.parseSparqlBindingValue(binding, 'lastUsedAt'),
|
|
1902
1963
|
failCount: this.parseIntegerValue(this.parseSparqlBindingValue(binding, 'failCount')),
|
|
1903
|
-
baseUrl: this.parseSparqlBindingValue(binding, '
|
|
1904
|
-
|
|
1964
|
+
baseUrl: this.parseSparqlBindingValue(binding, 'providerBaseUrl')
|
|
1965
|
+
?? this.parseSparqlBindingValue(binding, 'credentialBaseUrl'),
|
|
1966
|
+
proxyUrl: this.parseSparqlBindingValue(binding, 'providerProxyUrl')
|
|
1967
|
+
?? this.parseSparqlBindingValue(binding, 'credentialProxyUrl'),
|
|
1905
1968
|
defaultModel: this.parseSparqlBindingValue(binding, 'defaultModel')
|
|
1906
1969
|
?? this.parseSparqlBindingValue(binding, 'hasModel'),
|
|
1907
1970
|
};
|
|
@@ -1933,9 +1996,14 @@ WHERE { ${deletePatterns.join(' ')} }
|
|
|
1933
1996
|
}
|
|
1934
1997
|
this.ensurePodBaseUrlCache(context, db);
|
|
1935
1998
|
try {
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1999
|
+
try {
|
|
2000
|
+
const sparqlConfig = await this.queryAiConfigFromSettingsSparql(context);
|
|
2001
|
+
if (sparqlConfig !== null) {
|
|
2002
|
+
return sparqlConfig ?? undefined;
|
|
2003
|
+
}
|
|
2004
|
+
}
|
|
2005
|
+
catch (error) {
|
|
2006
|
+
this.logger.warn(`Failed to read AI config via settings SPARQL, falling back to model tables: ${error}`);
|
|
1939
2007
|
}
|
|
1940
2008
|
// 查询活跃的 AI 凭据
|
|
1941
2009
|
const credentials = await db.select()
|
|
@@ -2035,7 +2103,7 @@ WHERE { ${deletePatterns.join(' ')} }
|
|
|
2035
2103
|
catch (error) {
|
|
2036
2104
|
this.logger.warn(`Failed to load Pod models for ${config.providerId}: ${error}`);
|
|
2037
2105
|
}
|
|
2038
|
-
if (config.defaultModel) {
|
|
2106
|
+
if (config.defaultModel && !seenModelIds.has(config.defaultModel)) {
|
|
2039
2107
|
this.pushAvailableModel(models, seenModelIds, {
|
|
2040
2108
|
id: config.defaultModel,
|
|
2041
2109
|
name: config.defaultModel,
|