@undefineds.co/models 0.2.25 → 0.2.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/approval.schema.d.ts +4 -0
- package/dist/approval.schema.js +6 -1
- package/dist/audit.presentation.d.ts +1 -1
- package/dist/audit.presentation.js +19 -12
- package/dist/audit.schema.d.ts +4 -0
- package/dist/audit.schema.js +6 -1
- package/dist/bin/udfs.d.ts +2 -0
- package/dist/bin/udfs.js +430 -0
- package/dist/chat.repository.d.ts +8 -0
- package/dist/chat.schema.d.ts +10 -0
- package/dist/chat.schema.js +9 -2
- package/dist/chat.utils.js +24 -9
- package/dist/index.d.ts +9 -3
- package/dist/index.js +10 -3
- package/dist/issue.repository.d.ts +69 -0
- package/dist/issue.repository.js +8 -0
- package/dist/issue.schema.d.ts +48 -0
- package/dist/issue.schema.js +37 -0
- package/dist/message.repository.d.ts +29 -9
- package/dist/message.schema.d.ts +29 -6
- package/dist/message.schema.js +26 -10
- package/dist/namespaces.js +29 -0
- package/dist/pod-storage-descriptor.d.ts +189 -0
- package/dist/pod-storage-descriptor.js +283 -0
- package/dist/repository.d.ts +2 -0
- package/dist/repository.js +3 -0
- package/dist/resource-id-defaults.d.ts +18 -0
- package/dist/resource-id-defaults.js +84 -0
- package/dist/run.schema.d.ts +112 -0
- package/dist/run.schema.js +89 -0
- package/dist/schema.d.ts +176 -8
- package/dist/schema.js +11 -0
- package/dist/session/session.schema.js +2 -1
- package/dist/sidecar/persistence-mapping.d.ts +3 -3
- package/dist/sidecar/sidecar-events.d.ts +45 -45
- package/dist/sidecar/sidecar-events.js +1 -1
- package/dist/task.schema.d.ts +62 -0
- package/dist/task.schema.js +49 -0
- package/dist/thread.repository.d.ts +15 -3
- package/dist/thread.schema.d.ts +14 -2
- package/dist/thread.schema.js +13 -5
- package/package.json +11 -3
|
@@ -3,6 +3,8 @@ export declare function extractApprovalIdFromApprovalRef(approvalRef: string | n
|
|
|
3
3
|
export declare const approvalResource: import("@undefineds.co/drizzle-solid/dist/core/schema").PodTableWithColumns<import("@undefineds.co/drizzle-solid/dist/core/schema").ResolvedColumns<{
|
|
4
4
|
id: import("@undefineds.co/drizzle-solid/dist/core/schema").PodStringColumn<false, false>;
|
|
5
5
|
session: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"uri", null, true, false>;
|
|
6
|
+
chat: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"uri", null, false, false>;
|
|
7
|
+
thread: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"uri", null, false, false>;
|
|
6
8
|
toolCallId: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"string", null, true, false>;
|
|
7
9
|
toolName: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"string", null, true, false>;
|
|
8
10
|
target: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"uri", null, true, false>;
|
|
@@ -24,6 +26,8 @@ export declare const approvalResource: import("@undefineds.co/drizzle-solid/dist
|
|
|
24
26
|
export declare const approvalTable: import("@undefineds.co/drizzle-solid/dist/core/schema").PodTableWithColumns<import("@undefineds.co/drizzle-solid/dist/core/schema").ResolvedColumns<{
|
|
25
27
|
id: import("@undefineds.co/drizzle-solid/dist/core/schema").PodStringColumn<false, false>;
|
|
26
28
|
session: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"uri", null, true, false>;
|
|
29
|
+
chat: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"uri", null, false, false>;
|
|
30
|
+
thread: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"uri", null, false, false>;
|
|
27
31
|
toolCallId: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"string", null, true, false>;
|
|
28
32
|
toolName: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"string", null, true, false>;
|
|
29
33
|
target: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"uri", null, true, false>;
|
package/dist/approval.schema.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { extractPodResourceTemplateValue, podTable, uri, string, text, timestamp, id } from '@undefineds.co/drizzle-solid';
|
|
2
2
|
import { ODRL, UDFS, DCTerms } from './namespaces.js';
|
|
3
|
+
import { chatResource } from './chat.schema.js';
|
|
4
|
+
import { threadResource } from './thread.schema.js';
|
|
5
|
+
import { asPodResourceTemplateTarget } from './repository.js';
|
|
3
6
|
export function buildApprovalSubjectPath(approvalId, createdAt = new Date()) {
|
|
4
7
|
const date = createdAt instanceof Date ? createdAt : new Date(createdAt);
|
|
5
8
|
const safeDate = Number.isFinite(date.getTime()) ? date : new Date();
|
|
@@ -12,13 +15,15 @@ export function extractApprovalIdFromApprovalRef(approvalRef) {
|
|
|
12
15
|
if (approvalRef && !/[/:#]/.test(approvalRef)) {
|
|
13
16
|
return approvalRef;
|
|
14
17
|
}
|
|
15
|
-
return extractPodResourceTemplateValue(approvalResource, approvalRef);
|
|
18
|
+
return extractPodResourceTemplateValue(asPodResourceTemplateTarget(approvalResource), approvalRef);
|
|
16
19
|
}
|
|
17
20
|
// Approval request resource (separate from Solid inbox notifications).
|
|
18
21
|
export const approvalResource = podTable('approval', {
|
|
19
22
|
id: id('id'),
|
|
20
23
|
// Relations
|
|
21
24
|
session: uri('session').predicate(UDFS.session).notNull(),
|
|
25
|
+
chat: uri('chat').predicate(UDFS.conversation).link(chatResource),
|
|
26
|
+
thread: uri('thread').predicate(UDFS.inThread).link(threadResource),
|
|
22
27
|
toolCallId: string('toolCallId').predicate(UDFS.toolCallId).notNull(),
|
|
23
28
|
// Request details
|
|
24
29
|
toolName: string('toolName').predicate(UDFS.toolName).notNull(),
|
|
@@ -14,7 +14,7 @@ export interface AuditPresentation {
|
|
|
14
14
|
authMessage: string | null;
|
|
15
15
|
actorRoleLabel: string;
|
|
16
16
|
}
|
|
17
|
-
type RelatedApproval = Pick<ApprovalRow, 'target' | 'toolName' | 'risk' | 'reason' | 'status' | 'context'> | null | undefined;
|
|
17
|
+
type RelatedApproval = Pick<ApprovalRow, 'chat' | 'thread' | 'target' | 'toolName' | 'risk' | 'reason' | 'status' | 'context'> | null | undefined;
|
|
18
18
|
export declare function buildAuditDetailRecord(audit: AuditRow, relatedApproval?: RelatedApproval): Record<string, unknown>;
|
|
19
19
|
export declare function formatInboxStatusLabel(status?: string | null): string | null;
|
|
20
20
|
export declare function formatAuditActorRole(role?: string | null): string;
|
|
@@ -33,6 +33,8 @@ export function buildAuditDetailRecord(audit, relatedApproval) {
|
|
|
33
33
|
actorRole: audit.actorRole,
|
|
34
34
|
onBehalfOf: audit.onBehalfOf || undefined,
|
|
35
35
|
session: audit.session || undefined,
|
|
36
|
+
chat: audit.chat || undefined,
|
|
37
|
+
thread: audit.thread || undefined,
|
|
36
38
|
entry: audit.entry || undefined,
|
|
37
39
|
toolCallId: audit.toolCallId || undefined,
|
|
38
40
|
toolName: audit.toolName || undefined,
|
|
@@ -42,6 +44,8 @@ export function buildAuditDetailRecord(audit, relatedApproval) {
|
|
|
42
44
|
createdAt: audit.createdAt,
|
|
43
45
|
relatedApproval: relatedApproval
|
|
44
46
|
? {
|
|
47
|
+
chat: relatedApproval.chat || undefined,
|
|
48
|
+
thread: relatedApproval.thread || undefined,
|
|
45
49
|
target: relatedApproval.target,
|
|
46
50
|
toolName: relatedApproval.toolName,
|
|
47
51
|
risk: relatedApproval.risk,
|
|
@@ -102,9 +106,12 @@ export function createResolvedAuthTimestampsIndex(audits) {
|
|
|
102
106
|
return resolvedAuthTimestampsByKey;
|
|
103
107
|
}
|
|
104
108
|
export function buildAuditPresentation(audit, resolvedAuthTimestampsByKey, relatedApproval) {
|
|
105
|
-
const thread = audit.entry || relatedApproval?.target || null;
|
|
106
|
-
const
|
|
109
|
+
const thread = audit.thread || relatedApproval?.thread || audit.entry || relatedApproval?.target || null;
|
|
110
|
+
const chat = audit.chat || relatedApproval?.chat || null;
|
|
111
|
+
const about = relatedApproval?.target ?? audit.entry ?? audit.approval ?? thread ?? null;
|
|
107
112
|
const { chatId, threadId } = extractChatThreadRef(thread);
|
|
113
|
+
const chatRef = extractChatThreadRef(chat);
|
|
114
|
+
const resolvedChatId = chatId ?? chatRef.chatId;
|
|
108
115
|
const actorRoleLabel = formatAuditActorRole(audit.actorRole);
|
|
109
116
|
if (audit.action === 'runtime.auth_required') {
|
|
110
117
|
const method = audit.toolName || null;
|
|
@@ -117,7 +124,7 @@ export function buildAuditPresentation(audit, resolvedAuthTimestampsByKey, relat
|
|
|
117
124
|
description: method ? `运行时需要完成 ${method} 认证后才能继续。` : '运行时需要额外认证后才能继续。',
|
|
118
125
|
category: 'auth_required',
|
|
119
126
|
status: isResolved ? 'resolved' : 'pending',
|
|
120
|
-
chatId,
|
|
127
|
+
chatId: resolvedChatId,
|
|
121
128
|
threadId,
|
|
122
129
|
thread,
|
|
123
130
|
about,
|
|
@@ -134,7 +141,7 @@ export function buildAuditPresentation(audit, resolvedAuthTimestampsByKey, relat
|
|
|
134
141
|
description: '运行时认证已完成。',
|
|
135
142
|
category: 'audit',
|
|
136
143
|
status: 'resolved',
|
|
137
|
-
chatId,
|
|
144
|
+
chatId: resolvedChatId,
|
|
138
145
|
threadId,
|
|
139
146
|
thread,
|
|
140
147
|
about,
|
|
@@ -152,7 +159,7 @@ export function buildAuditPresentation(audit, resolvedAuthTimestampsByKey, relat
|
|
|
152
159
|
description: [risk, '已进入审批队列'].filter(Boolean).join(' · ') || '工具调用已进入审批队列。',
|
|
153
160
|
category: 'audit',
|
|
154
161
|
status: undefined,
|
|
155
|
-
chatId,
|
|
162
|
+
chatId: resolvedChatId,
|
|
156
163
|
threadId,
|
|
157
164
|
thread,
|
|
158
165
|
about,
|
|
@@ -168,7 +175,7 @@ export function buildAuditPresentation(audit, resolvedAuthTimestampsByKey, relat
|
|
|
168
175
|
description: buildApprovalDecisionDescription(audit, relatedApproval, 'approved'),
|
|
169
176
|
category: 'audit',
|
|
170
177
|
status: 'approved',
|
|
171
|
-
chatId,
|
|
178
|
+
chatId: resolvedChatId,
|
|
172
179
|
threadId,
|
|
173
180
|
thread,
|
|
174
181
|
about,
|
|
@@ -184,7 +191,7 @@ export function buildAuditPresentation(audit, resolvedAuthTimestampsByKey, relat
|
|
|
184
191
|
description: buildApprovalDecisionDescription(audit, relatedApproval, 'rejected'),
|
|
185
192
|
category: 'audit',
|
|
186
193
|
status: 'rejected',
|
|
187
|
-
chatId,
|
|
194
|
+
chatId: resolvedChatId,
|
|
188
195
|
threadId,
|
|
189
196
|
thread,
|
|
190
197
|
about,
|
|
@@ -200,7 +207,7 @@ export function buildAuditPresentation(audit, resolvedAuthTimestampsByKey, relat
|
|
|
200
207
|
description: buildRuntimeSessionDescription(audit, '运行时会话开始执行。'),
|
|
201
208
|
category: 'audit',
|
|
202
209
|
status: 'active',
|
|
203
|
-
chatId,
|
|
210
|
+
chatId: resolvedChatId,
|
|
204
211
|
threadId,
|
|
205
212
|
thread,
|
|
206
213
|
about,
|
|
@@ -216,7 +223,7 @@ export function buildAuditPresentation(audit, resolvedAuthTimestampsByKey, relat
|
|
|
216
223
|
description: buildRuntimeSessionDescription(audit, '运行时会话已暂停。'),
|
|
217
224
|
category: 'audit',
|
|
218
225
|
status: 'paused',
|
|
219
|
-
chatId,
|
|
226
|
+
chatId: resolvedChatId,
|
|
220
227
|
threadId,
|
|
221
228
|
thread,
|
|
222
229
|
about,
|
|
@@ -232,7 +239,7 @@ export function buildAuditPresentation(audit, resolvedAuthTimestampsByKey, relat
|
|
|
232
239
|
description: buildRuntimeSessionDescription(audit, '运行时会话已完成。'),
|
|
233
240
|
category: 'audit',
|
|
234
241
|
status: 'completed',
|
|
235
|
-
chatId,
|
|
242
|
+
chatId: resolvedChatId,
|
|
236
243
|
threadId,
|
|
237
244
|
thread,
|
|
238
245
|
about,
|
|
@@ -248,7 +255,7 @@ export function buildAuditPresentation(audit, resolvedAuthTimestampsByKey, relat
|
|
|
248
255
|
description: buildRuntimeSessionDescription(audit, '运行时会话执行失败。'),
|
|
249
256
|
category: 'audit',
|
|
250
257
|
status: 'error',
|
|
251
|
-
chatId,
|
|
258
|
+
chatId: resolvedChatId,
|
|
252
259
|
threadId,
|
|
253
260
|
thread,
|
|
254
261
|
about,
|
|
@@ -263,7 +270,7 @@ export function buildAuditPresentation(audit, resolvedAuthTimestampsByKey, relat
|
|
|
263
270
|
description: actorRoleLabel,
|
|
264
271
|
category: 'audit',
|
|
265
272
|
status: undefined,
|
|
266
|
-
chatId,
|
|
273
|
+
chatId: resolvedChatId,
|
|
267
274
|
threadId,
|
|
268
275
|
thread,
|
|
269
276
|
about,
|
package/dist/audit.schema.d.ts
CHANGED
|
@@ -6,6 +6,8 @@ export declare const auditResource: import("@undefineds.co/drizzle-solid/dist/co
|
|
|
6
6
|
actorRole: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"string", null, true, false>;
|
|
7
7
|
onBehalfOf: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"uri", null, false, false>;
|
|
8
8
|
session: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"uri", null, false, false>;
|
|
9
|
+
chat: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"uri", null, false, false>;
|
|
10
|
+
thread: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"uri", null, false, false>;
|
|
9
11
|
entry: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"uri", null, false, false>;
|
|
10
12
|
toolCallId: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"string", null, false, false>;
|
|
11
13
|
toolName: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"string", null, false, false>;
|
|
@@ -22,6 +24,8 @@ export declare const auditTable: import("@undefineds.co/drizzle-solid/dist/core/
|
|
|
22
24
|
actorRole: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"string", null, true, false>;
|
|
23
25
|
onBehalfOf: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"uri", null, false, false>;
|
|
24
26
|
session: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"uri", null, false, false>;
|
|
27
|
+
chat: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"uri", null, false, false>;
|
|
28
|
+
thread: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"uri", null, false, false>;
|
|
25
29
|
entry: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"uri", null, false, false>;
|
|
26
30
|
toolCallId: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"string", null, false, false>;
|
|
27
31
|
toolName: import("@undefineds.co/drizzle-solid/dist/core/schema").ColumnBuilder<"string", null, false, false>;
|
package/dist/audit.schema.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { extractPodResourceTemplateValue, podTable, uri, string, timestamp, id } from '@undefineds.co/drizzle-solid';
|
|
2
2
|
import { UDFS, DCTerms } from './namespaces.js';
|
|
3
|
+
import { chatResource } from './chat.schema.js';
|
|
4
|
+
import { threadResource } from './thread.schema.js';
|
|
5
|
+
import { asPodResourceTemplateTarget } from './repository.js';
|
|
3
6
|
export function buildAuditSubjectPath(auditId, createdAt = new Date()) {
|
|
4
7
|
const date = createdAt instanceof Date ? createdAt : new Date(createdAt);
|
|
5
8
|
const safeDate = Number.isFinite(date.getTime()) ? date : new Date();
|
|
@@ -21,6 +24,8 @@ export const auditResource = podTable('audit', {
|
|
|
21
24
|
onBehalfOf: uri('onBehalfOf').predicate(UDFS.onBehalfOf),
|
|
22
25
|
// Relations
|
|
23
26
|
session: uri('session').predicate(UDFS.session),
|
|
27
|
+
chat: uri('chat').predicate(UDFS.conversation).link(chatResource),
|
|
28
|
+
thread: uri('thread').predicate(UDFS.inThread).link(threadResource),
|
|
24
29
|
entry: uri('entry').predicate(UDFS.entry),
|
|
25
30
|
toolCallId: string('toolCallId').predicate(UDFS.toolCallId),
|
|
26
31
|
toolName: string('toolName').predicate(UDFS.toolName),
|
|
@@ -41,7 +46,7 @@ export function extractAuditIdFromAuditRef(auditRef) {
|
|
|
41
46
|
if (auditRef && !/[/:#]/.test(auditRef)) {
|
|
42
47
|
return auditRef;
|
|
43
48
|
}
|
|
44
|
-
return extractPodResourceTemplateValue(auditResource, auditRef);
|
|
49
|
+
return extractPodResourceTemplateValue(asPodResourceTemplateTarget(auditResource), auditRef);
|
|
45
50
|
}
|
|
46
51
|
// Compatibility alias. New model code should prefer `auditResource`.
|
|
47
52
|
export const auditTable = auditResource;
|
package/dist/bin/udfs.js
ADDED
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createPodStorage, podSchema, XPOD_CREDENTIAL, } from '../index.js';
|
|
3
|
+
async function main(argv) {
|
|
4
|
+
const [area, action, ...rest] = argv;
|
|
5
|
+
if (!area || area === 'help' || area === '--help' || area === '-h') {
|
|
6
|
+
printHelp();
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
if (area === 'schema') {
|
|
10
|
+
handleSchema(action, rest);
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
if (area === 'storage') {
|
|
14
|
+
handleStorage(action, rest);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
if (area === 'consensus') {
|
|
18
|
+
await handleConsensus(action, rest);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
throw new Error(`Unknown udfs command: ${area}`);
|
|
22
|
+
}
|
|
23
|
+
function handleSchema(action, args) {
|
|
24
|
+
if (action === 'list') {
|
|
25
|
+
writeJson(podSchema.list());
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
if (action === 'describe') {
|
|
29
|
+
const uri = args[0];
|
|
30
|
+
if (!uri)
|
|
31
|
+
throw new Error('Usage: udfs schema describe <uri>');
|
|
32
|
+
const descriptor = podSchema.describe({ uri });
|
|
33
|
+
if (!descriptor)
|
|
34
|
+
throw new Error(`Descriptor not found: ${uri}`);
|
|
35
|
+
writeJson(descriptor);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (action === 'classes') {
|
|
39
|
+
writeJson(podSchema.classes({
|
|
40
|
+
uri: readOption(args, '--uri'),
|
|
41
|
+
}));
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (action === 'search') {
|
|
45
|
+
const query = readOption(args, '--query') ?? args[0];
|
|
46
|
+
if (!query)
|
|
47
|
+
throw new Error('Usage: udfs schema search --query <text>');
|
|
48
|
+
writeJson(podSchema.search({
|
|
49
|
+
query,
|
|
50
|
+
source: readOption(args, '--source'),
|
|
51
|
+
resourceKind: readOption(args, '--resource-kind'),
|
|
52
|
+
limit: readNumberOption(args, '--limit'),
|
|
53
|
+
}));
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (action === 'predicates') {
|
|
57
|
+
writeJson(podSchema.predicates({
|
|
58
|
+
uri: readOption(args, '--uri'),
|
|
59
|
+
field: readOption(args, '--field'),
|
|
60
|
+
}));
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
throw new Error(`Unknown schema command: ${action ?? '(missing)'}`);
|
|
64
|
+
}
|
|
65
|
+
function handleStorage(action, args) {
|
|
66
|
+
if (action === 'validate') {
|
|
67
|
+
const input = readInputPayload(args, 'udfs storage validate --input \'<mutation-json>\'');
|
|
68
|
+
writeJson(createPodStorage().validate(input));
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
throw new Error(`Unknown storage command: ${action ?? '(missing)'}`);
|
|
72
|
+
}
|
|
73
|
+
async function handleConsensus(action, args) {
|
|
74
|
+
if (!action || action === '--help' || action === '-h') {
|
|
75
|
+
printConsensusHelp();
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
const allArgs = [action, ...args];
|
|
79
|
+
const input = readConsensusInput(allArgs);
|
|
80
|
+
const result = await resolveConsensusRequest({
|
|
81
|
+
sessionId: input.session_id,
|
|
82
|
+
request: input.request,
|
|
83
|
+
tokenType: input.answers?.token_type ?? 'tunnel-token',
|
|
84
|
+
conversation: input.conversation_id ?? process.env.UDFS_CONSENSUS_CONVERSATION_ID,
|
|
85
|
+
});
|
|
86
|
+
if (allArgs.includes('--json')) {
|
|
87
|
+
writeJson(result);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
process.stdout.write(`Consensus: ${input.request}\n`);
|
|
91
|
+
if (result.session_id) {
|
|
92
|
+
process.stdout.write(`Session: ${result.session_id}\n`);
|
|
93
|
+
}
|
|
94
|
+
process.stdout.write(`Consensus runtime: ${result.consensusRuntime.mode}${result.consensusRuntime.mode === 'remote' ? ` (${result.consensusRuntime.baseUrl})` : ''}\n`);
|
|
95
|
+
if (result.consensusResponse?.conversationId) {
|
|
96
|
+
process.stdout.write(`Conversation: ${result.consensusResponse.conversationId}\n`);
|
|
97
|
+
}
|
|
98
|
+
process.stdout.write(`Clarification: ${result.first.questions[0].question}\n`);
|
|
99
|
+
process.stdout.write(`Answer: ${input.answers?.token_type ?? 'tunnel-token'}\n`);
|
|
100
|
+
process.stdout.write(`Schema: ${result.resolved.schemaUri}\n`);
|
|
101
|
+
process.stdout.write(`Descriptor storage: ${result.descriptor.storage.base}${result.descriptor.storage.resourceIdPattern}\n`);
|
|
102
|
+
}
|
|
103
|
+
function resolveConsensusRuntime() {
|
|
104
|
+
const baseUrl = process.env.UDFS_CONSENSUS_BASE_URL;
|
|
105
|
+
const token = process.env.UDFS_CONSENSUS_TOKEN;
|
|
106
|
+
if (baseUrl && token) {
|
|
107
|
+
return {
|
|
108
|
+
mode: 'remote',
|
|
109
|
+
baseUrl,
|
|
110
|
+
auth: 'runtime-token',
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
mode: 'local-fallback',
|
|
115
|
+
auth: 'none',
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
async function resolveConsensusRequest(input) {
|
|
119
|
+
const runtime = resolveConsensusRuntime();
|
|
120
|
+
if (runtime.mode === 'remote') {
|
|
121
|
+
const remote = await callRemoteConsensus({
|
|
122
|
+
runtime,
|
|
123
|
+
sessionId: input.sessionId,
|
|
124
|
+
request: input.request,
|
|
125
|
+
conversation: input.conversation,
|
|
126
|
+
});
|
|
127
|
+
const parsed = parseRemoteConsensusPayload(remote.body);
|
|
128
|
+
const resolved = coerceResolvedConsensusPayload(parsed);
|
|
129
|
+
if (!resolved) {
|
|
130
|
+
throw new Error('Remote Consensus response did not contain a resolved schema payload');
|
|
131
|
+
}
|
|
132
|
+
return buildConsensusResult({
|
|
133
|
+
runtime,
|
|
134
|
+
sessionId: input.sessionId,
|
|
135
|
+
tokenType: input.tokenType,
|
|
136
|
+
fieldMapping: resolved.fieldMapping,
|
|
137
|
+
confidence: resolved.confidence,
|
|
138
|
+
response: {
|
|
139
|
+
id: remote.id,
|
|
140
|
+
conversationId: remote.conversationId,
|
|
141
|
+
parsed,
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
return buildConsensusResult({
|
|
146
|
+
runtime,
|
|
147
|
+
sessionId: input.sessionId,
|
|
148
|
+
tokenType: input.tokenType,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
async function callRemoteConsensus(input) {
|
|
152
|
+
const token = process.env.UDFS_CONSENSUS_TOKEN;
|
|
153
|
+
if (!token) {
|
|
154
|
+
throw new Error('Remote Consensus requires injected UDFS_CONSENSUS_TOKEN');
|
|
155
|
+
}
|
|
156
|
+
const body = {
|
|
157
|
+
model: process.env.UDFS_CONSENSUS_MODEL ?? 'consensus-modeling',
|
|
158
|
+
input: [
|
|
159
|
+
{
|
|
160
|
+
role: 'user',
|
|
161
|
+
content: [
|
|
162
|
+
{
|
|
163
|
+
type: 'input_text',
|
|
164
|
+
text: input.request,
|
|
165
|
+
},
|
|
166
|
+
],
|
|
167
|
+
},
|
|
168
|
+
],
|
|
169
|
+
metadata: {
|
|
170
|
+
product: 'linx',
|
|
171
|
+
purpose: 'pod-storage',
|
|
172
|
+
...(input.sessionId ? { session_id: input.sessionId } : {}),
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
if (input.conversation) {
|
|
176
|
+
body.conversation = input.conversation;
|
|
177
|
+
}
|
|
178
|
+
const response = await fetch(`${input.runtime.baseUrl.replace(/\/+$/u, '')}/responses`, {
|
|
179
|
+
method: 'POST',
|
|
180
|
+
headers: {
|
|
181
|
+
authorization: `Bearer ${token}`,
|
|
182
|
+
'content-type': 'application/json',
|
|
183
|
+
},
|
|
184
|
+
body: JSON.stringify(body),
|
|
185
|
+
});
|
|
186
|
+
const text = await response.text();
|
|
187
|
+
const parsedBody = text ? JSON.parse(text) : {};
|
|
188
|
+
if (!response.ok) {
|
|
189
|
+
throw new Error(`Remote Consensus request failed: ${response.status} ${text}`);
|
|
190
|
+
}
|
|
191
|
+
return {
|
|
192
|
+
id: typeof parsedBody.id === 'string' ? parsedBody.id : undefined,
|
|
193
|
+
conversationId: extractConversationId(parsedBody),
|
|
194
|
+
body: parsedBody,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
function extractConversationId(body) {
|
|
198
|
+
if (typeof body.conversation === 'string')
|
|
199
|
+
return body.conversation;
|
|
200
|
+
if (body.conversation
|
|
201
|
+
&& typeof body.conversation === 'object'
|
|
202
|
+
&& 'id' in body.conversation
|
|
203
|
+
&& typeof body.conversation.id === 'string') {
|
|
204
|
+
return body.conversation.id;
|
|
205
|
+
}
|
|
206
|
+
return undefined;
|
|
207
|
+
}
|
|
208
|
+
function parseRemoteConsensusPayload(body) {
|
|
209
|
+
if (isRecord(body) && typeof body.status === 'string') {
|
|
210
|
+
return body;
|
|
211
|
+
}
|
|
212
|
+
if (isRecord(body) && typeof body.output_text === 'string') {
|
|
213
|
+
return parseJsonMaybe(body.output_text);
|
|
214
|
+
}
|
|
215
|
+
if (isRecord(body) && Array.isArray(body.output)) {
|
|
216
|
+
for (const item of body.output) {
|
|
217
|
+
if (!isRecord(item) || !Array.isArray(item.content))
|
|
218
|
+
continue;
|
|
219
|
+
for (const content of item.content) {
|
|
220
|
+
if (!isRecord(content))
|
|
221
|
+
continue;
|
|
222
|
+
const text = typeof content.text === 'string'
|
|
223
|
+
? content.text
|
|
224
|
+
: typeof content.output_text === 'string'
|
|
225
|
+
? content.output_text
|
|
226
|
+
: undefined;
|
|
227
|
+
if (!text)
|
|
228
|
+
continue;
|
|
229
|
+
const parsed = parseJsonMaybe(text);
|
|
230
|
+
if (parsed)
|
|
231
|
+
return parsed;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
if (isRecord(body) && Array.isArray(body.choices)) {
|
|
236
|
+
for (const choice of body.choices) {
|
|
237
|
+
if (!isRecord(choice) || !isRecord(choice.message))
|
|
238
|
+
continue;
|
|
239
|
+
if (typeof choice.message.content !== 'string')
|
|
240
|
+
continue;
|
|
241
|
+
const parsed = parseJsonMaybe(choice.message.content);
|
|
242
|
+
if (parsed)
|
|
243
|
+
return parsed;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return undefined;
|
|
247
|
+
}
|
|
248
|
+
function coerceResolvedConsensusPayload(payload) {
|
|
249
|
+
if (!isRecord(payload) || payload.status !== 'resolved')
|
|
250
|
+
return null;
|
|
251
|
+
const schemaUri = stringField(payload, 'schemaUri') ?? stringField(payload, 'uri');
|
|
252
|
+
if (schemaUri !== XPOD_CREDENTIAL.Credential)
|
|
253
|
+
return null;
|
|
254
|
+
if (!isRecord(payload.fieldMapping))
|
|
255
|
+
return null;
|
|
256
|
+
const service = stringField(payload.fieldMapping, 'service');
|
|
257
|
+
const providerId = stringField(payload.fieldMapping, 'providerId');
|
|
258
|
+
const secretType = stringField(payload.fieldMapping, 'secretType');
|
|
259
|
+
if (!service || !providerId || !secretType)
|
|
260
|
+
return null;
|
|
261
|
+
return {
|
|
262
|
+
fieldMapping: {
|
|
263
|
+
service,
|
|
264
|
+
providerId,
|
|
265
|
+
secretType,
|
|
266
|
+
label: stringField(payload.fieldMapping, 'label'),
|
|
267
|
+
status: stringField(payload.fieldMapping, 'status'),
|
|
268
|
+
},
|
|
269
|
+
confidence: typeof payload.confidence === 'number' ? payload.confidence : undefined,
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
function parseJsonMaybe(text) {
|
|
273
|
+
try {
|
|
274
|
+
return JSON.parse(text);
|
|
275
|
+
}
|
|
276
|
+
catch {
|
|
277
|
+
return undefined;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
function isRecord(value) {
|
|
281
|
+
return typeof value === 'object' && value !== null;
|
|
282
|
+
}
|
|
283
|
+
function stringField(record, field) {
|
|
284
|
+
const value = record[field];
|
|
285
|
+
return typeof value === 'string' && value.trim() ? value : undefined;
|
|
286
|
+
}
|
|
287
|
+
function buildConsensusResult(input) {
|
|
288
|
+
const first = {
|
|
289
|
+
status: 'needs_clarification',
|
|
290
|
+
questions: [
|
|
291
|
+
{
|
|
292
|
+
id: 'token_type',
|
|
293
|
+
question: '这是 Cloudflare API Token 还是 Tunnel Token?',
|
|
294
|
+
options: ['tunnel-token', 'api-token'],
|
|
295
|
+
},
|
|
296
|
+
],
|
|
297
|
+
};
|
|
298
|
+
const resolved = {
|
|
299
|
+
status: 'resolved',
|
|
300
|
+
schemaUri: XPOD_CREDENTIAL.Credential,
|
|
301
|
+
fieldMapping: {
|
|
302
|
+
service: input.fieldMapping?.service ?? 'infra',
|
|
303
|
+
providerId: input.fieldMapping?.providerId ?? 'cloudflare',
|
|
304
|
+
secretType: input.fieldMapping?.secretType ?? input.tokenType,
|
|
305
|
+
label: input.fieldMapping?.label
|
|
306
|
+
?? defaultCredentialLabel(input.fieldMapping?.providerId ?? 'cloudflare', input.fieldMapping?.secretType ?? input.tokenType),
|
|
307
|
+
status: input.fieldMapping?.status ?? 'active',
|
|
308
|
+
},
|
|
309
|
+
confidence: input.confidence ?? (input.tokenType === 'tunnel-token' ? 0.96 : 0.94),
|
|
310
|
+
};
|
|
311
|
+
const descriptor = podSchema.describe({ uri: resolved.schemaUri });
|
|
312
|
+
if (!descriptor) {
|
|
313
|
+
throw new Error(`Descriptor not found: ${resolved.schemaUri}`);
|
|
314
|
+
}
|
|
315
|
+
return {
|
|
316
|
+
session_id: input.sessionId,
|
|
317
|
+
consensusRuntime: input.runtime,
|
|
318
|
+
consensusResponse: input.response,
|
|
319
|
+
first,
|
|
320
|
+
resolved,
|
|
321
|
+
descriptor: {
|
|
322
|
+
uri: descriptor.uri,
|
|
323
|
+
storage: descriptor.storage,
|
|
324
|
+
},
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
function readOption(args, name) {
|
|
328
|
+
const index = args.indexOf(name);
|
|
329
|
+
if (index === -1)
|
|
330
|
+
return undefined;
|
|
331
|
+
const value = args[index + 1];
|
|
332
|
+
return value && !value.startsWith('--') ? value : undefined;
|
|
333
|
+
}
|
|
334
|
+
function readNumberOption(args, name) {
|
|
335
|
+
const value = readOption(args, name);
|
|
336
|
+
if (!value)
|
|
337
|
+
return undefined;
|
|
338
|
+
const parsed = Number(value);
|
|
339
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
340
|
+
throw new Error(`${name} must be a positive number`);
|
|
341
|
+
}
|
|
342
|
+
return Math.floor(parsed);
|
|
343
|
+
}
|
|
344
|
+
function readConsensusInput(args) {
|
|
345
|
+
if (args[0] === 'model') {
|
|
346
|
+
throw new Error('Use: udfs consensus --input \'<json>\'');
|
|
347
|
+
}
|
|
348
|
+
const parsed = readInputPayload(args, 'udfs consensus --input \'<json>\' --json');
|
|
349
|
+
if (!isRecord(parsed)) {
|
|
350
|
+
throw new Error('Consensus input must be a JSON object');
|
|
351
|
+
}
|
|
352
|
+
const request = stringField(parsed, 'request')
|
|
353
|
+
?? stringField(parsed, 'message')
|
|
354
|
+
?? stringField(parsed, 'text');
|
|
355
|
+
if (!request) {
|
|
356
|
+
throw new Error('Consensus input requires a non-empty request field');
|
|
357
|
+
}
|
|
358
|
+
const answers = isRecord(parsed.answers) ? parsed.answers : {};
|
|
359
|
+
const tokenTypeText = stringField(answers, 'token_type') ?? stringField(parsed, 'token_type');
|
|
360
|
+
const tokenType = coerceTokenType(tokenTypeText);
|
|
361
|
+
if (tokenTypeText && !tokenType) {
|
|
362
|
+
throw new Error(`Unsupported token type: ${tokenTypeText}`);
|
|
363
|
+
}
|
|
364
|
+
return {
|
|
365
|
+
session_id: stringField(parsed, 'session_id'),
|
|
366
|
+
request,
|
|
367
|
+
answers: tokenType ? { token_type: tokenType } : undefined,
|
|
368
|
+
conversation_id: stringField(parsed, 'conversation_id') ?? stringField(parsed, 'conversation'),
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
function coerceTokenType(value) {
|
|
372
|
+
if (value === 'tunnel-token' || value === 'api-token') {
|
|
373
|
+
return value;
|
|
374
|
+
}
|
|
375
|
+
return undefined;
|
|
376
|
+
}
|
|
377
|
+
function defaultCredentialLabel(providerId, secretType) {
|
|
378
|
+
const providerLabel = providerId
|
|
379
|
+
.split(/[-_.]/g)
|
|
380
|
+
.filter(Boolean)
|
|
381
|
+
.map((part) => `${part.slice(0, 1).toUpperCase()}${part.slice(1)}`)
|
|
382
|
+
.join(' ');
|
|
383
|
+
const secretLabel = secretType
|
|
384
|
+
.split(/[-_.]/g)
|
|
385
|
+
.filter(Boolean)
|
|
386
|
+
.map((part) => part.toLowerCase() === 'api' ? 'API' : `${part.slice(0, 1).toUpperCase()}${part.slice(1)}`)
|
|
387
|
+
.join(' ');
|
|
388
|
+
return `${providerLabel} ${secretLabel}`;
|
|
389
|
+
}
|
|
390
|
+
function readInputPayload(args, usage) {
|
|
391
|
+
const raw = readOption(args, '--input');
|
|
392
|
+
if (!raw) {
|
|
393
|
+
throw new Error(`Usage: ${usage}`);
|
|
394
|
+
}
|
|
395
|
+
return JSON.parse(raw);
|
|
396
|
+
}
|
|
397
|
+
function writeJson(value) {
|
|
398
|
+
process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
399
|
+
}
|
|
400
|
+
function printHelp() {
|
|
401
|
+
process.stdout.write(`udfs - Undefineds Pod data semantics tool
|
|
402
|
+
|
|
403
|
+
Usage:
|
|
404
|
+
udfs schema list
|
|
405
|
+
udfs schema search --query <text>
|
|
406
|
+
udfs schema describe <uri>
|
|
407
|
+
udfs schema classes [--uri <uri>]
|
|
408
|
+
udfs schema predicates [--uri <uri>] [--field <field>]
|
|
409
|
+
udfs consensus --input '{"session_id":"sess_123","request":"我要保存这个 Cloudflare token","answers":{"token_type":"tunnel-token"}}' --json
|
|
410
|
+
udfs storage validate --input '<mutation-json>'
|
|
411
|
+
|
|
412
|
+
Runtime:
|
|
413
|
+
Remote Consensus uses UDFS_CONSENSUS_BASE_URL plus UDFS_CONSENSUS_TOKEN when injected by LinX/linx-lite.
|
|
414
|
+
Do not pass user API keys on the command line.
|
|
415
|
+
`);
|
|
416
|
+
}
|
|
417
|
+
function printConsensusHelp() {
|
|
418
|
+
process.stdout.write(`udfs consensus - Ask Consensus how a storage request should be represented
|
|
419
|
+
|
|
420
|
+
Usage:
|
|
421
|
+
udfs consensus --input '{"session_id":"sess_123","request":"我要保存这个 Cloudflare token","answers":{"token_type":"tunnel-token"}}' --json
|
|
422
|
+
|
|
423
|
+
Runtime:
|
|
424
|
+
Remote Consensus uses UDFS_CONSENSUS_BASE_URL plus UDFS_CONSENSUS_TOKEN when injected by LinX/linx-lite.
|
|
425
|
+
`);
|
|
426
|
+
}
|
|
427
|
+
main(process.argv.slice(2)).catch((error) => {
|
|
428
|
+
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
429
|
+
process.exitCode = 1;
|
|
430
|
+
});
|