@frockbot/plugin-custom-models 0.0.0 → 0.3.12

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.
@@ -0,0 +1,151 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import {
3
+ resolveEffectiveBotModelV1,
4
+ type BotSettingsViewV1,
5
+ type ExecutionPackageDefinition,
6
+ type ModelBindingV1,
7
+ type UserSettingsViewV1,
8
+ } from "@frockbot/configuration-core";
9
+ import { decodeFrockBotManifest } from "@frockbot/kernel-composition";
10
+ import rawManifest from "../frockbot.json" with { type: "json" };
11
+
12
+ const platformModel: ModelBindingV1 = {
13
+ connectionId: "flock-ai",
14
+ providerModelId: "@frock/auto",
15
+ };
16
+ const accountModel: ModelBindingV1 = {
17
+ connectionId: "flock-ai",
18
+ providerModelId: "@frock/manual",
19
+ };
20
+ const botModel: ModelBindingV1 = {
21
+ connectionId: "flock-ai",
22
+ providerModelId: "@frock/bot",
23
+ };
24
+
25
+ const customManifest = decodeFrockBotManifest(rawManifest);
26
+ const packages: ExecutionPackageDefinition[] = [
27
+ {
28
+ packageId: "provider-flock-ai",
29
+ version: "0.0.1",
30
+ settings: [],
31
+ capabilities: [
32
+ {
33
+ id: "flock-ai-models",
34
+ kind: "model",
35
+ connectionTypes: ["flock-ai-account"],
36
+ },
37
+ ],
38
+ connectionTypes: [
39
+ { id: "flock-ai-account", capabilities: ["flock-ai-models"] },
40
+ ],
41
+ },
42
+ {
43
+ packageId: customManifest.id,
44
+ version: customManifest.version,
45
+ settings: customManifest.configuration?.settings ?? [],
46
+ capabilities: [],
47
+ connectionTypes: [],
48
+ },
49
+ ];
50
+
51
+ function user(state: "disabled" | "installed"): UserSettingsViewV1 {
52
+ return {
53
+ schemaVersion: 1,
54
+ revision: 1,
55
+ profile: { name: "User" },
56
+ packages: [
57
+ {
58
+ packageId: "provider-flock-ai",
59
+ version: "0.0.1",
60
+ state: "installed",
61
+ },
62
+ {
63
+ packageId: "custom-models",
64
+ version: "0.0.1",
65
+ state,
66
+ values: { "account-model": accountModel },
67
+ },
68
+ ],
69
+ connections: [
70
+ {
71
+ connectionId: "flock-ai",
72
+ packageId: "provider-flock-ai",
73
+ connectionTypeId: "flock-ai-account",
74
+ displayName: "Frock AI",
75
+ state: "ready",
76
+ providerType: "flock-ai",
77
+ modelCatalog: {
78
+ schemaVersion: 1,
79
+ generation: "catalog-1",
80
+ state: "fresh",
81
+ models: [platformModel, accountModel, botModel].map((model) => ({
82
+ providerModelId: model.providerModelId,
83
+ displayName: model.providerModelId,
84
+ capabilities: { tools: true, vision: false, reasoning: true },
85
+ source: "discovered" as const,
86
+ })),
87
+ },
88
+ safeMetadata: {},
89
+ },
90
+ ],
91
+ platformModel,
92
+ };
93
+ }
94
+
95
+ function bot(): BotSettingsViewV1 {
96
+ return {
97
+ schemaVersion: 1,
98
+ botId: "scout",
99
+ revision: 1,
100
+ profile: { name: "Scout" },
101
+ notifications: { enabled: true },
102
+ packageValues: { "custom-models": { model: botModel } },
103
+ };
104
+ }
105
+
106
+ describe("Custom models resolution", () => {
107
+ test("ignores preserved Custom models values while disabled and restores Bot-over-account precedence when re-enabled", () => {
108
+ const disabledUser = user("disabled");
109
+ const configuredBot = bot();
110
+ const storedAccountValues = structuredClone(
111
+ disabledUser.packages[1]?.values,
112
+ );
113
+ const storedBotValues = structuredClone(configuredBot.packageValues);
114
+
115
+ expect(
116
+ resolveEffectiveBotModelV1({
117
+ bot: configuredBot,
118
+ user: disabledUser,
119
+ packages,
120
+ }),
121
+ ).toMatchObject({ source: "platform", model: platformModel });
122
+ expect(disabledUser.packages[1]?.values).toEqual(storedAccountValues);
123
+ expect(configuredBot.packageValues).toEqual(storedBotValues);
124
+
125
+ const enabledUser = user("installed");
126
+ expect(
127
+ resolveEffectiveBotModelV1({
128
+ bot: configuredBot,
129
+ user: enabledUser,
130
+ packages,
131
+ }),
132
+ ).toMatchObject({ source: "bot", model: botModel });
133
+ expect(
134
+ resolveEffectiveBotModelV1({
135
+ bot: { packageValues: {} },
136
+ user: enabledUser,
137
+ packages,
138
+ }),
139
+ ).toMatchObject({ source: "account", model: accountModel });
140
+
141
+ const withoutAccount = user("installed");
142
+ delete withoutAccount.packages[1]?.values;
143
+ expect(
144
+ resolveEffectiveBotModelV1({
145
+ bot: { packageValues: {} },
146
+ user: withoutAccount,
147
+ packages,
148
+ }),
149
+ ).toMatchObject({ source: "platform", model: platformModel });
150
+ });
151
+ });
@@ -0,0 +1,19 @@
1
+ import {
2
+ decodeModelBindingV1,
3
+ type ModelBindingV1,
4
+ } from "@frockbot/configuration-core";
5
+
6
+ export const ACCOUNT_MODEL_SETTING_ID_V1 = "account-model";
7
+ export const BOT_MODEL_SETTING_ID_V1 = "model";
8
+
9
+ /** A model-role value has already crossed a decoded settings seam; be defensive when reading an absent or stale value. */
10
+ export function storedModelBindingV1(
11
+ value: unknown,
12
+ ): ModelBindingV1 | undefined {
13
+ if (value === undefined) return undefined;
14
+ try {
15
+ return decodeModelBindingV1(value);
16
+ } catch {
17
+ return undefined;
18
+ }
19
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2023",
4
+ "module": "ESNext",
5
+ "moduleResolution": "Bundler",
6
+ "allowImportingTsExtensions": true,
7
+ "resolveJsonModule": true,
8
+ "strict": true,
9
+ "noEmit": true,
10
+ "skipLibCheck": true,
11
+ "lib": ["ES2023", "DOM", "DOM.Iterable"],
12
+ "types": ["bun", "vite/client"]
13
+ },
14
+ "include": ["src/**/*.ts", "src/**/*.vue"]
15
+ }
package/vite.config.ts ADDED
@@ -0,0 +1,32 @@
1
+ import { fileURLToPath } from "node:url";
2
+ import vue from "@vitejs/plugin-vue";
3
+ import { defineConfig } from "vite";
4
+
5
+ export default defineConfig({
6
+ plugins: [vue()],
7
+ build: {
8
+ outDir: fileURLToPath(new URL("./dist", import.meta.url)),
9
+ emptyOutDir: true,
10
+ manifest: "manifest.json",
11
+ cssCodeSplit: false,
12
+ assetsInlineLimit: Number.POSITIVE_INFINITY,
13
+ lib: {
14
+ entry: fileURLToPath(new URL("./src/client/index.ts", import.meta.url)),
15
+ formats: ["es"],
16
+ },
17
+ rollupOptions: {
18
+ external: [
19
+ "vue",
20
+ "@frockbot/client-core",
21
+ "@frockbot/client-ui",
22
+ "@frockbot/plugin-shell/shared",
23
+ "@frockbot/plugin-settings/client",
24
+ ],
25
+ output: {
26
+ entryFileNames: "assets/custom-models-[hash].js",
27
+ chunkFileNames: "assets/chunk-[hash].js",
28
+ assetFileNames: "assets/[name]-[hash][extname]",
29
+ },
30
+ },
31
+ },
32
+ });
package/README.md DELETED
@@ -1,3 +0,0 @@
1
- # @frockbot/plugin-custom-models
2
-
3
- Placeholder reserving this name. See https://github.com/timoconnellaus/frockbot.