@frockbot/plugin-shell 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.
@@ -173,7 +173,7 @@ describe("application manifest protocol", () => {
173
173
  ],
174
174
  }),
175
175
  ).toEqual([]);
176
- // A tool Package a User installs and assigns with no credential at all:
176
+ // A tool Package a User enables with no credential at all:
177
177
  // one Capability, no Connection Type. It stays in the catalog, because
178
178
  // needing no Connection is not the same as offering nothing.
179
179
  expect(
@@ -202,6 +202,55 @@ describe("application manifest protocol", () => {
202
202
  connectionTypes: [],
203
203
  }),
204
204
  ]);
205
+ // A settings-only Package still has User-visible enablement: turning it on
206
+ // is what makes its otherwise-inert controls available.
207
+ expect(
208
+ decodePluginCatalog({
209
+ ...emptyManifest,
210
+ packages: [
211
+ {
212
+ id: "custom-models",
213
+ displayName: "Custom models",
214
+ version: "0.0.1",
215
+ contributions: ["client"],
216
+ configuration: {
217
+ settings: [
218
+ {
219
+ id: "account-model",
220
+ schemaVersion: 1,
221
+ scopes: ["user"],
222
+ role: "model",
223
+ schema: {
224
+ type: "object",
225
+ properties: {
226
+ connectionId: { type: "string" },
227
+ providerModelId: { type: "string" },
228
+ },
229
+ required: ["connectionId", "providerModelId"],
230
+ additionalProperties: false,
231
+ },
232
+ },
233
+ ],
234
+ connectionTypes: [],
235
+ capabilities: [],
236
+ },
237
+ },
238
+ ],
239
+ }),
240
+ ).toEqual([
241
+ expect.objectContaining({
242
+ packageId: "custom-models",
243
+ capabilities: [],
244
+ connectionTypes: [],
245
+ settings: [
246
+ expect.objectContaining({
247
+ id: "account-model",
248
+ scopes: ["user"],
249
+ role: "model",
250
+ }),
251
+ ],
252
+ }),
253
+ ]);
205
254
  // The same Package with a turn-type admission ceiling: manifest v4 is what
206
255
  // the catalog wraps the served configuration as, so the field decodes.
207
256
  expect(
@@ -289,121 +338,6 @@ describe("composer hydration context", () => {
289
338
  });
290
339
  });
291
340
 
292
- describe("hosted Assignment commands", () => {
293
- test("uses distinct atomic Assign, Replace, and Unassign commands", async () => {
294
- let provided: Ref<FrockBotWebData> | undefined;
295
- const commands: unknown[] = [];
296
- await shellClientPlugin({
297
- transport: {
298
- turn: () => Promise.resolve({ runId: "run", text: "", events: [] }),
299
- readConfiguration: () =>
300
- Promise.resolve(initializeBotSettingsV1("primary")),
301
- executeConfiguration: (command) => {
302
- commands.push(command);
303
- return Promise.resolve({
304
- schemaVersion: 1,
305
- commandId: command.commandId,
306
- revision: command.expectedRevision + 1,
307
- status: "applied",
308
- });
309
- },
310
- },
311
- slot: () => () => {},
312
- inject: () => {
313
- throw new Error("unexpected client provider injection");
314
- },
315
- provide: (_key, value) => {
316
- provided = value as Ref<FrockBotWebData>;
317
- return () => {};
318
- },
319
- });
320
- if (!provided) throw new Error("shell data was not provided");
321
- provided.value.activeBotId = "primary";
322
- provided.value.botSettings = initializeBotSettingsV1("primary");
323
- const assignment = {
324
- assignmentId: "mail",
325
- packageId: "mail",
326
- capabilityId: "send",
327
- connectionId: "mail-1",
328
- };
329
- await provided.value.assignCapability(assignment);
330
- provided.value.botSettings = {
331
- ...initializeBotSettingsV1("primary"),
332
- revision: 1,
333
- };
334
- await provided.value.replaceCapability(assignment);
335
- provided.value.botSettings = {
336
- ...initializeBotSettingsV1("primary"),
337
- revision: 2,
338
- };
339
- await provided.value.unassignCapability("mail");
340
- expect(commands).toMatchObject([
341
- { type: "bot/assign-capability", expectedRevision: 0, assignment },
342
- { type: "bot/replace-capability", expectedRevision: 1, assignment },
343
- {
344
- type: "bot/unassign-capability",
345
- expectedRevision: 2,
346
- assignmentId: "mail",
347
- },
348
- ]);
349
- });
350
-
351
- test("surfaces rejected and retrying Assignment receipts", async () => {
352
- let provided: Ref<FrockBotWebData> | undefined;
353
- const receipts = [
354
- {
355
- schemaVersion: 1 as const,
356
- commandId: "rejected",
357
- revision: 0,
358
- status: "rejected" as const,
359
- failure: "Connection is unavailable",
360
- },
361
- {
362
- schemaVersion: 1 as const,
363
- commandId: "pending",
364
- revision: 0,
365
- status: "pending" as const,
366
- },
367
- ];
368
- await shellClientPlugin({
369
- transport: {
370
- turn: () => Promise.resolve({ runId: "run", text: "", events: [] }),
371
- readConfiguration: () =>
372
- Promise.resolve(initializeBotSettingsV1("primary")),
373
- executeConfiguration: () => Promise.resolve(receipts.shift()!),
374
- },
375
- slot: () => () => {},
376
- inject: () => {
377
- throw new Error("unexpected client provider injection");
378
- },
379
- provide: (_key, value) => {
380
- provided = value as Ref<FrockBotWebData>;
381
- return () => {};
382
- },
383
- });
384
- if (!provided) throw new Error("shell data was not provided");
385
- provided.value.activeBotId = "primary";
386
- provided.value.botSettings = initializeBotSettingsV1("primary");
387
- const assignment = {
388
- assignmentId: "mail",
389
- packageId: "mail",
390
- capabilityId: "send",
391
- connectionId: "mail-1",
392
- };
393
-
394
- await expect(provided.value.assignCapability(assignment)).rejects.toThrow(
395
- "Connection is unavailable",
396
- );
397
- expect(provided.value.settingsError).toBe("Connection is unavailable");
398
- await expect(provided.value.assignCapability(assignment)).resolves.toBe(
399
- undefined,
400
- );
401
- expect(provided.value.settingsError).toBe(
402
- "Assignment operation is retrying.",
403
- );
404
- });
405
- });
406
-
407
341
  describe("Bot selection", () => {
408
342
  test("passes explicit Bot IDs and ignores stale hydration", async () => {
409
343
  Object.defineProperty(globalThis, "window", {
@@ -576,197 +510,218 @@ describe("Bot selection", () => {
576
510
  expect(provided.value.userSettings?.profile.name).toBe("Newer");
577
511
  });
578
512
 
579
- test("labels an explicitly bound Ollama Bot by its provider", async () => {
580
- let provided: Ref<FrockBotWebData> | undefined;
581
- const bot = {
582
- ...initializeBotSettingsV1("ollama-bot"),
583
- model: {
584
- connectionId: "ollama-work",
585
- providerModelId: "glm-5.3-flash:cloud",
586
- },
587
- assignments: [
588
- {
589
- assignmentId: "ollama-model",
590
- packageId: "provider-ollama-cloud",
591
- capabilityId: "ollama-cloud-models",
592
- connectionId: "ollama-work",
593
- state: "enabled" as const,
594
- },
595
- ],
596
- };
597
- const user: UserSettingsViewV1 = {
598
- schemaVersion: 1,
599
- revision: 1,
600
- profile: { name: "User" },
601
- packages: [
602
- {
603
- packageId: "provider-ollama-cloud",
604
- version: "0.0.1",
605
- state: "installed",
606
- },
607
- ],
608
- connections: [
609
- {
610
- connectionId: "ollama-work",
611
- packageId: "provider-ollama-cloud",
612
- connectionTypeId: "ollama-cloud-account",
613
- displayName: "Work",
614
- state: "ready",
615
- providerType: "ollama-cloud",
616
- safeMetadata: {},
513
+ test.each([
514
+ {
515
+ source: "bot" as const,
516
+ botValues: {
517
+ "custom-models": {
518
+ model: {
519
+ connectionId: "model-connection",
520
+ providerModelId: "model-id",
521
+ },
617
522
  },
618
- ],
619
- };
620
- await shellClientPlugin({
621
- transport: {
622
- turn: () => Promise.resolve({ runId: "run", text: "", events: [] }),
623
- readConfiguration: (query) =>
624
- Promise.resolve(query.type === "user/get" ? user : bot),
625
- },
626
- slot: () => () => {},
627
- inject: () => {
628
- throw new Error("unexpected client provider injection");
629
523
  },
630
- provide: (_key, value) => {
631
- provided = value as Ref<FrockBotWebData>;
632
- return () => {};
524
+ accountValues: undefined,
525
+ platformModel: undefined,
526
+ expectedLabel: "Model name · Model provider · Bot override",
527
+ expectedProjection: "bot",
528
+ ready: true,
529
+ },
530
+ {
531
+ source: "account" as const,
532
+ botValues: {},
533
+ accountValues: {
534
+ model: {
535
+ connectionId: "model-connection",
536
+ providerModelId: "model-id",
537
+ },
633
538
  },
634
- });
635
- if (!provided) throw new Error("shell data was not provided");
636
- provided.value.activeBotId = bot.botId;
637
- provided.value.pluginCatalog = [
638
- {
639
- packageId: "provider-ollama-cloud",
640
- displayName: "Ollama Cloud",
641
- version: "0.0.1",
642
- capabilities: [
539
+ platformModel: undefined,
540
+ expectedLabel: "Model name · Model provider · Account model",
541
+ expectedProjection: "default",
542
+ ready: true,
543
+ },
544
+ {
545
+ source: "platform" as const,
546
+ botValues: {},
547
+ accountValues: undefined,
548
+ platformModel: {
549
+ connectionId: "model-connection",
550
+ providerModelId: "model-id",
551
+ },
552
+ expectedLabel: "Model name · Model provider",
553
+ expectedProjection: "default",
554
+ ready: true,
555
+ },
556
+ {
557
+ source: "none" as const,
558
+ botValues: {},
559
+ accountValues: undefined,
560
+ platformModel: undefined,
561
+ expectedLabel: "Model unavailable",
562
+ expectedProjection: "none",
563
+ ready: false,
564
+ },
565
+ ])(
566
+ "labels the $source effective model",
567
+ async ({
568
+ botValues,
569
+ accountValues,
570
+ platformModel,
571
+ expectedLabel,
572
+ expectedProjection,
573
+ ready,
574
+ }) => {
575
+ let provided: Ref<FrockBotWebData> | undefined;
576
+ const bot = {
577
+ ...initializeBotSettingsV1("model-bot"),
578
+ packageValues: structuredClone(botValues) as Record<
579
+ string,
580
+ Record<string, unknown>
581
+ >,
582
+ };
583
+ const user: UserSettingsViewV1 = {
584
+ schemaVersion: 1,
585
+ revision: 1,
586
+ profile: { name: "User" },
587
+ packages: [
643
588
  {
644
- id: "ollama-cloud-models",
645
- kind: "model",
646
- connectionTypes: ["ollama-cloud-account"],
589
+ packageId: "custom-models",
590
+ version: "0.0.1",
591
+ state: "installed",
592
+ ...(accountValues ? { values: accountValues } : {}),
647
593
  },
648
594
  {
649
- id: "ollama-cloud-tools",
650
- kind: "tool",
651
- connectionTypes: ["ollama-cloud-account"],
595
+ packageId: "model-provider",
596
+ version: "0.0.1",
597
+ state: "installed",
652
598
  },
653
599
  ],
654
- connectionTypes: [
600
+ connections: [
655
601
  {
656
- id: "ollama-cloud-account",
657
- displayName: "Ollama Cloud account",
658
- allowMultiple: true,
659
- authorizationKind: "api-key",
660
- capabilities: ["ollama-cloud-models", "ollama-cloud-tools"],
602
+ connectionId: "model-connection",
603
+ packageId: "model-provider",
604
+ connectionTypeId: "model-account",
605
+ displayName: "Work",
606
+ state: "ready",
607
+ providerType: "model-provider",
608
+ safeMetadata: {},
609
+ modelCatalog: {
610
+ schemaVersion: 1,
611
+ generation: "catalog-1",
612
+ state: "fresh",
613
+ models: [
614
+ {
615
+ providerModelId: "model-id",
616
+ displayName: "Model name",
617
+ capabilities: {
618
+ tools: true,
619
+ vision: false,
620
+ reasoning: false,
621
+ },
622
+ source: "discovered",
623
+ },
624
+ ],
625
+ },
661
626
  },
662
627
  ],
663
- },
664
- ];
665
-
666
- await provided.value.loadBotSettings();
667
- await provided.value.loadUserSettings();
668
-
669
- expect(provided.value.modelLabel).toBe(
670
- "glm-5.3-flash:cloud · Ollama Cloud",
671
- );
672
- expect(provided.value.modelReady).toBe(true);
673
- expect(provided.value.modelSource).toBe("bot");
674
-
675
- bot.assignments[0] = {
676
- ...bot.assignments[0]!,
677
- capabilityId: "ollama-cloud-tools",
678
- };
679
- await provided.value.loadBotSettings();
680
- expect(provided.value.modelReady).toBe(false);
681
-
682
- // A Bot without a model of its own follows the User's default, and the
683
- // label never says so: the Bot simply runs on that model.
684
- bot.model = undefined as unknown as typeof bot.model;
685
- user.newBotModelTemplate = {
686
- connectionId: "ollama-work",
687
- providerModelId: "llama-3:cloud",
688
- };
689
- user.newBotModelTemplateSource = "auto";
690
- await provided.value.loadUserSettings();
691
- await provided.value.loadBotSettings();
692
- expect(provided.value.modelSource).toBe("default");
693
- expect(provided.value.modelLabel).toBe("llama-3:cloud · Ollama Cloud");
694
- expect(provided.value.modelReady).toBe(true);
695
-
696
- user.newBotModelTemplate = undefined;
697
- user.newBotModelTemplateSource = undefined;
698
- await provided.value.loadUserSettings();
699
- expect(provided.value.modelSource).toBe("none");
700
- expect(provided.value.modelLabel).toBe("No default model");
701
- expect(provided.value.modelReady).toBe(false);
702
- });
703
-
704
- test("assigns a newly connected model capability before model selection", async () => {
705
- let provided: Ref<FrockBotWebData> | undefined;
706
- let bot = initializeBotSettingsV1("ollama-bot");
707
- const commands: Array<{ type: string; expectedRevision: number }> = [];
708
- const user: UserSettingsViewV1 = {
709
- schemaVersion: 1,
710
- revision: 1,
711
- profile: { name: "User" },
712
- packages: [
628
+ ...(platformModel ? { platformModel } : {}),
629
+ };
630
+ await shellClientPlugin({
631
+ transport: {
632
+ turn: () => Promise.resolve({ runId: "run", text: "", events: [] }),
633
+ readConfiguration: (query) =>
634
+ Promise.resolve(query.type === "user/get" ? user : bot),
635
+ },
636
+ slot: () => () => {},
637
+ inject: () => {
638
+ throw new Error("unexpected client provider injection");
639
+ },
640
+ provide: (_key, value) => {
641
+ provided = value as Ref<FrockBotWebData>;
642
+ return () => {};
643
+ },
644
+ });
645
+ if (!provided) throw new Error("shell data was not provided");
646
+ provided.value.activeBotId = bot.botId;
647
+ provided.value.pluginCatalog = [
713
648
  {
714
- packageId: "provider-ollama-cloud",
649
+ packageId: "custom-models",
650
+ displayName: "Custom models",
715
651
  version: "0.0.1",
716
- state: "installed",
652
+ capabilities: [],
653
+ connectionTypes: [],
654
+ settings: [
655
+ {
656
+ id: "model",
657
+ schemaVersion: 1,
658
+ scopes: ["user", "bot"],
659
+ role: "model",
660
+ schema: {
661
+ type: "object",
662
+ properties: {
663
+ connectionId: { type: "string" },
664
+ providerModelId: { type: "string" },
665
+ },
666
+ required: ["connectionId", "providerModelId"],
667
+ additionalProperties: false,
668
+ },
669
+ },
670
+ ],
717
671
  },
718
- ],
719
- connections: [
720
672
  {
721
- connectionId: "ollama-work",
722
- packageId: "provider-ollama-cloud",
723
- connectionTypeId: "ollama-cloud-account",
724
- displayName: "Work",
725
- state: "ready",
726
- providerType: "ollama-cloud",
727
- safeMetadata: {},
673
+ packageId: "model-provider",
674
+ displayName: "Model provider",
675
+ version: "0.0.1",
676
+ capabilities: [
677
+ {
678
+ id: "models",
679
+ kind: "model",
680
+ connectionTypes: ["model-account"],
681
+ },
682
+ ],
683
+ connectionTypes: [
684
+ {
685
+ id: "model-account",
686
+ displayName: "Model account",
687
+ allowMultiple: false,
688
+ authorizationKind: "api-key",
689
+ capabilities: ["models"],
690
+ },
691
+ ],
692
+ settings: [],
728
693
  },
729
- ],
694
+ ];
695
+
696
+ await provided.value.loadBotSettings();
697
+
698
+ expect(provided.value.modelLabel).toBe(expectedLabel);
699
+ expect(provided.value.modelReady).toBe(ready);
700
+ expect(provided.value.modelSource).toBe(expectedProjection);
701
+ },
702
+ );
703
+
704
+ test("saves Bot-scoped Package settings through the generic command", async () => {
705
+ type PackageSettingsWebData = FrockBotWebData & {
706
+ saveBotPackageSettings(
707
+ packageId: string,
708
+ values: Record<string, unknown>,
709
+ ): Promise<void>;
730
710
  };
711
+ let provided: Ref<PackageSettingsWebData> | undefined;
712
+ const commands: unknown[] = [];
713
+ const bot = initializeBotSettingsV1("package-bot");
731
714
  await shellClientPlugin({
732
715
  transport: {
733
716
  turn: () => Promise.resolve({ runId: "run", text: "", events: [] }),
734
- readConfiguration: (query) =>
735
- Promise.resolve(query.type === "user/get" ? user : bot),
717
+ readConfiguration: () => Promise.resolve(bot),
736
718
  executeConfiguration: (command) => {
737
- if (!("botId" in command)) throw new Error("unexpected User command");
738
- commands.push({
739
- type: command.type,
740
- expectedRevision: command.expectedRevision,
741
- });
742
- if (command.type === "bot/assign-capability") {
743
- bot = {
744
- ...bot,
745
- revision: 1,
746
- model: command.model,
747
- assignments: [{ ...command.assignment, state: "enabled" }],
748
- };
749
- } else if (command.type === "bot/select-model") {
750
- bot = { ...bot, revision: bot.revision + 1, model: command.model };
751
- } else if (command.type === "bot/unbind-model") {
752
- bot = {
753
- ...bot,
754
- revision: bot.revision + 1,
755
- model: undefined,
756
- assignments: bot.assignments.map((assignment) =>
757
- assignment.assignmentId === command.assignmentId
758
- ? { ...assignment, state: "unavailable" }
759
- : assignment,
760
- ),
761
- };
762
- } else {
763
- throw new Error("unexpected Bot command");
764
- }
719
+ commands.push(command);
765
720
  return Promise.resolve({
766
721
  schemaVersion: 1,
767
722
  commandId: command.commandId,
768
- revision: bot.revision,
769
- status: "applied" as const,
723
+ revision: command.expectedRevision + 1,
724
+ status: "applied",
770
725
  });
771
726
  },
772
727
  },
@@ -775,102 +730,52 @@ describe("Bot selection", () => {
775
730
  throw new Error("unexpected client provider injection");
776
731
  },
777
732
  provide: (_key, value) => {
778
- provided = value as Ref<FrockBotWebData>;
733
+ provided = value as Ref<PackageSettingsWebData>;
779
734
  return () => {};
780
735
  },
781
736
  });
782
737
  if (!provided) throw new Error("shell data was not provided");
783
738
  provided.value.activeBotId = bot.botId;
784
739
  provided.value.botSettings = bot;
785
- provided.value.userSettings = user;
786
- provided.value.pluginCatalog = [
787
- {
788
- packageId: "provider-ollama-cloud",
789
- displayName: "Ollama Cloud",
790
- version: "0.0.1",
791
- capabilities: [
792
- {
793
- id: "ollama-cloud-models",
794
- kind: "model",
795
- connectionTypes: ["ollama-cloud-account"],
796
- },
797
- ],
798
- connectionTypes: [
799
- {
800
- id: "ollama-cloud-account",
801
- displayName: "Ollama Cloud account",
802
- allowMultiple: true,
803
- authorizationKind: "api-key",
804
- capabilities: ["ollama-cloud-models"],
805
- },
806
- ],
807
- },
808
- ];
809
740
 
810
- await provided.value.saveBotModel({
811
- connectionId: "ollama-work",
812
- providerModelId: "glm-5.3-flash:cloud",
813
- });
814
-
815
- expect(commands).toEqual([
816
- { type: "bot/assign-capability", expectedRevision: 0 },
817
- ]);
818
- expect(bot).toMatchObject({
819
- revision: 1,
741
+ await provided.value.saveBotPackageSettings("custom-models", {
820
742
  model: {
821
- connectionId: "ollama-work",
822
- providerModelId: "glm-5.3-flash:cloud",
743
+ connectionId: "model-connection",
744
+ providerModelId: "model-id",
823
745
  },
824
- assignments: [
825
- {
826
- packageId: "provider-ollama-cloud",
827
- capabilityId: "ollama-cloud-models",
828
- connectionId: "ollama-work",
829
- state: "enabled",
830
- },
831
- ],
832
746
  });
833
747
 
834
- bot = {
835
- ...bot,
836
- assignments: bot.assignments.map((assignment) => ({
837
- ...assignment,
838
- state: "unavailable",
839
- })),
840
- };
841
- provided.value.botSettings = bot;
842
-
843
- await provided.value.clearBotModel();
844
-
845
- expect(commands.at(-1)).toEqual({
846
- type: "bot/unbind-model",
847
- expectedRevision: 1,
848
- });
849
- expect(bot).toMatchObject({
850
- revision: 2,
851
- model: undefined,
852
- assignments: [{ state: "unavailable" }],
853
- });
748
+ expect(commands).toMatchObject([
749
+ {
750
+ type: "bot/set-package-settings",
751
+ botId: "package-bot",
752
+ packageId: "custom-models",
753
+ expectedRevision: 0,
754
+ values: {
755
+ model: {
756
+ connectionId: "model-connection",
757
+ providerModelId: "model-id",
758
+ },
759
+ },
760
+ },
761
+ ]);
854
762
  });
855
763
 
856
- test("does not resubmit an unchanged unavailable model", async () => {
764
+ test("shows the backend reason when Package enablement is refused", async () => {
857
765
  let provided: Ref<FrockBotWebData> | undefined;
858
- const bot = {
859
- ...initializeBotSettingsV1("ollama-bot"),
860
- model: {
861
- connectionId: "revoked-connection",
862
- providerModelId: "glm-5.3-flash:cloud",
863
- },
864
- assignments: [],
865
- };
866
- let executed = false;
766
+ const failure =
767
+ 'Enable dependency "custom-models" before enabling "provider-ollama-cloud"';
867
768
  await shellClientPlugin({
868
769
  transport: {
869
770
  turn: () => Promise.resolve({ runId: "run", text: "", events: [] }),
870
- executeConfiguration: () => {
871
- executed = true;
872
- throw new Error("model was resubmitted");
873
- },
771
+ executeConfiguration: (command) =>
772
+ Promise.resolve({
773
+ schemaVersion: 1,
774
+ commandId: command.commandId,
775
+ revision: command.expectedRevision,
776
+ status: "rejected",
777
+ failure,
778
+ }),
874
779
  },
875
780
  slot: () => () => {},
876
781
  inject: () => {
@@ -882,19 +787,24 @@ describe("Bot selection", () => {
882
787
  },
883
788
  });
884
789
  if (!provided) throw new Error("shell data was not provided");
885
- provided.value.activeBotId = bot.botId;
886
- provided.value.botSettings = bot;
887
790
  provided.value.userSettings = {
888
791
  schemaVersion: 1,
889
- revision: 1,
792
+ revision: 2,
890
793
  profile: { name: "User" },
891
- packages: [],
794
+ packages: [
795
+ {
796
+ packageId: "provider-ollama-cloud",
797
+ version: "0.0.1",
798
+ state: "disabled",
799
+ },
800
+ ],
892
801
  connections: [],
893
802
  };
894
803
 
895
- await provided.value.saveBotModel(bot.model);
896
-
897
- expect(executed).toBe(false);
804
+ await expect(
805
+ provided.value.setPackageEnabled("provider-ollama-cloud", true),
806
+ ).rejects.toThrow(failure);
807
+ expect(provided.value.settingsError).toBe(failure);
898
808
  });
899
809
  });
900
810
 
@@ -984,7 +894,7 @@ describe("detached Turn projection", () => {
984
894
  input: "Keep working",
985
895
  events: [],
986
896
  status: "completed",
987
- responseText: "Finished durably.",
897
+ responseText: "Finished successfully.",
988
898
  },
989
899
  ],
990
900
  );
@@ -992,7 +902,7 @@ describe("detached Turn projection", () => {
992
902
  expect(messages).toHaveLength(2);
993
903
  expect(messages[1]).toMatchObject({
994
904
  role: "assistant",
995
- text: "Finished durably.",
905
+ text: "Finished successfully.",
996
906
  status: "completed",
997
907
  });
998
908
  });
@@ -1423,8 +1333,18 @@ describe("active durable Turn projection", () => {
1423
1333
  await shellClientPlugin({
1424
1334
  transport: {
1425
1335
  turn: () => Promise.resolve({ runId: "run", text: "", events: [] }),
1426
- readConfiguration: () =>
1427
- Promise.resolve(initializeBotSettingsV1("default")),
1336
+ readConfiguration: (query) =>
1337
+ Promise.resolve(
1338
+ query.type === "bot/get"
1339
+ ? initializeBotSettingsV1("default")
1340
+ : {
1341
+ schemaVersion: 1 as const,
1342
+ revision: 0,
1343
+ profile: { name: "User" },
1344
+ packages: [],
1345
+ connections: [],
1346
+ },
1347
+ ),
1428
1348
  listRuns: () =>
1429
1349
  Promise.resolve([
1430
1350
  {
@@ -1583,8 +1503,18 @@ describe("hosted Stop", () => {
1583
1503
  await shellClientPlugin({
1584
1504
  transport: {
1585
1505
  turn: () => Promise.resolve({ runId: "run", text: "", events: [] }),
1586
- readConfiguration: () =>
1587
- Promise.resolve(initializeBotSettingsV1("default")),
1506
+ readConfiguration: (query) =>
1507
+ Promise.resolve(
1508
+ query.type === "bot/get"
1509
+ ? initializeBotSettingsV1("default")
1510
+ : {
1511
+ schemaVersion: 1 as const,
1512
+ revision: 0,
1513
+ profile: { name: "User" },
1514
+ packages: [],
1515
+ connections: [],
1516
+ },
1517
+ ),
1588
1518
  listRuns: () =>
1589
1519
  Promise.resolve([
1590
1520
  {
@@ -1619,7 +1549,7 @@ describe("hosted Stop", () => {
1619
1549
  expect(provided.value.activeRun).toMatchObject({
1620
1550
  runId: "run-1",
1621
1551
  status: "running",
1622
- message: "Stop accepted; waiting for durable settlement.",
1552
+ message: "Stop requested; finishing up.",
1623
1553
  canResume: false,
1624
1554
  });
1625
1555
 
@@ -1715,8 +1645,18 @@ describe("hosted Stop", () => {
1715
1645
  await shellClientPlugin({
1716
1646
  transport: {
1717
1647
  turn: () => Promise.resolve({ runId: "run", text: "", events: [] }),
1718
- readConfiguration: () =>
1719
- Promise.resolve(initializeBotSettingsV1("other")),
1648
+ readConfiguration: (query) =>
1649
+ Promise.resolve(
1650
+ query.type === "bot/get"
1651
+ ? initializeBotSettingsV1("other")
1652
+ : {
1653
+ schemaVersion: 1 as const,
1654
+ revision: 0,
1655
+ profile: { name: "User" },
1656
+ packages: [],
1657
+ connections: [],
1658
+ },
1659
+ ),
1720
1660
  listRuns: () => Promise.resolve([]),
1721
1661
  listNotifications: () => Promise.resolve([]),
1722
1662
  stopRun: () => {
@@ -1788,7 +1728,7 @@ describe("uncertain Turn admission", () => {
1788
1728
  input: "continue",
1789
1729
  status: lookups === 2 ? "running" : "completed",
1790
1730
  events: [],
1791
- ...(lookups === 2 ? {} : { responseText: "Done durably" }),
1731
+ ...(lookups === 2 ? {} : { responseText: "Done successfully" }),
1792
1732
  });
1793
1733
  },
1794
1734
  fenceRunAdmission: () =>
@@ -1822,7 +1762,7 @@ describe("uncertain Turn admission", () => {
1822
1762
  expect(provided.value.settingsError).toBeUndefined();
1823
1763
  expect(outstandingAbortListeners).toBe(0);
1824
1764
  expect(provided.value.messages.at(-1)).toMatchObject({
1825
- text: "Done durably",
1765
+ text: "Done successfully",
1826
1766
  status: "completed",
1827
1767
  });
1828
1768
  });