@okrlinkhub/agent-factory 0.2.12 → 0.2.14
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 +2 -0
- package/dist/client/index.d.ts +36 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +81 -2
- package/dist/client/index.js.map +1 -1
- package/dist/component/_generated/component.d.ts +126 -4
- package/dist/component/_generated/component.d.ts.map +1 -1
- package/dist/component/config.d.ts.map +1 -1
- package/dist/component/config.js +5 -0
- package/dist/component/config.js.map +1 -1
- package/dist/component/lib.d.ts +1 -1
- package/dist/component/lib.d.ts.map +1 -1
- package/dist/component/lib.js +1 -1
- package/dist/component/lib.js.map +1 -1
- package/dist/component/queue.d.ts +113 -4
- package/dist/component/queue.d.ts.map +1 -1
- package/dist/component/queue.js +565 -10
- package/dist/component/queue.js.map +1 -1
- package/dist/component/schema.d.ts +99 -29
- package/dist/component/schema.d.ts.map +1 -1
- package/dist/component/schema.js +49 -4
- package/dist/component/schema.js.map +1 -1
- package/package.json +1 -1
- package/src/client/index.ts +82 -2
- package/src/component/_generated/component.ts +168 -4
- package/src/component/config.ts +5 -0
- package/src/component/lib.test.ts +175 -0
- package/src/component/lib.ts +3 -0
- package/src/component/queue.ts +662 -10
- package/src/component/schema.ts +64 -12
package/src/component/queue.ts
CHANGED
|
@@ -65,6 +65,23 @@ const bridgeRuntimeConfigValidator = v.object({
|
|
|
65
65
|
serviceKeySecretRef: v.union(v.null(), v.string()),
|
|
66
66
|
});
|
|
67
67
|
|
|
68
|
+
const messageRuntimeConfigValidator = v.object({
|
|
69
|
+
systemPrompt: v.optional(v.string()),
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const globalSkillStatusValidator = v.union(v.literal("active"), v.literal("disabled"));
|
|
73
|
+
const globalSkillReleaseChannelValidator = v.union(v.literal("stable"), v.literal("canary"));
|
|
74
|
+
const globalSkillModuleFormatValidator = v.union(v.literal("esm"), v.literal("cjs"));
|
|
75
|
+
|
|
76
|
+
const globalSkillManifestItemValidator = v.object({
|
|
77
|
+
slug: v.string(),
|
|
78
|
+
version: v.string(),
|
|
79
|
+
moduleFormat: globalSkillModuleFormatValidator,
|
|
80
|
+
entryPoint: v.string(),
|
|
81
|
+
sourceJs: v.string(),
|
|
82
|
+
sha256: v.string(),
|
|
83
|
+
});
|
|
84
|
+
|
|
68
85
|
const BRIDGE_SECRET_REFS = {
|
|
69
86
|
serviceKey: "agent-bridge.serviceKey",
|
|
70
87
|
baseUrl: "agent-bridge.baseUrl",
|
|
@@ -73,6 +90,11 @@ const BRIDGE_SECRET_REFS = {
|
|
|
73
90
|
appKey: "agent-bridge.appKey",
|
|
74
91
|
} as const;
|
|
75
92
|
|
|
93
|
+
const RUNTIME_CONFIG_KEYS = {
|
|
94
|
+
provider: "provider",
|
|
95
|
+
message: "message",
|
|
96
|
+
} as const;
|
|
97
|
+
|
|
76
98
|
export const enqueueMessage = mutation({
|
|
77
99
|
args: {
|
|
78
100
|
conversationId: v.string(),
|
|
@@ -87,6 +109,10 @@ export const enqueueMessage = mutation({
|
|
|
87
109
|
returns: v.id("messageQueue"),
|
|
88
110
|
handler: async (ctx, args) => {
|
|
89
111
|
const nowMs = args.nowMs ?? Date.now();
|
|
112
|
+
const messageRuntimeConfigRow = await ctx.db
|
|
113
|
+
.query("runtimeConfig")
|
|
114
|
+
.withIndex("by_key", (q) => q.eq("key", RUNTIME_CONFIG_KEYS.message))
|
|
115
|
+
.unique();
|
|
90
116
|
const profile = await ctx.db
|
|
91
117
|
.query("agentProfiles")
|
|
92
118
|
.withIndex("by_agentKey", (q) => q.eq("agentKey", args.agentKey))
|
|
@@ -113,6 +139,10 @@ export const enqueueMessage = mutation({
|
|
|
113
139
|
|
|
114
140
|
const payload = {
|
|
115
141
|
...args.payload,
|
|
142
|
+
messageText: appendSystemPromptToMessage(
|
|
143
|
+
args.payload.messageText,
|
|
144
|
+
messageRuntimeConfigRow?.messageConfig?.systemPrompt,
|
|
145
|
+
),
|
|
116
146
|
providerUserId: providerUserIdStr,
|
|
117
147
|
metadata: {
|
|
118
148
|
...(args.payload.metadata ?? {}),
|
|
@@ -239,9 +269,9 @@ export const upsertAgentProfile = mutation({
|
|
|
239
269
|
agentKey: v.string(),
|
|
240
270
|
providerUserId: v.optional(v.string()),
|
|
241
271
|
version: v.string(),
|
|
242
|
-
soulMd: v.string(),
|
|
272
|
+
soulMd: v.optional(v.string()),
|
|
243
273
|
clientMd: v.optional(v.string()),
|
|
244
|
-
skills: v.array(v.string()),
|
|
274
|
+
skills: v.optional(v.array(v.string())),
|
|
245
275
|
secretsRef: v.array(v.string()),
|
|
246
276
|
bridgeConfig: v.optional(bridgeProfileConfigValidator),
|
|
247
277
|
enabled: v.boolean(),
|
|
@@ -265,6 +295,85 @@ export const upsertAgentProfile = mutation({
|
|
|
265
295
|
},
|
|
266
296
|
});
|
|
267
297
|
|
|
298
|
+
export const clearDeprecatedAgentProfileFields = mutation({
|
|
299
|
+
args: {
|
|
300
|
+
dryRun: v.optional(v.boolean()),
|
|
301
|
+
},
|
|
302
|
+
returns: v.object({
|
|
303
|
+
dryRun: v.boolean(),
|
|
304
|
+
scanned: v.number(),
|
|
305
|
+
updated: v.number(),
|
|
306
|
+
unchanged: v.number(),
|
|
307
|
+
clearedProviderUserId: v.number(),
|
|
308
|
+
clearedSoulMd: v.number(),
|
|
309
|
+
clearedClientMd: v.number(),
|
|
310
|
+
clearedSkills: v.number(),
|
|
311
|
+
updatedAgentKeys: v.array(v.string()),
|
|
312
|
+
}),
|
|
313
|
+
handler: async (ctx, args) => {
|
|
314
|
+
const profiles = await ctx.db.query("agentProfiles").collect();
|
|
315
|
+
const dryRun = args.dryRun ?? false;
|
|
316
|
+
|
|
317
|
+
let updated = 0;
|
|
318
|
+
let clearedProviderUserId = 0;
|
|
319
|
+
let clearedSoulMd = 0;
|
|
320
|
+
let clearedClientMd = 0;
|
|
321
|
+
let clearedSkills = 0;
|
|
322
|
+
const updatedAgentKeys: Array<string> = [];
|
|
323
|
+
|
|
324
|
+
for (const profile of profiles) {
|
|
325
|
+
const patch: {
|
|
326
|
+
providerUserId?: undefined;
|
|
327
|
+
soulMd?: undefined;
|
|
328
|
+
clientMd?: undefined;
|
|
329
|
+
skills?: undefined;
|
|
330
|
+
} = {};
|
|
331
|
+
let shouldPatch = false;
|
|
332
|
+
|
|
333
|
+
if (profile.providerUserId !== undefined) {
|
|
334
|
+
patch.providerUserId = undefined;
|
|
335
|
+
clearedProviderUserId += 1;
|
|
336
|
+
shouldPatch = true;
|
|
337
|
+
}
|
|
338
|
+
if (profile.soulMd !== undefined) {
|
|
339
|
+
patch.soulMd = undefined;
|
|
340
|
+
clearedSoulMd += 1;
|
|
341
|
+
shouldPatch = true;
|
|
342
|
+
}
|
|
343
|
+
if (profile.clientMd !== undefined) {
|
|
344
|
+
patch.clientMd = undefined;
|
|
345
|
+
clearedClientMd += 1;
|
|
346
|
+
shouldPatch = true;
|
|
347
|
+
}
|
|
348
|
+
if (profile.skills !== undefined) {
|
|
349
|
+
patch.skills = undefined;
|
|
350
|
+
clearedSkills += 1;
|
|
351
|
+
shouldPatch = true;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
if (!shouldPatch) continue;
|
|
355
|
+
|
|
356
|
+
updated += 1;
|
|
357
|
+
updatedAgentKeys.push(profile.agentKey);
|
|
358
|
+
if (!dryRun) {
|
|
359
|
+
await ctx.db.patch(profile._id, patch);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
return {
|
|
364
|
+
dryRun,
|
|
365
|
+
scanned: profiles.length,
|
|
366
|
+
updated,
|
|
367
|
+
unchanged: profiles.length - updated,
|
|
368
|
+
clearedProviderUserId,
|
|
369
|
+
clearedSoulMd,
|
|
370
|
+
clearedClientMd,
|
|
371
|
+
clearedSkills,
|
|
372
|
+
updatedAgentKeys,
|
|
373
|
+
};
|
|
374
|
+
},
|
|
375
|
+
});
|
|
376
|
+
|
|
268
377
|
export const importPlaintextSecret = mutation({
|
|
269
378
|
args: {
|
|
270
379
|
secretRef: v.string(),
|
|
@@ -365,9 +474,9 @@ export const getProviderRuntimeConfig = internalQuery({
|
|
|
365
474
|
handler: async (ctx) => {
|
|
366
475
|
const row = await ctx.db
|
|
367
476
|
.query("runtimeConfig")
|
|
368
|
-
.withIndex("by_key", (q) => q.eq("key",
|
|
477
|
+
.withIndex("by_key", (q) => q.eq("key", RUNTIME_CONFIG_KEYS.provider))
|
|
369
478
|
.unique();
|
|
370
|
-
if (!row) {
|
|
479
|
+
if (!row?.providerConfig) {
|
|
371
480
|
return null;
|
|
372
481
|
}
|
|
373
482
|
return row.providerConfig;
|
|
@@ -384,11 +493,11 @@ export const upsertProviderRuntimeConfig = internalMutation({
|
|
|
384
493
|
const nowMs = args.nowMs ?? Date.now();
|
|
385
494
|
const existing = await ctx.db
|
|
386
495
|
.query("runtimeConfig")
|
|
387
|
-
.withIndex("by_key", (q) => q.eq("key",
|
|
496
|
+
.withIndex("by_key", (q) => q.eq("key", RUNTIME_CONFIG_KEYS.provider))
|
|
388
497
|
.unique();
|
|
389
498
|
if (!existing) {
|
|
390
499
|
await ctx.db.insert("runtimeConfig", {
|
|
391
|
-
key:
|
|
500
|
+
key: RUNTIME_CONFIG_KEYS.provider,
|
|
392
501
|
providerConfig: args.providerConfig,
|
|
393
502
|
updatedAt: nowMs,
|
|
394
503
|
});
|
|
@@ -408,9 +517,9 @@ export const providerRuntimeConfig = query({
|
|
|
408
517
|
handler: async (ctx) => {
|
|
409
518
|
const row = await ctx.db
|
|
410
519
|
.query("runtimeConfig")
|
|
411
|
-
.withIndex("by_key", (q) => q.eq("key",
|
|
520
|
+
.withIndex("by_key", (q) => q.eq("key", RUNTIME_CONFIG_KEYS.provider))
|
|
412
521
|
.unique();
|
|
413
|
-
if (!row) {
|
|
522
|
+
if (!row?.providerConfig) {
|
|
414
523
|
return null;
|
|
415
524
|
}
|
|
416
525
|
return row.providerConfig;
|
|
@@ -427,11 +536,11 @@ export const setProviderRuntimeConfig = mutation({
|
|
|
427
536
|
const nowMs = args.nowMs ?? Date.now();
|
|
428
537
|
const existing = await ctx.db
|
|
429
538
|
.query("runtimeConfig")
|
|
430
|
-
.withIndex("by_key", (q) => q.eq("key",
|
|
539
|
+
.withIndex("by_key", (q) => q.eq("key", RUNTIME_CONFIG_KEYS.provider))
|
|
431
540
|
.unique();
|
|
432
541
|
if (!existing) {
|
|
433
542
|
await ctx.db.insert("runtimeConfig", {
|
|
434
|
-
key:
|
|
543
|
+
key: RUNTIME_CONFIG_KEYS.provider,
|
|
435
544
|
providerConfig: args.providerConfig,
|
|
436
545
|
updatedAt: nowMs,
|
|
437
546
|
});
|
|
@@ -445,6 +554,511 @@ export const setProviderRuntimeConfig = mutation({
|
|
|
445
554
|
},
|
|
446
555
|
});
|
|
447
556
|
|
|
557
|
+
export const getMessageRuntimeConfig = internalQuery({
|
|
558
|
+
args: {},
|
|
559
|
+
returns: v.union(v.null(), messageRuntimeConfigValidator),
|
|
560
|
+
handler: async (ctx) => {
|
|
561
|
+
const row = await ctx.db
|
|
562
|
+
.query("runtimeConfig")
|
|
563
|
+
.withIndex("by_key", (q) => q.eq("key", RUNTIME_CONFIG_KEYS.message))
|
|
564
|
+
.unique();
|
|
565
|
+
if (!row?.messageConfig) {
|
|
566
|
+
return null;
|
|
567
|
+
}
|
|
568
|
+
return row.messageConfig;
|
|
569
|
+
},
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
export const upsertMessageRuntimeConfig = internalMutation({
|
|
573
|
+
args: {
|
|
574
|
+
messageConfig: messageRuntimeConfigValidator,
|
|
575
|
+
nowMs: v.optional(v.number()),
|
|
576
|
+
},
|
|
577
|
+
returns: v.null(),
|
|
578
|
+
handler: async (ctx, args) => {
|
|
579
|
+
const nowMs = args.nowMs ?? Date.now();
|
|
580
|
+
const normalizedMessageConfig = normalizeMessageRuntimeConfig(args.messageConfig);
|
|
581
|
+
const existing = await ctx.db
|
|
582
|
+
.query("runtimeConfig")
|
|
583
|
+
.withIndex("by_key", (q) => q.eq("key", RUNTIME_CONFIG_KEYS.message))
|
|
584
|
+
.unique();
|
|
585
|
+
if (normalizedMessageConfig === null) {
|
|
586
|
+
if (existing) {
|
|
587
|
+
await ctx.db.delete(existing._id);
|
|
588
|
+
}
|
|
589
|
+
return null;
|
|
590
|
+
}
|
|
591
|
+
if (!existing) {
|
|
592
|
+
await ctx.db.insert("runtimeConfig", {
|
|
593
|
+
key: RUNTIME_CONFIG_KEYS.message,
|
|
594
|
+
messageConfig: normalizedMessageConfig,
|
|
595
|
+
updatedAt: nowMs,
|
|
596
|
+
});
|
|
597
|
+
return null;
|
|
598
|
+
}
|
|
599
|
+
await ctx.db.patch(existing._id, {
|
|
600
|
+
messageConfig: normalizedMessageConfig,
|
|
601
|
+
updatedAt: nowMs,
|
|
602
|
+
});
|
|
603
|
+
return null;
|
|
604
|
+
},
|
|
605
|
+
});
|
|
606
|
+
|
|
607
|
+
export const messageRuntimeConfig = query({
|
|
608
|
+
args: {},
|
|
609
|
+
returns: v.union(v.null(), messageRuntimeConfigValidator),
|
|
610
|
+
handler: async (ctx) => {
|
|
611
|
+
const row = await ctx.db
|
|
612
|
+
.query("runtimeConfig")
|
|
613
|
+
.withIndex("by_key", (q) => q.eq("key", RUNTIME_CONFIG_KEYS.message))
|
|
614
|
+
.unique();
|
|
615
|
+
if (!row?.messageConfig) {
|
|
616
|
+
return null;
|
|
617
|
+
}
|
|
618
|
+
return row.messageConfig;
|
|
619
|
+
},
|
|
620
|
+
});
|
|
621
|
+
|
|
622
|
+
export const setMessageRuntimeConfig = mutation({
|
|
623
|
+
args: {
|
|
624
|
+
messageConfig: messageRuntimeConfigValidator,
|
|
625
|
+
nowMs: v.optional(v.number()),
|
|
626
|
+
},
|
|
627
|
+
returns: v.null(),
|
|
628
|
+
handler: async (ctx, args) => {
|
|
629
|
+
const nowMs = args.nowMs ?? Date.now();
|
|
630
|
+
const normalizedMessageConfig = normalizeMessageRuntimeConfig(args.messageConfig);
|
|
631
|
+
const existing = await ctx.db
|
|
632
|
+
.query("runtimeConfig")
|
|
633
|
+
.withIndex("by_key", (q) => q.eq("key", RUNTIME_CONFIG_KEYS.message))
|
|
634
|
+
.unique();
|
|
635
|
+
if (normalizedMessageConfig === null) {
|
|
636
|
+
if (existing) {
|
|
637
|
+
await ctx.db.delete(existing._id);
|
|
638
|
+
}
|
|
639
|
+
return null;
|
|
640
|
+
}
|
|
641
|
+
if (!existing) {
|
|
642
|
+
await ctx.db.insert("runtimeConfig", {
|
|
643
|
+
key: RUNTIME_CONFIG_KEYS.message,
|
|
644
|
+
messageConfig: normalizedMessageConfig,
|
|
645
|
+
updatedAt: nowMs,
|
|
646
|
+
});
|
|
647
|
+
return null;
|
|
648
|
+
}
|
|
649
|
+
await ctx.db.patch(existing._id, {
|
|
650
|
+
messageConfig: normalizedMessageConfig,
|
|
651
|
+
updatedAt: nowMs,
|
|
652
|
+
});
|
|
653
|
+
return null;
|
|
654
|
+
},
|
|
655
|
+
});
|
|
656
|
+
|
|
657
|
+
export const deployGlobalSkill = mutation({
|
|
658
|
+
args: {
|
|
659
|
+
slug: v.string(),
|
|
660
|
+
displayName: v.optional(v.string()),
|
|
661
|
+
description: v.optional(v.string()),
|
|
662
|
+
version: v.string(),
|
|
663
|
+
sourceJs: v.string(),
|
|
664
|
+
entryPoint: v.optional(v.string()),
|
|
665
|
+
moduleFormat: v.optional(globalSkillModuleFormatValidator),
|
|
666
|
+
releaseChannel: v.optional(globalSkillReleaseChannelValidator),
|
|
667
|
+
actor: v.optional(v.string()),
|
|
668
|
+
nowMs: v.optional(v.number()),
|
|
669
|
+
},
|
|
670
|
+
returns: v.object({
|
|
671
|
+
skillId: v.id("globalSkills"),
|
|
672
|
+
versionId: v.id("globalSkillVersions"),
|
|
673
|
+
releaseId: v.id("globalSkillReleases"),
|
|
674
|
+
slug: v.string(),
|
|
675
|
+
version: v.string(),
|
|
676
|
+
sha256: v.string(),
|
|
677
|
+
releaseChannel: globalSkillReleaseChannelValidator,
|
|
678
|
+
}),
|
|
679
|
+
handler: async (ctx, args) => {
|
|
680
|
+
const nowMs = args.nowMs ?? Date.now();
|
|
681
|
+
const slug = args.slug.trim().toLowerCase();
|
|
682
|
+
const version = args.version.trim();
|
|
683
|
+
const entryPoint = (args.entryPoint ?? "default").trim();
|
|
684
|
+
const releaseChannel = args.releaseChannel ?? "stable";
|
|
685
|
+
const moduleFormat = args.moduleFormat ?? "esm";
|
|
686
|
+
const actor = args.actor?.trim() || "system";
|
|
687
|
+
const sourceJs = args.sourceJs.trim();
|
|
688
|
+
|
|
689
|
+
if (!/^[a-z0-9][a-z0-9-_]{1,127}$/.test(slug)) {
|
|
690
|
+
throw new Error("Invalid skill slug. Use lowercase letters, numbers, '-' and '_'.");
|
|
691
|
+
}
|
|
692
|
+
if (!/^\d+\.\d+\.\d+(?:[-+][A-Za-z0-9.-]+)?$/.test(version)) {
|
|
693
|
+
throw new Error("Invalid skill version. Use semantic versioning format.");
|
|
694
|
+
}
|
|
695
|
+
if (sourceJs.length < 16) {
|
|
696
|
+
throw new Error("Skill source is too short.");
|
|
697
|
+
}
|
|
698
|
+
if (sourceJs.length > 200_000) {
|
|
699
|
+
throw new Error("Skill source too large (max 200KB).");
|
|
700
|
+
}
|
|
701
|
+
if (!entryPoint) {
|
|
702
|
+
throw new Error("entryPoint is required.");
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
const sha256 = await computeSha256Hex(sourceJs);
|
|
706
|
+
|
|
707
|
+
const existingSkill = await ctx.db
|
|
708
|
+
.query("globalSkills")
|
|
709
|
+
.withIndex("by_slug", (q) => q.eq("slug", slug))
|
|
710
|
+
.unique();
|
|
711
|
+
const skillId =
|
|
712
|
+
existingSkill?._id ??
|
|
713
|
+
(await ctx.db.insert("globalSkills", {
|
|
714
|
+
slug,
|
|
715
|
+
displayName: args.displayName?.trim() || slug,
|
|
716
|
+
description: args.description?.trim(),
|
|
717
|
+
status: "active",
|
|
718
|
+
createdBy: actor,
|
|
719
|
+
updatedBy: actor,
|
|
720
|
+
createdAt: nowMs,
|
|
721
|
+
updatedAt: nowMs,
|
|
722
|
+
}));
|
|
723
|
+
|
|
724
|
+
if (existingSkill) {
|
|
725
|
+
await ctx.db.patch(skillId, {
|
|
726
|
+
displayName: args.displayName?.trim() || existingSkill.displayName,
|
|
727
|
+
description:
|
|
728
|
+
args.description !== undefined ? args.description.trim() : existingSkill.description,
|
|
729
|
+
status: "active",
|
|
730
|
+
updatedBy: actor,
|
|
731
|
+
updatedAt: nowMs,
|
|
732
|
+
});
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
const existingVersion = await ctx.db
|
|
736
|
+
.query("globalSkillVersions")
|
|
737
|
+
.withIndex("by_skillId_and_version", (q) => q.eq("skillId", skillId).eq("version", version))
|
|
738
|
+
.unique();
|
|
739
|
+
|
|
740
|
+
let versionId = existingVersion?._id;
|
|
741
|
+
if (!existingVersion) {
|
|
742
|
+
versionId = await ctx.db.insert("globalSkillVersions", {
|
|
743
|
+
skillId,
|
|
744
|
+
version,
|
|
745
|
+
moduleFormat,
|
|
746
|
+
entryPoint,
|
|
747
|
+
sourceJs,
|
|
748
|
+
sha256,
|
|
749
|
+
createdBy: actor,
|
|
750
|
+
createdAt: nowMs,
|
|
751
|
+
});
|
|
752
|
+
} else if (existingVersion.sha256 !== sha256) {
|
|
753
|
+
throw new Error(`Skill ${slug}@${version} already exists with a different source.`);
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
const activeReleases = await ctx.db
|
|
757
|
+
.query("globalSkillReleases")
|
|
758
|
+
.withIndex("by_skillId_and_releaseChannel_and_isActive", (q) =>
|
|
759
|
+
q.eq("skillId", skillId).eq("releaseChannel", releaseChannel).eq("isActive", true),
|
|
760
|
+
)
|
|
761
|
+
.collect();
|
|
762
|
+
for (const release of activeReleases) {
|
|
763
|
+
await ctx.db.patch(release._id, { isActive: false });
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
const releaseId = await ctx.db.insert("globalSkillReleases", {
|
|
767
|
+
skillId,
|
|
768
|
+
versionId: versionId!,
|
|
769
|
+
releaseChannel,
|
|
770
|
+
isActive: true,
|
|
771
|
+
activatedBy: actor,
|
|
772
|
+
activatedAt: nowMs,
|
|
773
|
+
});
|
|
774
|
+
|
|
775
|
+
return {
|
|
776
|
+
skillId,
|
|
777
|
+
versionId: versionId!,
|
|
778
|
+
releaseId,
|
|
779
|
+
slug,
|
|
780
|
+
version,
|
|
781
|
+
sha256,
|
|
782
|
+
releaseChannel,
|
|
783
|
+
};
|
|
784
|
+
},
|
|
785
|
+
});
|
|
786
|
+
|
|
787
|
+
export const listGlobalSkills = query({
|
|
788
|
+
args: {
|
|
789
|
+
releaseChannel: v.optional(globalSkillReleaseChannelValidator),
|
|
790
|
+
status: v.optional(globalSkillStatusValidator),
|
|
791
|
+
limit: v.optional(v.number()),
|
|
792
|
+
},
|
|
793
|
+
returns: v.array(
|
|
794
|
+
v.object({
|
|
795
|
+
skillId: v.id("globalSkills"),
|
|
796
|
+
slug: v.string(),
|
|
797
|
+
displayName: v.string(),
|
|
798
|
+
description: v.optional(v.string()),
|
|
799
|
+
status: globalSkillStatusValidator,
|
|
800
|
+
updatedAt: v.number(),
|
|
801
|
+
activeRelease: v.union(
|
|
802
|
+
v.null(),
|
|
803
|
+
v.object({
|
|
804
|
+
releaseId: v.id("globalSkillReleases"),
|
|
805
|
+
versionId: v.id("globalSkillVersions"),
|
|
806
|
+
version: v.string(),
|
|
807
|
+
sha256: v.string(),
|
|
808
|
+
moduleFormat: globalSkillModuleFormatValidator,
|
|
809
|
+
entryPoint: v.string(),
|
|
810
|
+
releaseChannel: globalSkillReleaseChannelValidator,
|
|
811
|
+
activatedAt: v.number(),
|
|
812
|
+
}),
|
|
813
|
+
),
|
|
814
|
+
}),
|
|
815
|
+
),
|
|
816
|
+
handler: async (ctx, args) => {
|
|
817
|
+
const releaseChannel = args.releaseChannel ?? "stable";
|
|
818
|
+
const limit = Math.max(1, Math.min(args.limit ?? 200, 500));
|
|
819
|
+
const skills =
|
|
820
|
+
args.status !== undefined
|
|
821
|
+
? await ctx.db
|
|
822
|
+
.query("globalSkills")
|
|
823
|
+
.withIndex("by_status", (q) => q.eq("status", args.status!))
|
|
824
|
+
.take(limit)
|
|
825
|
+
: await ctx.db.query("globalSkills").take(limit);
|
|
826
|
+
|
|
827
|
+
const sortedSkills = [...skills].sort((a, b) => a.slug.localeCompare(b.slug));
|
|
828
|
+
const out: Array<{
|
|
829
|
+
skillId: any;
|
|
830
|
+
slug: string;
|
|
831
|
+
displayName: string;
|
|
832
|
+
description?: string;
|
|
833
|
+
status: "active" | "disabled";
|
|
834
|
+
updatedAt: number;
|
|
835
|
+
activeRelease: {
|
|
836
|
+
releaseId: any;
|
|
837
|
+
versionId: any;
|
|
838
|
+
version: string;
|
|
839
|
+
sha256: string;
|
|
840
|
+
moduleFormat: "esm" | "cjs";
|
|
841
|
+
entryPoint: string;
|
|
842
|
+
releaseChannel: "stable" | "canary";
|
|
843
|
+
activatedAt: number;
|
|
844
|
+
} | null;
|
|
845
|
+
}> = [];
|
|
846
|
+
|
|
847
|
+
for (const skill of sortedSkills) {
|
|
848
|
+
const activeRelease = await ctx.db
|
|
849
|
+
.query("globalSkillReleases")
|
|
850
|
+
.withIndex("by_skillId_and_releaseChannel_and_isActive", (q) =>
|
|
851
|
+
q.eq("skillId", skill._id).eq("releaseChannel", releaseChannel).eq("isActive", true),
|
|
852
|
+
)
|
|
853
|
+
.first();
|
|
854
|
+
|
|
855
|
+
let activeReleaseRow: (typeof out)[number]["activeRelease"] = null;
|
|
856
|
+
if (activeRelease) {
|
|
857
|
+
const version = await ctx.db.get(activeRelease.versionId);
|
|
858
|
+
if (version) {
|
|
859
|
+
activeReleaseRow = {
|
|
860
|
+
releaseId: activeRelease._id,
|
|
861
|
+
versionId: version._id,
|
|
862
|
+
version: version.version,
|
|
863
|
+
sha256: version.sha256,
|
|
864
|
+
moduleFormat: version.moduleFormat,
|
|
865
|
+
entryPoint: version.entryPoint,
|
|
866
|
+
releaseChannel: activeRelease.releaseChannel,
|
|
867
|
+
activatedAt: activeRelease.activatedAt,
|
|
868
|
+
};
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
out.push({
|
|
873
|
+
skillId: skill._id,
|
|
874
|
+
slug: skill.slug,
|
|
875
|
+
displayName: skill.displayName,
|
|
876
|
+
description: skill.description,
|
|
877
|
+
status: skill.status,
|
|
878
|
+
updatedAt: skill.updatedAt,
|
|
879
|
+
activeRelease: activeReleaseRow,
|
|
880
|
+
});
|
|
881
|
+
}
|
|
882
|
+
return out;
|
|
883
|
+
},
|
|
884
|
+
});
|
|
885
|
+
|
|
886
|
+
export const getWorkerGlobalSkillsManifest = query({
|
|
887
|
+
args: {
|
|
888
|
+
workspaceId: v.optional(v.string()),
|
|
889
|
+
workerId: v.optional(v.string()),
|
|
890
|
+
releaseChannel: v.optional(globalSkillReleaseChannelValidator),
|
|
891
|
+
},
|
|
892
|
+
returns: v.object({
|
|
893
|
+
manifestVersion: v.string(),
|
|
894
|
+
generatedAt: v.number(),
|
|
895
|
+
releaseChannel: globalSkillReleaseChannelValidator,
|
|
896
|
+
workspaceId: v.string(),
|
|
897
|
+
skills: v.array(globalSkillManifestItemValidator),
|
|
898
|
+
}),
|
|
899
|
+
handler: async (ctx, args) => {
|
|
900
|
+
const nowMs = Date.now();
|
|
901
|
+
const releaseChannel = args.releaseChannel ?? "stable";
|
|
902
|
+
const activeSkills = await ctx.db
|
|
903
|
+
.query("globalSkills")
|
|
904
|
+
.withIndex("by_status", (q) => q.eq("status", "active"))
|
|
905
|
+
.collect();
|
|
906
|
+
const sortedSkills = [...activeSkills].sort((a, b) => a.slug.localeCompare(b.slug));
|
|
907
|
+
|
|
908
|
+
const manifestSkills: Array<{
|
|
909
|
+
slug: string;
|
|
910
|
+
version: string;
|
|
911
|
+
moduleFormat: "esm" | "cjs";
|
|
912
|
+
entryPoint: string;
|
|
913
|
+
sourceJs: string;
|
|
914
|
+
sha256: string;
|
|
915
|
+
}> = [];
|
|
916
|
+
|
|
917
|
+
for (const skill of sortedSkills) {
|
|
918
|
+
const activeRelease = await ctx.db
|
|
919
|
+
.query("globalSkillReleases")
|
|
920
|
+
.withIndex("by_skillId_and_releaseChannel_and_isActive", (q) =>
|
|
921
|
+
q.eq("skillId", skill._id).eq("releaseChannel", releaseChannel).eq("isActive", true),
|
|
922
|
+
)
|
|
923
|
+
.first();
|
|
924
|
+
if (!activeRelease) continue;
|
|
925
|
+
|
|
926
|
+
const version = await ctx.db.get(activeRelease.versionId);
|
|
927
|
+
if (!version) continue;
|
|
928
|
+
manifestSkills.push({
|
|
929
|
+
slug: skill.slug,
|
|
930
|
+
version: version.version,
|
|
931
|
+
moduleFormat: version.moduleFormat,
|
|
932
|
+
entryPoint: version.entryPoint,
|
|
933
|
+
sourceJs: version.sourceJs,
|
|
934
|
+
sha256: version.sha256,
|
|
935
|
+
});
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
manifestSkills.sort((a, b) => {
|
|
939
|
+
if (a.slug !== b.slug) return a.slug.localeCompare(b.slug);
|
|
940
|
+
return a.version.localeCompare(b.version);
|
|
941
|
+
});
|
|
942
|
+
|
|
943
|
+
const fingerprintSeed = manifestSkills
|
|
944
|
+
.map((row) => `${row.slug}@${row.version}:${row.sha256}`)
|
|
945
|
+
.join("|");
|
|
946
|
+
const manifestVersion = await computeSha256Hex(fingerprintSeed || "empty");
|
|
947
|
+
|
|
948
|
+
return {
|
|
949
|
+
manifestVersion,
|
|
950
|
+
generatedAt: nowMs,
|
|
951
|
+
releaseChannel,
|
|
952
|
+
workspaceId: args.workspaceId ?? "default",
|
|
953
|
+
skills: manifestSkills,
|
|
954
|
+
};
|
|
955
|
+
},
|
|
956
|
+
});
|
|
957
|
+
|
|
958
|
+
export const setGlobalSkillStatus = mutation({
|
|
959
|
+
args: {
|
|
960
|
+
slug: v.string(),
|
|
961
|
+
status: globalSkillStatusValidator,
|
|
962
|
+
actor: v.optional(v.string()),
|
|
963
|
+
nowMs: v.optional(v.number()),
|
|
964
|
+
},
|
|
965
|
+
returns: v.object({
|
|
966
|
+
updated: v.boolean(),
|
|
967
|
+
slug: v.string(),
|
|
968
|
+
status: globalSkillStatusValidator,
|
|
969
|
+
}),
|
|
970
|
+
handler: async (ctx, args) => {
|
|
971
|
+
const slug = args.slug.trim().toLowerCase();
|
|
972
|
+
const nowMs = args.nowMs ?? Date.now();
|
|
973
|
+
const actor = args.actor?.trim() || "system";
|
|
974
|
+
const skill = await ctx.db
|
|
975
|
+
.query("globalSkills")
|
|
976
|
+
.withIndex("by_slug", (q) => q.eq("slug", slug))
|
|
977
|
+
.unique();
|
|
978
|
+
if (!skill) {
|
|
979
|
+
return { updated: false, slug, status: args.status };
|
|
980
|
+
}
|
|
981
|
+
await ctx.db.patch(skill._id, {
|
|
982
|
+
status: args.status,
|
|
983
|
+
updatedBy: actor,
|
|
984
|
+
updatedAt: nowMs,
|
|
985
|
+
});
|
|
986
|
+
return { updated: true, slug, status: args.status };
|
|
987
|
+
},
|
|
988
|
+
});
|
|
989
|
+
|
|
990
|
+
export const deleteGlobalSkill = mutation({
|
|
991
|
+
args: {
|
|
992
|
+
slug: v.string(),
|
|
993
|
+
},
|
|
994
|
+
returns: v.object({
|
|
995
|
+
deleted: v.boolean(),
|
|
996
|
+
slug: v.string(),
|
|
997
|
+
deletedVersions: v.number(),
|
|
998
|
+
deletedReleases: v.number(),
|
|
999
|
+
}),
|
|
1000
|
+
handler: async (ctx, args) => {
|
|
1001
|
+
const slug = args.slug.trim().toLowerCase();
|
|
1002
|
+
const skill = await ctx.db
|
|
1003
|
+
.query("globalSkills")
|
|
1004
|
+
.withIndex("by_slug", (q) => q.eq("slug", slug))
|
|
1005
|
+
.unique();
|
|
1006
|
+
if (!skill) {
|
|
1007
|
+
return { deleted: false, slug, deletedVersions: 0, deletedReleases: 0 };
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
const stableActiveReleases = await ctx.db
|
|
1011
|
+
.query("globalSkillReleases")
|
|
1012
|
+
.withIndex("by_skillId_and_releaseChannel_and_isActive", (q) =>
|
|
1013
|
+
q.eq("skillId", skill._id).eq("releaseChannel", "stable").eq("isActive", true),
|
|
1014
|
+
)
|
|
1015
|
+
.collect();
|
|
1016
|
+
const stableInactiveReleases = await ctx.db
|
|
1017
|
+
.query("globalSkillReleases")
|
|
1018
|
+
.withIndex("by_skillId_and_releaseChannel_and_isActive", (q) =>
|
|
1019
|
+
q.eq("skillId", skill._id).eq("releaseChannel", "stable").eq("isActive", false),
|
|
1020
|
+
)
|
|
1021
|
+
.collect();
|
|
1022
|
+
const canaryActiveReleases = await ctx.db
|
|
1023
|
+
.query("globalSkillReleases")
|
|
1024
|
+
.withIndex("by_skillId_and_releaseChannel_and_isActive", (q) =>
|
|
1025
|
+
q.eq("skillId", skill._id).eq("releaseChannel", "canary").eq("isActive", true),
|
|
1026
|
+
)
|
|
1027
|
+
.collect();
|
|
1028
|
+
const canaryInactiveReleases = await ctx.db
|
|
1029
|
+
.query("globalSkillReleases")
|
|
1030
|
+
.withIndex("by_skillId_and_releaseChannel_and_isActive", (q) =>
|
|
1031
|
+
q.eq("skillId", skill._id).eq("releaseChannel", "canary").eq("isActive", false),
|
|
1032
|
+
)
|
|
1033
|
+
.collect();
|
|
1034
|
+
const allReleases = [
|
|
1035
|
+
...stableActiveReleases,
|
|
1036
|
+
...stableInactiveReleases,
|
|
1037
|
+
...canaryActiveReleases,
|
|
1038
|
+
...canaryInactiveReleases,
|
|
1039
|
+
];
|
|
1040
|
+
const versions = await ctx.db
|
|
1041
|
+
.query("globalSkillVersions")
|
|
1042
|
+
.withIndex("by_skillId_and_createdAt", (q) => q.eq("skillId", skill._id))
|
|
1043
|
+
.collect();
|
|
1044
|
+
|
|
1045
|
+
for (const release of allReleases) {
|
|
1046
|
+
await ctx.db.delete(release._id);
|
|
1047
|
+
}
|
|
1048
|
+
for (const version of versions) {
|
|
1049
|
+
await ctx.db.delete(version._id);
|
|
1050
|
+
}
|
|
1051
|
+
await ctx.db.delete(skill._id);
|
|
1052
|
+
|
|
1053
|
+
return {
|
|
1054
|
+
deleted: true,
|
|
1055
|
+
slug,
|
|
1056
|
+
deletedVersions: versions.length,
|
|
1057
|
+
deletedReleases: allReleases.length,
|
|
1058
|
+
};
|
|
1059
|
+
},
|
|
1060
|
+
});
|
|
1061
|
+
|
|
448
1062
|
export const generateMediaUploadUrl = mutation({
|
|
449
1063
|
args: {},
|
|
450
1064
|
returns: v.object({
|
|
@@ -1623,6 +2237,36 @@ async function resolveBridgeRuntimeConfig(
|
|
|
1623
2237
|
};
|
|
1624
2238
|
}
|
|
1625
2239
|
|
|
2240
|
+
function appendSystemPromptToMessage(messageText: string, systemPrompt?: string): string {
|
|
2241
|
+
const normalizedSystemPrompt = normalizeSystemPrompt(systemPrompt);
|
|
2242
|
+
if (normalizedSystemPrompt === null) {
|
|
2243
|
+
return messageText;
|
|
2244
|
+
}
|
|
2245
|
+
const normalizedMessageText = messageText.trimEnd();
|
|
2246
|
+
if (normalizedMessageText.length === 0) {
|
|
2247
|
+
return normalizedSystemPrompt;
|
|
2248
|
+
}
|
|
2249
|
+
return `${normalizedMessageText}\n\n${normalizedSystemPrompt}`;
|
|
2250
|
+
}
|
|
2251
|
+
|
|
2252
|
+
function normalizeMessageRuntimeConfig(
|
|
2253
|
+
messageConfig: { systemPrompt?: string } | null | undefined,
|
|
2254
|
+
): { systemPrompt?: string } | null {
|
|
2255
|
+
const systemPrompt = normalizeSystemPrompt(messageConfig?.systemPrompt);
|
|
2256
|
+
if (systemPrompt === null) {
|
|
2257
|
+
return null;
|
|
2258
|
+
}
|
|
2259
|
+
return { systemPrompt };
|
|
2260
|
+
}
|
|
2261
|
+
|
|
2262
|
+
function normalizeSystemPrompt(systemPrompt?: string | null): string | null {
|
|
2263
|
+
if (typeof systemPrompt !== "string") {
|
|
2264
|
+
return null;
|
|
2265
|
+
}
|
|
2266
|
+
const normalizedSystemPrompt = systemPrompt.trim();
|
|
2267
|
+
return normalizedSystemPrompt.length > 0 ? normalizedSystemPrompt : null;
|
|
2268
|
+
}
|
|
2269
|
+
|
|
1626
2270
|
function getBridgeSecretRefsForProfile(
|
|
1627
2271
|
agentKey: string,
|
|
1628
2272
|
bridgeConfig:
|
|
@@ -1688,6 +2332,14 @@ function fingerprintConversationDelta(
|
|
|
1688
2332
|
return `f${(hash >>> 0).toString(16)}`;
|
|
1689
2333
|
}
|
|
1690
2334
|
|
|
2335
|
+
async function computeSha256Hex(input: string): Promise<string> {
|
|
2336
|
+
const bytes = new TextEncoder().encode(input);
|
|
2337
|
+
const digest = await crypto.subtle.digest("SHA-256", bytes);
|
|
2338
|
+
return Array.from(new Uint8Array(digest))
|
|
2339
|
+
.map((value) => value.toString(16).padStart(2, "0"))
|
|
2340
|
+
.join("");
|
|
2341
|
+
}
|
|
2342
|
+
|
|
1691
2343
|
function encryptSecretValue(plaintext: string): string {
|
|
1692
2344
|
const units = Array.from(plaintext);
|
|
1693
2345
|
return units
|