@frockbot/plugin-flock 0.1.3 → 0.1.4
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/package.json +7 -7
- package/src/agent.test.ts +3 -12
- package/src/client/FlockOverlay.vue +3 -3
- package/src/shared.test.ts +5 -16
- package/src/shared.ts +1 -116
- package/src/user.test.ts +6 -123
- package/src/user.ts +3 -59
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frockbot/plugin-flock",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -27,16 +27,16 @@
|
|
|
27
27
|
"typecheck": "vue-tsc --noEmit -p tsconfig.json"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@frockbot/client-core": "0.1.
|
|
31
|
-
"@frockbot/client-ui": "0.1.
|
|
32
|
-
"@frockbot/configuration-core": "0.1.
|
|
33
|
-
"@frockbot/kernel-contracts": "0.1.
|
|
34
|
-
"@frockbot/plugin-shell": "0.1.
|
|
30
|
+
"@frockbot/client-core": "0.1.4",
|
|
31
|
+
"@frockbot/client-ui": "0.1.4",
|
|
32
|
+
"@frockbot/configuration-core": "0.1.4",
|
|
33
|
+
"@frockbot/kernel-contracts": "0.1.4",
|
|
34
|
+
"@frockbot/plugin-shell": "0.1.4",
|
|
35
35
|
"cordis": "4.0.0-rc.8",
|
|
36
36
|
"vue": "3.5.41"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"@frockbot/plugin-testkit": "0.1.
|
|
39
|
+
"@frockbot/plugin-testkit": "0.1.4",
|
|
40
40
|
"@types/bun": "1.4.0",
|
|
41
41
|
"@vitejs/plugin-vue": "6.0.8",
|
|
42
42
|
"css-tree": "2.3.1",
|
package/src/agent.test.ts
CHANGED
|
@@ -94,14 +94,6 @@ function harness(initial?: Partial<BotSettingsViewV1>): Harness {
|
|
|
94
94
|
const storage = memoryStorage();
|
|
95
95
|
const flock = createFlockUserBackendContribution({
|
|
96
96
|
storage,
|
|
97
|
-
readUserSettings: () =>
|
|
98
|
-
Promise.resolve({
|
|
99
|
-
schemaVersion: 1,
|
|
100
|
-
revision: 0,
|
|
101
|
-
profile: { name: "User" },
|
|
102
|
-
packages: [],
|
|
103
|
-
connections: [],
|
|
104
|
-
}),
|
|
105
97
|
now: () => new Date("2026-08-31T10:00:00.000Z"),
|
|
106
98
|
random: () => 0,
|
|
107
99
|
commandBotLifecycle: () => {
|
|
@@ -339,10 +331,9 @@ describe("bot_create", () => {
|
|
|
339
331
|
expect(created.botId).toBe(
|
|
340
332
|
await createdBotIdV1(OWNER, CONTEXT.effectId, "Budget"),
|
|
341
333
|
);
|
|
342
|
-
//
|
|
343
|
-
//
|
|
344
|
-
expect(created
|
|
345
|
-
expect(created.initialModelBinding).toBeUndefined();
|
|
334
|
+
// Model and Capability authority resolve account-wide on the new Bot's
|
|
335
|
+
// next admitted Turn; neither is copied into its registration.
|
|
336
|
+
expect(Object.hasOwn(created, "initialModel")).toBe(false);
|
|
346
337
|
expect(result.content).toContain(created.botId);
|
|
347
338
|
});
|
|
348
339
|
|
|
@@ -73,7 +73,7 @@ onBeforeUnmount(() => restoreFocus?.focus());
|
|
|
73
73
|
<h1 id="flock-title">Archive this Bot?</h1>
|
|
74
74
|
<p>
|
|
75
75
|
Archiving stops new work and hides the Bot from your active flock.
|
|
76
|
-
History
|
|
76
|
+
History and settings are preserved for restoration.
|
|
77
77
|
</p>
|
|
78
78
|
<p
|
|
79
79
|
v-if="flock.error"
|
|
@@ -185,8 +185,8 @@ onBeforeUnmount(() => restoreFocus?.focus());
|
|
|
185
185
|
</div>
|
|
186
186
|
</fieldset>
|
|
187
187
|
<div class="flock-note">
|
|
188
|
-
This identity
|
|
189
|
-
re-roll it.
|
|
188
|
+
This identity stays with your Bot. Refreshing or switching devices
|
|
189
|
+
won’t re-roll it.
|
|
190
190
|
</div>
|
|
191
191
|
<p
|
|
192
192
|
v-if="flock.error"
|
package/src/shared.test.ts
CHANGED
|
@@ -69,10 +69,9 @@ describe("Flock v1 contracts", () => {
|
|
|
69
69
|
).toThrow("unknown or missing field");
|
|
70
70
|
});
|
|
71
71
|
|
|
72
|
-
test("
|
|
72
|
+
test("rejects retired model seed fields", () => {
|
|
73
73
|
const sheep = randomSheepRecipeV1(() => 0);
|
|
74
|
-
|
|
75
|
-
expect(
|
|
74
|
+
expect(() =>
|
|
76
75
|
decodeDirectoryViewV1({
|
|
77
76
|
schemaVersion: 1,
|
|
78
77
|
revision: 1,
|
|
@@ -84,23 +83,13 @@ describe("Flock v1 contracts", () => {
|
|
|
84
83
|
initialName: "Alpha",
|
|
85
84
|
initialModel: {
|
|
86
85
|
connectionId: "connection-1",
|
|
87
|
-
providerModelId,
|
|
88
|
-
},
|
|
89
|
-
initialModelBinding: {
|
|
90
|
-
assignment: {
|
|
91
|
-
assignmentId: "create-alpha",
|
|
92
|
-
packageId: "provider-ollama-cloud",
|
|
93
|
-
capabilityId: "ollama-cloud-models",
|
|
94
|
-
connectionId: "connection-1",
|
|
95
|
-
state: "enabled",
|
|
96
|
-
},
|
|
97
|
-
generation: "create-alpha",
|
|
86
|
+
providerModelId: "model-1",
|
|
98
87
|
},
|
|
99
88
|
sheep,
|
|
100
89
|
},
|
|
101
90
|
],
|
|
102
|
-
})
|
|
103
|
-
).
|
|
91
|
+
}),
|
|
92
|
+
).toThrow("unknown or missing field");
|
|
104
93
|
expect(() =>
|
|
105
94
|
decodeCreateBotCommandV1({
|
|
106
95
|
schemaVersion: 1,
|
package/src/shared.ts
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
// Shared configuration types remain provider-neutral at this package seam.
|
|
2
2
|
import {
|
|
3
|
-
decodeCapabilityAssignmentV1,
|
|
4
3
|
decodeBotIdV1,
|
|
5
4
|
decodeBotSelfWriterV1,
|
|
6
5
|
isPublicIdentifier,
|
|
7
6
|
type BotNameProvenanceV1,
|
|
8
7
|
type BotSelfWriterV1,
|
|
9
|
-
type CapabilityAssignmentView,
|
|
10
|
-
type ModelAssignment,
|
|
11
8
|
} from "@frockbot/configuration-core";
|
|
12
9
|
export type { BotSelfWriterV1 } from "@frockbot/configuration-core";
|
|
13
10
|
import assetManifest from "../assets/manifest.json" with { type: "json" };
|
|
@@ -26,10 +23,6 @@ export interface SheepRecipeV1 {
|
|
|
26
23
|
middle: string;
|
|
27
24
|
lower: string;
|
|
28
25
|
}
|
|
29
|
-
export interface InitialModelBindingV1 {
|
|
30
|
-
assignment: CapabilityAssignmentView;
|
|
31
|
-
generation: string;
|
|
32
|
-
}
|
|
33
26
|
export interface BotRegistrationV1 {
|
|
34
27
|
schemaVersion: 1;
|
|
35
28
|
botId: string;
|
|
@@ -42,13 +35,6 @@ export interface BotRegistrationV1 {
|
|
|
42
35
|
* Durable Object, which no other Bot may write.
|
|
43
36
|
*/
|
|
44
37
|
initialDescription?: string;
|
|
45
|
-
initialModel?: ModelAssignment;
|
|
46
|
-
initialModelBinding?: InitialModelBindingV1;
|
|
47
|
-
/**
|
|
48
|
-
* Connection-less Capability authority snapshotted from the User's installed
|
|
49
|
-
* Packages when this Bot was admitted.
|
|
50
|
-
*/
|
|
51
|
-
initialAssignments?: CapabilityAssignmentView[];
|
|
52
38
|
/**
|
|
53
39
|
* The Bot and Turn that created this Bot, when a Bot created it. Absent for
|
|
54
40
|
* a User-created Bot and for every registration written before this existed.
|
|
@@ -264,63 +250,6 @@ function revision(value: unknown): number {
|
|
|
264
250
|
throw new FlockDecodeError("revision is invalid");
|
|
265
251
|
return value as number;
|
|
266
252
|
}
|
|
267
|
-
function modelAssignment(value: unknown): ModelAssignment {
|
|
268
|
-
const model = record(value, "initialModel");
|
|
269
|
-
exact(model, ["connectionId", "providerModelId"]);
|
|
270
|
-
return {
|
|
271
|
-
connectionId: identifier(model.connectionId, "initialModel.connectionId"),
|
|
272
|
-
providerModelId: boundedText(
|
|
273
|
-
model.providerModelId,
|
|
274
|
-
"initialModel.providerModelId",
|
|
275
|
-
256,
|
|
276
|
-
),
|
|
277
|
-
};
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
function initialModelBinding(value: unknown): InitialModelBindingV1 {
|
|
281
|
-
const binding = record(value, "initialModelBinding");
|
|
282
|
-
exact(binding, ["assignment", "generation"]);
|
|
283
|
-
const assignment = record(
|
|
284
|
-
binding.assignment,
|
|
285
|
-
"initialModelBinding.assignment",
|
|
286
|
-
);
|
|
287
|
-
exact(assignment, [
|
|
288
|
-
"assignmentId",
|
|
289
|
-
"packageId",
|
|
290
|
-
"capabilityId",
|
|
291
|
-
"connectionId",
|
|
292
|
-
"state",
|
|
293
|
-
]);
|
|
294
|
-
if (assignment.state !== "enabled") {
|
|
295
|
-
throw new FlockDecodeError("initial model assignment is invalid");
|
|
296
|
-
}
|
|
297
|
-
return {
|
|
298
|
-
assignment: {
|
|
299
|
-
assignmentId: identifier(
|
|
300
|
-
assignment.assignmentId,
|
|
301
|
-
"initialModelBinding.assignment.assignmentId",
|
|
302
|
-
),
|
|
303
|
-
packageId: identifier(
|
|
304
|
-
assignment.packageId,
|
|
305
|
-
"initialModelBinding.assignment.packageId",
|
|
306
|
-
),
|
|
307
|
-
capabilityId: identifier(
|
|
308
|
-
assignment.capabilityId,
|
|
309
|
-
"initialModelBinding.assignment.capabilityId",
|
|
310
|
-
),
|
|
311
|
-
connectionId: identifier(
|
|
312
|
-
assignment.connectionId,
|
|
313
|
-
"initialModelBinding.assignment.connectionId",
|
|
314
|
-
),
|
|
315
|
-
state: "enabled",
|
|
316
|
-
},
|
|
317
|
-
generation: identifier(
|
|
318
|
-
binding.generation,
|
|
319
|
-
"initialModelBinding.generation",
|
|
320
|
-
),
|
|
321
|
-
};
|
|
322
|
-
}
|
|
323
|
-
|
|
324
253
|
export function decodeSheepRecipeV1(input: unknown): SheepRecipeV1 {
|
|
325
254
|
const value = record(input, "sheep recipe");
|
|
326
255
|
exact(value, ["schemaVersion", "background", "upper", "middle", "lower"]);
|
|
@@ -405,51 +334,10 @@ export function decodeBotRegistrationV1(input: unknown): BotRegistrationV1 {
|
|
|
405
334
|
exact(
|
|
406
335
|
bot,
|
|
407
336
|
["schemaVersion", "botId", "registeredAt", "initialName", "sheep"],
|
|
408
|
-
[
|
|
409
|
-
"initialDescription",
|
|
410
|
-
"initialModel",
|
|
411
|
-
"initialModelBinding",
|
|
412
|
-
"initialAssignments",
|
|
413
|
-
"createdBy",
|
|
414
|
-
],
|
|
337
|
+
["initialDescription", "createdBy"],
|
|
415
338
|
);
|
|
416
339
|
if (bot.schemaVersion !== 1)
|
|
417
340
|
throw new FlockDecodeError("unsupported Bot registration");
|
|
418
|
-
const initialModel =
|
|
419
|
-
bot.initialModel === undefined
|
|
420
|
-
? undefined
|
|
421
|
-
: modelAssignment(bot.initialModel);
|
|
422
|
-
const binding =
|
|
423
|
-
bot.initialModelBinding === undefined
|
|
424
|
-
? undefined
|
|
425
|
-
: initialModelBinding(bot.initialModelBinding);
|
|
426
|
-
if (
|
|
427
|
-
bot.initialAssignments !== undefined &&
|
|
428
|
-
!Array.isArray(bot.initialAssignments)
|
|
429
|
-
)
|
|
430
|
-
throw new FlockDecodeError("initial Assignments are invalid");
|
|
431
|
-
const initialAssignments =
|
|
432
|
-
bot.initialAssignments === undefined
|
|
433
|
-
? undefined
|
|
434
|
-
: bot.initialAssignments.map(decodeCapabilityAssignmentV1);
|
|
435
|
-
if (
|
|
436
|
-
new Set(
|
|
437
|
-
(initialAssignments ?? []).map((assignment) => assignment.assignmentId),
|
|
438
|
-
).size !== (initialAssignments ?? []).length ||
|
|
439
|
-
(initialAssignments ?? []).some(
|
|
440
|
-
(assignment) =>
|
|
441
|
-
assignment.connectionId !== undefined || assignment.state !== "enabled",
|
|
442
|
-
)
|
|
443
|
-
) {
|
|
444
|
-
throw new FlockDecodeError("initial Assignments are invalid");
|
|
445
|
-
}
|
|
446
|
-
if (
|
|
447
|
-
binding &&
|
|
448
|
-
(!initialModel ||
|
|
449
|
-
binding.assignment.connectionId !== initialModel.connectionId)
|
|
450
|
-
) {
|
|
451
|
-
throw new FlockDecodeError("initial model binding is invalid");
|
|
452
|
-
}
|
|
453
341
|
const botId = botIdentifier(bot.botId);
|
|
454
342
|
const createdBy = botWriter(bot.createdBy, "createdBy");
|
|
455
343
|
if (createdBy && createdBy.botId === botId)
|
|
@@ -468,9 +356,6 @@ export function decodeBotRegistrationV1(input: unknown): BotRegistrationV1 {
|
|
|
468
356
|
10_000,
|
|
469
357
|
),
|
|
470
358
|
}),
|
|
471
|
-
initialModel,
|
|
472
|
-
initialModelBinding: binding,
|
|
473
|
-
...(initialAssignments ? { initialAssignments } : {}),
|
|
474
359
|
...(createdBy ? { createdBy } : {}),
|
|
475
360
|
sheep: decodeSheepRecipeV1(bot.sheep),
|
|
476
361
|
};
|
package/src/user.test.ts
CHANGED
|
@@ -41,22 +41,6 @@ class MemoryStorage {
|
|
|
41
41
|
return Promise.resolve();
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
|
-
const settings = {
|
|
45
|
-
schemaVersion: 1 as const,
|
|
46
|
-
revision: 4,
|
|
47
|
-
profile: { name: "User" },
|
|
48
|
-
packages: [
|
|
49
|
-
{ packageId: "web", version: "0.0.1", state: "installed" as const },
|
|
50
|
-
{
|
|
51
|
-
packageId: "provider-ollama-cloud",
|
|
52
|
-
version: "0.0.1",
|
|
53
|
-
state: "installed" as const,
|
|
54
|
-
},
|
|
55
|
-
],
|
|
56
|
-
connections: [],
|
|
57
|
-
newBotModelTemplate: { connectionId: "provider", providerModelId: "model" },
|
|
58
|
-
newBotModelTemplateSource: "auto" as const,
|
|
59
|
-
};
|
|
60
44
|
function command(commandId = "create-1", expectedRevision = 0) {
|
|
61
45
|
return {
|
|
62
46
|
schemaVersion: 1 as const,
|
|
@@ -70,46 +54,10 @@ function command(commandId = "create-1", expectedRevision = 0) {
|
|
|
70
54
|
}
|
|
71
55
|
|
|
72
56
|
describe("Flock User contribution", () => {
|
|
73
|
-
test("atomically admits
|
|
57
|
+
test("atomically admits a model-free Bot and replays duplicate delivery", async () => {
|
|
74
58
|
const storage = new MemoryStorage();
|
|
75
59
|
const contribution = createFlockUserBackendContribution({
|
|
76
60
|
storage,
|
|
77
|
-
availablePackages: [
|
|
78
|
-
{
|
|
79
|
-
packageId: "web",
|
|
80
|
-
version: "0.0.1",
|
|
81
|
-
capabilities: [
|
|
82
|
-
{ id: "web-fetch", kind: "tool", connectionTypes: [] },
|
|
83
|
-
],
|
|
84
|
-
connectionTypes: [],
|
|
85
|
-
},
|
|
86
|
-
{
|
|
87
|
-
packageId: "provider-ollama-cloud",
|
|
88
|
-
version: "0.0.1",
|
|
89
|
-
capabilities: [
|
|
90
|
-
{
|
|
91
|
-
id: "ollama-cloud-models",
|
|
92
|
-
kind: "model",
|
|
93
|
-
connectionTypes: ["ollama-cloud-account"],
|
|
94
|
-
},
|
|
95
|
-
],
|
|
96
|
-
connectionTypes: [
|
|
97
|
-
{
|
|
98
|
-
id: "ollama-cloud-account",
|
|
99
|
-
capabilities: ["ollama-cloud-models"],
|
|
100
|
-
},
|
|
101
|
-
],
|
|
102
|
-
},
|
|
103
|
-
],
|
|
104
|
-
readUserSettings: () => Promise.resolve(settings),
|
|
105
|
-
claimInitialModelBinding: (_storage, input) =>
|
|
106
|
-
Promise.resolve({
|
|
107
|
-
assignmentId: input.generation,
|
|
108
|
-
packageId: "provider-ollama-cloud",
|
|
109
|
-
capabilityId: "ollama-cloud-models",
|
|
110
|
-
connectionId: input.model.connectionId,
|
|
111
|
-
state: "enabled",
|
|
112
|
-
}),
|
|
113
61
|
now: () => new Date("2026-08-29T00:00:00.000Z"),
|
|
114
62
|
commandBotLifecycle: () => Promise.reject(new Error("not used")),
|
|
115
63
|
readBotLifecycle: () => Promise.reject(new Error("not used")),
|
|
@@ -122,20 +70,9 @@ describe("Flock User contribution", () => {
|
|
|
122
70
|
initialName: "Alpha",
|
|
123
71
|
registeredAt: "2026-08-29T00:00:00.000Z",
|
|
124
72
|
});
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
expect(
|
|
128
|
-
initialModel: undefined,
|
|
129
|
-
initialModelBinding: undefined,
|
|
130
|
-
initialAssignments: [
|
|
131
|
-
{
|
|
132
|
-
assignmentId: "default-0-0",
|
|
133
|
-
packageId: "web",
|
|
134
|
-
capabilityId: "web-fetch",
|
|
135
|
-
state: "enabled",
|
|
136
|
-
},
|
|
137
|
-
],
|
|
138
|
-
});
|
|
73
|
+
const registration = await contribution.registration("alpha");
|
|
74
|
+
expect(Object.hasOwn(registration, "initialModel")).toBe(false);
|
|
75
|
+
expect(Object.hasOwn(registration, "initialCapabilities")).toBe(false);
|
|
139
76
|
await expect(
|
|
140
77
|
contribution.createBot("user-1", { ...command(), name: "Different" }),
|
|
141
78
|
).rejects.toThrow("command ID collision");
|
|
@@ -147,16 +84,10 @@ describe("Flock User contribution", () => {
|
|
|
147
84
|
).rejects.toBeInstanceOf(FlockConflictError);
|
|
148
85
|
});
|
|
149
86
|
|
|
150
|
-
test("admits a Bot
|
|
87
|
+
test("admits a Bot without consulting User model state", async () => {
|
|
151
88
|
const storage = new MemoryStorage();
|
|
152
|
-
let claims = 0;
|
|
153
89
|
const contribution = createFlockUserBackendContribution({
|
|
154
90
|
storage,
|
|
155
|
-
readUserSettings: () => Promise.resolve(settings),
|
|
156
|
-
claimInitialModelBinding: () => {
|
|
157
|
-
claims += 1;
|
|
158
|
-
return Promise.resolve(undefined);
|
|
159
|
-
},
|
|
160
91
|
commandBotLifecycle: () => Promise.reject(new Error("not used")),
|
|
161
92
|
readBotLifecycle: () => Promise.reject(new Error("not used")),
|
|
162
93
|
});
|
|
@@ -164,9 +95,8 @@ describe("Flock User contribution", () => {
|
|
|
164
95
|
await expect(
|
|
165
96
|
contribution.createBot("user-1", command()),
|
|
166
97
|
).resolves.toMatchObject({ status: "applied" });
|
|
167
|
-
expect(claims).toBe(0);
|
|
168
98
|
expect((await contribution.listBots()).bots).toMatchObject([
|
|
169
|
-
{ botId: "alpha"
|
|
99
|
+
{ botId: "alpha" },
|
|
170
100
|
]);
|
|
171
101
|
});
|
|
172
102
|
|
|
@@ -174,10 +104,8 @@ describe("Flock User contribution", () => {
|
|
|
174
104
|
const storage = new MemoryStorage();
|
|
175
105
|
const contribution = createFlockUserBackendContribution({
|
|
176
106
|
storage,
|
|
177
|
-
readUserSettings: () => Promise.resolve(settings),
|
|
178
107
|
commandBotLifecycle: () => Promise.reject(new Error("not used")),
|
|
179
108
|
readBotLifecycle: () => Promise.reject(new Error("not used")),
|
|
180
|
-
claimInitialModelBinding: () => Promise.resolve(undefined),
|
|
181
109
|
});
|
|
182
110
|
await storage.put("flock:directory:v1", {
|
|
183
111
|
schemaVersion: 1,
|
|
@@ -204,15 +132,6 @@ describe("Flock User contribution", () => {
|
|
|
204
132
|
let calls = 0;
|
|
205
133
|
const contribution = createFlockUserBackendContribution({
|
|
206
134
|
storage,
|
|
207
|
-
readUserSettings: () => Promise.resolve(settings),
|
|
208
|
-
claimInitialModelBinding: (_storage, input) =>
|
|
209
|
-
Promise.resolve({
|
|
210
|
-
assignmentId: input.generation,
|
|
211
|
-
packageId: "provider-ollama-cloud",
|
|
212
|
-
capabilityId: "ollama-cloud-models",
|
|
213
|
-
connectionId: input.model.connectionId,
|
|
214
|
-
state: "enabled" as const,
|
|
215
|
-
}),
|
|
216
135
|
commandBotLifecycle: (_userId, lifecycleCommand) => {
|
|
217
136
|
calls += 1;
|
|
218
137
|
botStatus =
|
|
@@ -273,15 +192,6 @@ describe("Flock User contribution", () => {
|
|
|
273
192
|
let recovered = false;
|
|
274
193
|
const contribution = createFlockUserBackendContribution({
|
|
275
194
|
storage,
|
|
276
|
-
readUserSettings: () => Promise.resolve(settings),
|
|
277
|
-
claimInitialModelBinding: (_storage, input) =>
|
|
278
|
-
Promise.resolve({
|
|
279
|
-
assignmentId: input.generation,
|
|
280
|
-
packageId: "provider-ollama-cloud",
|
|
281
|
-
capabilityId: "ollama-cloud-models",
|
|
282
|
-
connectionId: input.model.connectionId,
|
|
283
|
-
state: "enabled" as const,
|
|
284
|
-
}),
|
|
285
195
|
commandBotLifecycle: () => Promise.reject(new Error("response lost")),
|
|
286
196
|
readBotLifecycle: (_userId, botId) =>
|
|
287
197
|
recovered
|
|
@@ -315,15 +225,6 @@ describe("Flock User contribution", () => {
|
|
|
315
225
|
recovered = true;
|
|
316
226
|
const reconstructed = createFlockUserBackendContribution({
|
|
317
227
|
storage,
|
|
318
|
-
readUserSettings: () => Promise.resolve(settings),
|
|
319
|
-
claimInitialModelBinding: (_storage, input) =>
|
|
320
|
-
Promise.resolve({
|
|
321
|
-
assignmentId: input.generation,
|
|
322
|
-
packageId: "provider-ollama-cloud",
|
|
323
|
-
capabilityId: "ollama-cloud-models",
|
|
324
|
-
connectionId: input.model.connectionId,
|
|
325
|
-
state: "enabled" as const,
|
|
326
|
-
}),
|
|
327
228
|
commandBotLifecycle: () => Promise.reject(new Error("response lost")),
|
|
328
229
|
readBotLifecycle: (_userId, botId) =>
|
|
329
230
|
Promise.resolve({
|
|
@@ -356,15 +257,6 @@ describe("Flock User contribution", () => {
|
|
|
356
257
|
const create = () =>
|
|
357
258
|
createFlockUserBackendContribution({
|
|
358
259
|
storage,
|
|
359
|
-
readUserSettings: () => Promise.resolve(settings),
|
|
360
|
-
claimInitialModelBinding: (_storage, input) =>
|
|
361
|
-
Promise.resolve({
|
|
362
|
-
assignmentId: input.generation,
|
|
363
|
-
packageId: "provider-ollama-cloud",
|
|
364
|
-
capabilityId: "ollama-cloud-models",
|
|
365
|
-
connectionId: input.model.connectionId,
|
|
366
|
-
state: "enabled" as const,
|
|
367
|
-
}),
|
|
368
260
|
commandBotLifecycle: () =>
|
|
369
261
|
Promise.resolve({
|
|
370
262
|
schemaVersion: 1,
|
|
@@ -411,17 +303,8 @@ describe("Flock User contribution", () => {
|
|
|
411
303
|
const storage = new MemoryStorage();
|
|
412
304
|
const contribution = createFlockUserBackendContribution({
|
|
413
305
|
storage,
|
|
414
|
-
readUserSettings: () => Promise.resolve(settings),
|
|
415
306
|
commandBotLifecycle: () => Promise.reject(new Error("not used")),
|
|
416
307
|
readBotLifecycle: () => Promise.reject(new Error("not used")),
|
|
417
|
-
claimInitialModelBinding: (_storage, input) =>
|
|
418
|
-
Promise.resolve({
|
|
419
|
-
assignmentId: input.generation,
|
|
420
|
-
packageId: "provider-ollama-cloud",
|
|
421
|
-
capabilityId: "ollama-cloud-models",
|
|
422
|
-
connectionId: input.model.connectionId,
|
|
423
|
-
state: "enabled",
|
|
424
|
-
}),
|
|
425
308
|
});
|
|
426
309
|
await contribution.createBot("user-1", command());
|
|
427
310
|
expect(
|
package/src/user.ts
CHANGED
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
CapabilityAssignmentView,
|
|
3
|
-
ExecutionPackageDefinition,
|
|
4
|
-
ModelAssignment,
|
|
5
|
-
UserSettingsViewV1,
|
|
6
|
-
} from "@frockbot/configuration-core";
|
|
7
1
|
import type { Plugin } from "cordis";
|
|
8
2
|
import {
|
|
9
3
|
BotNotFoundError,
|
|
@@ -51,28 +45,6 @@ interface Storage extends FlockUserTransaction {
|
|
|
51
45
|
}
|
|
52
46
|
export interface FlockUserBackendHost {
|
|
53
47
|
storage: Storage;
|
|
54
|
-
/**
|
|
55
|
-
* Retained for hosts that materialize a Bot from User state. A new Bot no
|
|
56
|
-
* longer copies the User default model, so neither seam is called here.
|
|
57
|
-
*/
|
|
58
|
-
readUserSettings(
|
|
59
|
-
storage: FlockUserTransaction,
|
|
60
|
-
userId: string,
|
|
61
|
-
): Promise<UserSettingsViewV1>;
|
|
62
|
-
/**
|
|
63
|
-
* Immutable Package definitions from the application manifest. Omitted only
|
|
64
|
-
* by narrow test adapters that intentionally expose no Package authority.
|
|
65
|
-
*/
|
|
66
|
-
availablePackages?: readonly ExecutionPackageDefinition[];
|
|
67
|
-
claimInitialModelBinding?(
|
|
68
|
-
storage: FlockUserTransaction,
|
|
69
|
-
input: {
|
|
70
|
-
userId: string;
|
|
71
|
-
botId: string;
|
|
72
|
-
generation: string;
|
|
73
|
-
model: ModelAssignment;
|
|
74
|
-
},
|
|
75
|
-
): Promise<CapabilityAssignmentView | undefined>;
|
|
76
48
|
now?: () => Date;
|
|
77
49
|
random?: () => number;
|
|
78
50
|
commandBotLifecycle(
|
|
@@ -187,34 +159,9 @@ export class FlockUserBackendContribution {
|
|
|
187
159
|
failure: "Bot directory limit reached",
|
|
188
160
|
};
|
|
189
161
|
} else {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
pkg.state === "installed" ? [[pkg.packageId, pkg.version]] : [],
|
|
194
|
-
),
|
|
195
|
-
);
|
|
196
|
-
const initialAssignments = (this.host.availablePackages ?? []).flatMap(
|
|
197
|
-
(pkg, packageIndex) =>
|
|
198
|
-
installedVersions.get(pkg.packageId) === pkg.version
|
|
199
|
-
? pkg.capabilities.flatMap((capability, capabilityIndex) =>
|
|
200
|
-
capability.connectionTypes.length === 0 &&
|
|
201
|
-
capability.kind !== "model"
|
|
202
|
-
? [
|
|
203
|
-
{
|
|
204
|
-
assignmentId: `default-${packageIndex}-${capabilityIndex}`,
|
|
205
|
-
packageId: pkg.packageId,
|
|
206
|
-
capabilityId: capability.id,
|
|
207
|
-
state: "enabled" as const,
|
|
208
|
-
},
|
|
209
|
-
]
|
|
210
|
-
: [],
|
|
211
|
-
)
|
|
212
|
-
: [],
|
|
213
|
-
);
|
|
214
|
-
// A new Bot carries no model of its own: it follows the User's
|
|
215
|
-
// default model dynamically, and claims the Connection's model
|
|
216
|
-
// Capability the first time it resolves its execution context. Only a
|
|
217
|
-
// Bot that overrides the default owns a durable `model`.
|
|
162
|
+
// A new Bot carries neither a model nor a grant. Both resolve from the
|
|
163
|
+
// User's enabled Packages and Connections at its next admitted Turn
|
|
164
|
+
// (AGENTS.md Configuration shape; ADR 0019).
|
|
218
165
|
const registration: BotRegistrationV1 = {
|
|
219
166
|
schemaVersion: 1,
|
|
220
167
|
botId: command.botId,
|
|
@@ -223,9 +170,6 @@ export class FlockUserBackendContribution {
|
|
|
223
170
|
...(command.description === undefined
|
|
224
171
|
? {}
|
|
225
172
|
: { initialDescription: command.description }),
|
|
226
|
-
initialModel: undefined,
|
|
227
|
-
initialModelBinding: undefined,
|
|
228
|
-
initialAssignments,
|
|
229
173
|
// The creator is durable history: a Bot the Flock made on another
|
|
230
174
|
// Bot's behalf says so in the registration seed itself.
|
|
231
175
|
...(command.createdBy
|