openbot 0.5.8 → 0.5.9

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/CLAUDE.md CHANGED
@@ -31,7 +31,7 @@ OpenBot is a local-first, event-driven harness for running AI agents, built on t
31
31
 
32
32
  Core built-ins: `storage` (infra handlers for `/api/state`), `plugin-manager` (marketplace + npm plugin install). The default agent runtime is **`@meetopenbot/openbot`**, a community npm package installed to `~/.openbot/plugins/@meetopenbot/openbot/` on first boot (`ensureDefaultStack`). Disk-installed plugins take precedence over built-ins in `resolvePlugin`.
33
33
 
34
- A `Plugin`'s `factory(context)` returns a `MelonyPlugin`; `PluginContext` carries `agentId`, `agentDetails`, per-agent `config` (from `AGENT.md` frontmatter), the shared `storage` service, the merged `tools` map, `publicBaseUrl`, the run's `abortSignal`, and `host` (platform hooks: `runAgent`, cloud auth, model registry, config).
34
+ A `Plugin`'s `factory(context)` returns a `MelonyPlugin`; `PluginContext` carries `agentId`, `agentDetails`, per-agent `config` (from `AGENT.md` frontmatter), the shared `storage` service, the merged `tools` map, `publicBaseUrl`, the run's `abortSignal`, and `host` (platform hooks: `runAgent`, cloud auth, config).
35
35
 
36
36
  ### Agents
37
37
 
package/dist/app/cli.js CHANGED
@@ -18,7 +18,7 @@ function checkNodeVersion() {
18
18
  }
19
19
  }
20
20
  checkNodeVersion();
21
- program.name('openbot').description('OpenBot CLI').version('0.5.8');
21
+ program.name('openbot').description('OpenBot CLI').version('0.5.9');
22
22
  program
23
23
  .command('start')
24
24
  .description('Start the OpenBot harness')
@@ -7,6 +7,7 @@ import { abortRegistry, abortKey } from '../services/abort.js';
7
7
  import { loadConfig } from '../app/config.js';
8
8
  import { getPublicBaseUrl } from '../plugins/storage/files.js';
9
9
  import { createPluginHost } from '../services/plugins/host.js';
10
+ import { getInvokeConfigOverrides, mergePluginConfig } from './merge-plugin-config.js';
10
11
  export { STATE_AGENT_ID, ORCHESTRATOR_AGENT_ID };
11
12
  async function emitEvent(chunk, state, { persistEvents, channelId, threadId, onEvent, parentAgentId, parentToolCallId, }) {
12
13
  ensureEventId(chunk);
@@ -69,6 +70,11 @@ export async function runAgent(options) {
69
70
  }
70
71
  const builder = melony().initialState(state);
71
72
  const pluginHost = createPluginHost(runAgent);
73
+ const invokeConfigOverrides = getInvokeConfigOverrides(event);
74
+ const pluginConfigs = Object.fromEntries(pluginRefs.map((ref) => [
75
+ ref.id,
76
+ mergePluginConfig(ref.config, invokeConfigOverrides, ref.id),
77
+ ]));
72
78
  for (const ref of pluginRefs) {
73
79
  const plugin = await resolvePlugin(ref.id);
74
80
  if (!plugin)
@@ -76,7 +82,7 @@ export async function runAgent(options) {
76
82
  builder.use(plugin.factory({
77
83
  agentId,
78
84
  agentDetails,
79
- config: ref.config ?? {},
85
+ config: pluginConfigs[ref.id],
80
86
  storage: storageService,
81
87
  tools,
82
88
  publicBaseUrl,
@@ -0,0 +1,26 @@
1
+ function isPlainObject(value) {
2
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
3
+ }
4
+ function isPluginKeyedConfig(config) {
5
+ return Object.values(config).every(isPlainObject);
6
+ }
7
+ export function getInvokeConfigOverrides(event) {
8
+ if (event.type !== 'agent:invoke')
9
+ return undefined;
10
+ const config = event.data?.config;
11
+ if (!isPlainObject(config) || Object.keys(config).length === 0)
12
+ return undefined;
13
+ return config;
14
+ }
15
+ export function mergePluginConfig(base, overrides, pluginId) {
16
+ const baseConfig = base ?? {};
17
+ if (!overrides)
18
+ return baseConfig;
19
+ if (isPluginKeyedConfig(overrides)) {
20
+ const pluginOverride = overrides[pluginId];
21
+ if (!isPlainObject(pluginOverride))
22
+ return baseConfig;
23
+ return { ...baseConfig, ...pluginOverride };
24
+ }
25
+ return { ...baseConfig, ...overrides };
26
+ }
@@ -9,7 +9,7 @@ import crypto from 'node:crypto';
9
9
  import matter from 'gray-matter';
10
10
  import { OPENBOT_PLUGIN_ID } from '../../app/openbot-plugin.js';
11
11
  import { listBuiltInPlugins, parsePluginModule } from '../../services/plugins/registry.js';
12
- import { enrichOpenbotPluginDescriptor, listRegistryModelOptions, } from '../../services/plugins/model-registry.js';
12
+ import { enrichOpenbotPluginDescriptor } from '../../services/plugins/enrich-openbot-plugin.js';
13
13
  import { processService } from '../../services/process.js';
14
14
  import { memoryService } from '../memory/service.js';
15
15
  import { guessMimeType, resolveChannelFile, statChannelFile } from './files.js';
@@ -837,13 +837,12 @@ export const storageService = {
837
837
  return Array.from(deduped.values()).filter((agent) => !agent.hidden);
838
838
  },
839
839
  getPlugins: async () => {
840
- const [builtIn, fromDisk, modelOptions] = await Promise.all([
840
+ const [builtIn, fromDisk] = await Promise.all([
841
841
  listBuiltInPluginDescriptors(),
842
842
  listPluginsFromDisk(),
843
- listRegistryModelOptions(),
844
843
  ]);
845
- const enrichedBuiltIn = builtIn.map((plugin) => enrichOpenbotPluginDescriptor(plugin, modelOptions));
846
- const merged = [...enrichedBuiltIn, ...fromDisk];
844
+ const enrichPlugin = (plugin) => enrichOpenbotPluginDescriptor(plugin);
845
+ const merged = [...builtIn.map(enrichPlugin), ...fromDisk.map(enrichPlugin)];
847
846
  const deduped = new Map();
848
847
  for (const plugin of merged) {
849
848
  if (!deduped.has(plugin.id)) {
@@ -0,0 +1,38 @@
1
+ import { OPENBOT_PLUGIN_ID } from '../../app/openbot-plugin.js';
2
+ import { DEFAULT_CLOUD_OPENBOT_AUTH_MODE, isCloudMode } from '../../app/cloud-mode.js';
3
+ /** Injects cloud platform fields into the openbot plugin descriptor for settings UI. */
4
+ export function enrichOpenbotPluginDescriptor(descriptor) {
5
+ if (descriptor.id !== OPENBOT_PLUGIN_ID || !descriptor.configSchema)
6
+ return descriptor;
7
+ if (!isCloudMode())
8
+ return descriptor;
9
+ const { authMode: _authMode, ...otherProperties } = descriptor.configSchema.properties;
10
+ const cloudAuthModeProperty = {
11
+ type: 'string',
12
+ description: 'Credits uses OpenBot platform billing. BYOK uses your own API keys.',
13
+ enum: ['credits', 'byok'],
14
+ default: DEFAULT_CLOUD_OPENBOT_AUTH_MODE,
15
+ options: [
16
+ {
17
+ label: 'Credits',
18
+ value: 'credits',
19
+ description: 'Use OpenBot platform credits.',
20
+ },
21
+ {
22
+ label: 'Bring your own key',
23
+ value: 'byok',
24
+ description: 'Use your own provider API keys.',
25
+ },
26
+ ],
27
+ };
28
+ return {
29
+ ...descriptor,
30
+ configSchema: {
31
+ ...descriptor.configSchema,
32
+ properties: {
33
+ authMode: cloudAuthModeProperty,
34
+ ...otherProperties,
35
+ },
36
+ },
37
+ };
38
+ }
@@ -2,15 +2,12 @@ import { DEFAULT_CLOUD_OPENBOT_AUTH_MODE, isCloudMode, isCloudSystemAgent, parse
2
2
  import { ORCHESTRATOR_AGENT_ID } from '../../app/agent-ids.js';
3
3
  import { OPENBOT_PLUGIN_ID } from '../../app/openbot-plugin.js';
4
4
  import { getBaseDir, resolvePath, saveConfig } from '../../app/config.js';
5
- import { listApiKeyProvidersFromRegistry, resolveModelRegistry, } from './model-registry.js';
6
5
  export function createPluginHost(runAgent) {
7
6
  return {
8
7
  runAgent,
9
8
  isCloudSystemAgent,
10
9
  isCloudMode,
11
10
  parseOpenbotAuthMode,
12
- resolveModelRegistry,
13
- listApiKeyProvidersFromRegistry,
14
11
  saveConfig,
15
12
  getBaseDir,
16
13
  resolvePath,
@@ -74,7 +74,7 @@ export function enrichOpenbotPluginDescriptor(descriptor, modelOptions) {
74
74
  : pickDefaultModelValue(modelOptions) ?? staticDefault;
75
75
  const nextModelProperty = {
76
76
  ...modelProperty,
77
- description: 'Model from the hosted marketplace registry.',
77
+ description: modelProperty.description ?? 'Model from the hosted marketplace registry.',
78
78
  };
79
79
  if (values.length > 0) {
80
80
  nextModelProperty.enum = values;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openbot",
3
- "version": "0.5.8",
3
+ "version": "0.5.9",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "engines": {
@@ -11,7 +11,7 @@
11
11
  "build": "tsc && mkdir -p dist/assets && cp src/assets/icon.svg dist/assets/icon.svg",
12
12
  "start": "node dist/app/cli.js start",
13
13
  "format": "prettier --write .",
14
- "push": "fly deploy --build-only --push --config deploy/fly.toml -a openbot-runtime --image-label v0.5.8"
14
+ "push": "fly deploy --build-only --push --config deploy/fly.toml -a openbot-runtime --image-label v0.5.9"
15
15
  },
16
16
  "bin": {
17
17
  "openbot": "./dist/app/cli.js"
package/src/app/cli.ts CHANGED
@@ -27,7 +27,7 @@ function checkNodeVersion() {
27
27
 
28
28
  checkNodeVersion();
29
29
 
30
- program.name('openbot').description('OpenBot CLI').version('0.5.8');
30
+ program.name('openbot').description('OpenBot CLI').version('0.5.9');
31
31
 
32
32
  program
33
33
  .command('start')
package/src/app/types.ts CHANGED
@@ -42,6 +42,8 @@ export type AgentInvokeEvent = BaseEvent & {
42
42
  role?: 'user' | 'assistant' | 'system';
43
43
  content: string;
44
44
  agentId?: string;
45
+ /** Per-run config overrides: flat fields (e.g. model) or nested by plugin id. */
46
+ config?: Record<string, unknown>;
45
47
  };
46
48
  };
47
49
 
@@ -9,6 +9,7 @@ import { abortRegistry, abortKey } from '../services/abort.js';
9
9
  import { loadConfig } from '../app/config.js';
10
10
  import { getPublicBaseUrl } from '../plugins/storage/files.js';
11
11
  import { createPluginHost } from '../services/plugins/host.js';
12
+ import { getInvokeConfigOverrides, mergePluginConfig } from './merge-plugin-config.js';
12
13
 
13
14
  export { STATE_AGENT_ID, ORCHESTRATOR_AGENT_ID };
14
15
 
@@ -121,6 +122,13 @@ export async function runAgent(options: RunAgentOptions): Promise<void> {
121
122
  const builder = melony<OpenBotState, OpenBotEvent>().initialState(state);
122
123
 
123
124
  const pluginHost = createPluginHost(runAgent);
125
+ const invokeConfigOverrides = getInvokeConfigOverrides(event);
126
+ const pluginConfigs = Object.fromEntries(
127
+ pluginRefs.map((ref) => [
128
+ ref.id,
129
+ mergePluginConfig(ref.config, invokeConfigOverrides, ref.id),
130
+ ]),
131
+ );
124
132
 
125
133
  for (const ref of pluginRefs) {
126
134
  const plugin = await resolvePlugin(ref.id);
@@ -130,7 +138,7 @@ export async function runAgent(options: RunAgentOptions): Promise<void> {
130
138
  plugin.factory({
131
139
  agentId,
132
140
  agentDetails,
133
- config: ref.config ?? {},
141
+ config: pluginConfigs[ref.id],
134
142
  storage: storageService,
135
143
  tools,
136
144
  publicBaseUrl,
@@ -0,0 +1,35 @@
1
+ import { OpenBotEvent } from '../app/types.js';
2
+
3
+ function isPlainObject(value: unknown): value is Record<string, unknown> {
4
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
5
+ }
6
+
7
+ function isPluginKeyedConfig(config: Record<string, unknown>): boolean {
8
+ return Object.values(config).every(isPlainObject);
9
+ }
10
+
11
+ export function getInvokeConfigOverrides(event: OpenBotEvent): Record<string, unknown> | undefined {
12
+ if (event.type !== 'agent:invoke') return undefined;
13
+
14
+ const config = event.data?.config;
15
+ if (!isPlainObject(config) || Object.keys(config).length === 0) return undefined;
16
+
17
+ return config;
18
+ }
19
+
20
+ export function mergePluginConfig(
21
+ base: Record<string, unknown> | undefined,
22
+ overrides: Record<string, unknown> | undefined,
23
+ pluginId: string,
24
+ ): Record<string, unknown> {
25
+ const baseConfig = base ?? {};
26
+ if (!overrides) return baseConfig;
27
+
28
+ if (isPluginKeyedConfig(overrides)) {
29
+ const pluginOverride = overrides[pluginId];
30
+ if (!isPlainObject(pluginOverride)) return baseConfig;
31
+ return { ...baseConfig, ...pluginOverride };
32
+ }
33
+
34
+ return { ...baseConfig, ...overrides };
35
+ }
@@ -33,10 +33,7 @@ import {
33
33
  import type { PluginRef } from '../../services/plugins/types.js';
34
34
  import { OPENBOT_PLUGIN_ID } from '../../app/openbot-plugin.js';
35
35
  import { listBuiltInPlugins, parsePluginModule } from '../../services/plugins/registry.js';
36
- import {
37
- enrichOpenbotPluginDescriptor,
38
- listRegistryModelOptions,
39
- } from '../../services/plugins/model-registry.js';
36
+ import { enrichOpenbotPluginDescriptor } from '../../services/plugins/enrich-openbot-plugin.js';
40
37
  import { OpenBotEvent, OpenBotState } from '../../app/types.js';
41
38
  import { processService } from '../../services/process.js';
42
39
  import { memoryService } from '../memory/service.js';
@@ -1056,17 +1053,14 @@ export const storageService = {
1056
1053
  return Array.from(deduped.values()).filter((agent) => !agent.hidden);
1057
1054
  },
1058
1055
  getPlugins: async (): Promise<PluginDescriptor[]> => {
1059
- const [builtIn, fromDisk, modelOptions] = await Promise.all([
1056
+ const [builtIn, fromDisk] = await Promise.all([
1060
1057
  listBuiltInPluginDescriptors(),
1061
1058
  listPluginsFromDisk(),
1062
- listRegistryModelOptions(),
1063
1059
  ]);
1064
1060
 
1065
- const enrichedBuiltIn = builtIn.map((plugin) =>
1066
- enrichOpenbotPluginDescriptor(plugin, modelOptions),
1067
- );
1061
+ const enrichPlugin = (plugin: PluginDescriptor) => enrichOpenbotPluginDescriptor(plugin);
1068
1062
 
1069
- const merged = [...enrichedBuiltIn, ...fromDisk];
1063
+ const merged = [...builtIn.map(enrichPlugin), ...fromDisk.map(enrichPlugin)];
1070
1064
  const deduped = new Map<string, PluginDescriptor>();
1071
1065
  for (const plugin of merged) {
1072
1066
  if (!deduped.has(plugin.id)) {
@@ -0,0 +1,41 @@
1
+ import { OPENBOT_PLUGIN_ID } from '../../app/openbot-plugin.js';
2
+ import { DEFAULT_CLOUD_OPENBOT_AUTH_MODE, isCloudMode } from '../../app/cloud-mode.js';
3
+ import type { ConfigSchema, PluginDescriptor } from './domain.js';
4
+
5
+ /** Injects cloud platform fields into the openbot plugin descriptor for settings UI. */
6
+ export function enrichOpenbotPluginDescriptor(descriptor: PluginDescriptor): PluginDescriptor {
7
+ if (descriptor.id !== OPENBOT_PLUGIN_ID || !descriptor.configSchema) return descriptor;
8
+ if (!isCloudMode()) return descriptor;
9
+
10
+ const { authMode: _authMode, ...otherProperties } = descriptor.configSchema.properties;
11
+
12
+ const cloudAuthModeProperty: ConfigSchema['properties'][string] = {
13
+ type: 'string',
14
+ description: 'Credits uses OpenBot platform billing. BYOK uses your own API keys.',
15
+ enum: ['credits', 'byok'],
16
+ default: DEFAULT_CLOUD_OPENBOT_AUTH_MODE,
17
+ options: [
18
+ {
19
+ label: 'Credits',
20
+ value: 'credits',
21
+ description: 'Use OpenBot platform credits.',
22
+ },
23
+ {
24
+ label: 'Bring your own key',
25
+ value: 'byok',
26
+ description: 'Use your own provider API keys.',
27
+ },
28
+ ],
29
+ };
30
+
31
+ return {
32
+ ...descriptor,
33
+ configSchema: {
34
+ ...descriptor.configSchema,
35
+ properties: {
36
+ authMode: cloudAuthModeProperty,
37
+ ...otherProperties,
38
+ },
39
+ },
40
+ };
41
+ }
@@ -8,10 +8,6 @@ import {
8
8
  import { ORCHESTRATOR_AGENT_ID } from '../../app/agent-ids.js';
9
9
  import { OPENBOT_PLUGIN_ID } from '../../app/openbot-plugin.js';
10
10
  import { getBaseDir, resolvePath, saveConfig } from '../../app/config.js';
11
- import {
12
- listApiKeyProvidersFromRegistry,
13
- resolveModelRegistry,
14
- } from './model-registry.js';
15
11
  import type { PluginHost, RunAgentHostOptions } from './types.js';
16
12
 
17
13
  export function createPluginHost(
@@ -22,8 +18,6 @@ export function createPluginHost(
22
18
  isCloudSystemAgent,
23
19
  isCloudMode,
24
20
  parseOpenbotAuthMode,
25
- resolveModelRegistry,
26
- listApiKeyProvidersFromRegistry,
27
21
  saveConfig,
28
22
  getBaseDir,
29
23
  resolvePath,
@@ -38,12 +38,6 @@ export interface PluginHost {
38
38
  isCloudSystemAgent: (agentId: string) => boolean;
39
39
  isCloudMode: () => boolean;
40
40
  parseOpenbotAuthMode: (value: unknown) => 'credits' | 'byok';
41
- resolveModelRegistry: () => ReturnType<
42
- typeof import('./model-registry.js').resolveModelRegistry
43
- >;
44
- listApiKeyProvidersFromRegistry: (
45
- registry: Awaited<ReturnType<PluginHost['resolveModelRegistry']>>,
46
- ) => Array<{ id: string; label: string }>;
47
41
  saveConfig: (patch: Record<string, unknown>) => void;
48
42
  getBaseDir: () => string;
49
43
  resolvePath: (p: string) => string;
@@ -1,178 +0,0 @@
1
- import {
2
- DEFAULT_MARKETPLACE_REGISTRY_URL,
3
- loadConfig,
4
- } from '../../app/config.js';
5
- import { OPENBOT_PLUGIN_ID } from '../../app/openbot-plugin.js';
6
- import {
7
- DEFAULT_CLOUD_OPENBOT_AUTH_MODE,
8
- isCloudMode,
9
- } from '../../app/cloud-mode.js';
10
- import type { ConfigSchema, PluginDescriptor } from './domain.js';
11
-
12
- export type RegistryProviderCatalog = Record<
13
- string,
14
- {
15
- label: string;
16
- models: Array<{ id: string; label: string; description: string }>;
17
- }
18
- >;
19
-
20
- export type ModelRegistry = {
21
- providers?: RegistryProviderCatalog;
22
- };
23
-
24
- export type RegistryModelOption = {
25
- value: string;
26
- label: string;
27
- description?: string;
28
- provider: string;
29
- };
30
-
31
- let cachedRegistry: ModelRegistry | null = null;
32
- let cacheUrl: string | null = null;
33
-
34
- function getRegistryUrl(): string {
35
- const { marketplaceRegistryUrl } = loadConfig();
36
- return marketplaceRegistryUrl?.trim() || DEFAULT_MARKETPLACE_REGISTRY_URL;
37
- }
38
-
39
- export async function resolveModelRegistry(): Promise<ModelRegistry> {
40
- const url = getRegistryUrl();
41
- if (cachedRegistry && cacheUrl === url) return cachedRegistry;
42
-
43
- try {
44
- const res = await fetch(url, {
45
- headers: { Accept: 'application/json' },
46
- signal: AbortSignal.timeout(15_000),
47
- });
48
- if (!res.ok) {
49
- throw new Error(`Registry HTTP ${res.status} ${res.statusText}`);
50
- }
51
- cachedRegistry = (await res.json()) as ModelRegistry;
52
- cacheUrl = url;
53
- return cachedRegistry;
54
- } catch (err) {
55
- console.warn(
56
- '[model-registry] fetch failed:',
57
- err instanceof Error ? err.message : err,
58
- );
59
- return { providers: {} };
60
- }
61
- }
62
-
63
- export function listModelOptionsFromRegistry(registry: ModelRegistry): RegistryModelOption[] {
64
- const providers = registry.providers ?? {};
65
- const out: RegistryModelOption[] = [];
66
-
67
- for (const [providerId, provider] of Object.entries(providers)) {
68
- for (const model of provider.models ?? []) {
69
- out.push({
70
- value: `${providerId}/${model.id}`,
71
- label: `${provider.label} — ${model.label}`,
72
- description: model.description,
73
- provider: providerId,
74
- });
75
- }
76
- }
77
-
78
- return out;
79
- }
80
-
81
- export async function listRegistryModelOptions(): Promise<RegistryModelOption[]> {
82
- const registry = await resolveModelRegistry();
83
- return listModelOptionsFromRegistry(registry);
84
- }
85
-
86
- export function listApiKeyProvidersFromRegistry(
87
- registry: ModelRegistry,
88
- ): Array<{ id: string; label: string }> {
89
- const providers = registry.providers ?? {};
90
- return Object.entries(providers).map(([id, provider]) => ({
91
- id,
92
- label: provider.label,
93
- }));
94
- }
95
-
96
- function pickDefaultModelValue(options: RegistryModelOption[]): string | undefined {
97
- if (options.length === 0) return undefined;
98
- const values = options.map((option) => option.value);
99
- const preferred = values.find((value) => value.startsWith('openai/'));
100
- return preferred ?? values[0];
101
- }
102
-
103
- export function enrichOpenbotPluginDescriptor(
104
- descriptor: PluginDescriptor,
105
- modelOptions: RegistryModelOption[],
106
- ): PluginDescriptor {
107
- if (descriptor.id !== OPENBOT_PLUGIN_ID || !descriptor.configSchema) return descriptor;
108
-
109
- const modelProperty = descriptor.configSchema.properties.model;
110
- if (!modelProperty) return descriptor;
111
-
112
- const values = modelOptions.map((option) => option.value);
113
- const staticDefault =
114
- typeof modelProperty.default === 'string' ? modelProperty.default : undefined;
115
- const defaultModel =
116
- staticDefault && values.includes(staticDefault)
117
- ? staticDefault
118
- : pickDefaultModelValue(modelOptions) ?? staticDefault;
119
-
120
- const nextModelProperty: ConfigSchema['properties'][string] = {
121
- ...modelProperty,
122
- description: 'Model from the hosted marketplace registry.',
123
- };
124
-
125
- if (values.length > 0) {
126
- nextModelProperty.enum = values;
127
- nextModelProperty.options = modelOptions.map((option) => ({
128
- label: option.label,
129
- value: option.value,
130
- description: option.description,
131
- }));
132
- }
133
-
134
- if (defaultModel) {
135
- nextModelProperty.default = defaultModel;
136
- }
137
-
138
- const { model: _model, authMode: _authMode, ...otherProperties } =
139
- descriptor.configSchema.properties;
140
-
141
- const cloudAuthModeProperty: ConfigSchema['properties'][string] = {
142
- type: 'string',
143
- description: 'Credits uses OpenBot platform billing. BYOK uses your own API keys.',
144
- enum: ['credits', 'byok'],
145
- default: DEFAULT_CLOUD_OPENBOT_AUTH_MODE,
146
- options: [
147
- {
148
- label: 'Credits',
149
- value: 'credits',
150
- description: 'Use OpenBot platform credits.',
151
- },
152
- {
153
- label: 'Bring your own key',
154
- value: 'byok',
155
- description: 'Use your own provider API keys.',
156
- },
157
- ],
158
- };
159
-
160
- const nextProperties: ConfigSchema['properties'] = isCloudMode()
161
- ? {
162
- authMode: cloudAuthModeProperty,
163
- model: nextModelProperty,
164
- ...otherProperties,
165
- }
166
- : {
167
- model: nextModelProperty,
168
- ...otherProperties,
169
- };
170
-
171
- return {
172
- ...descriptor,
173
- configSchema: {
174
- ...descriptor.configSchema,
175
- properties: nextProperties,
176
- },
177
- };
178
- }