@meetopenbot/plugin-sdk 0.2.0 → 0.4.0

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.
Files changed (49) hide show
  1. package/README.md +30 -40
  2. package/dist/agent-plugin.d.ts +55 -0
  3. package/dist/agent-plugin.d.ts.map +1 -0
  4. package/dist/agent-plugin.js +118 -0
  5. package/dist/agent-plugin.js.map +1 -0
  6. package/dist/cloud-mode.d.ts +14 -0
  7. package/dist/cloud-mode.d.ts.map +1 -0
  8. package/dist/cloud-mode.js +26 -0
  9. package/dist/cloud-mode.js.map +1 -0
  10. package/dist/credits-auth.d.ts +47 -0
  11. package/dist/credits-auth.d.ts.map +1 -0
  12. package/dist/credits-auth.js +139 -0
  13. package/dist/credits-auth.js.map +1 -0
  14. package/dist/helpers.d.ts +90 -2
  15. package/dist/helpers.d.ts.map +1 -1
  16. package/dist/helpers.js +195 -0
  17. package/dist/helpers.js.map +1 -1
  18. package/dist/index.d.ts +9 -0
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +9 -0
  21. package/dist/index.js.map +1 -1
  22. package/dist/mcp-agent.d.ts +36 -0
  23. package/dist/mcp-agent.d.ts.map +1 -0
  24. package/dist/mcp-agent.js +93 -0
  25. package/dist/mcp-agent.js.map +1 -0
  26. package/dist/mcp-args.d.ts +3 -0
  27. package/dist/mcp-args.d.ts.map +1 -0
  28. package/dist/mcp-args.js +41 -0
  29. package/dist/mcp-args.js.map +1 -0
  30. package/dist/model-registry.d.ts +54 -0
  31. package/dist/model-registry.d.ts.map +1 -0
  32. package/dist/model-registry.js +109 -0
  33. package/dist/model-registry.js.map +1 -0
  34. package/dist/openai-model.d.ts +4 -0
  35. package/dist/openai-model.d.ts.map +1 -0
  36. package/dist/openai-model.js +13 -0
  37. package/dist/openai-model.js.map +1 -0
  38. package/dist/plugin.d.ts +6 -0
  39. package/dist/plugin.d.ts.map +1 -1
  40. package/dist/plugin.js.map +1 -1
  41. package/dist/text-reply.d.ts +30 -0
  42. package/dist/text-reply.d.ts.map +1 -0
  43. package/dist/text-reply.js +53 -0
  44. package/dist/text-reply.js.map +1 -0
  45. package/dist/thread-context.d.ts +15 -0
  46. package/dist/thread-context.d.ts.map +1 -0
  47. package/dist/thread-context.js +69 -0
  48. package/dist/thread-context.js.map +1 -0
  49. package/package.json +7 -2
package/README.md CHANGED
@@ -35,13 +35,11 @@ export default definePlugin({
35
35
  configSchema: {
36
36
  type: "object",
37
37
  properties: {
38
- apiKey: {
38
+ model: {
39
39
  type: "string",
40
- description: "Your API Key",
41
- format: "password",
40
+ description: "Model id",
42
41
  },
43
42
  },
44
- required: ["apiKey"],
45
43
  },
46
44
  factory: (context) => (builder) => {
47
45
  builder.on("agent:invoke", async function* (event) {
@@ -97,16 +95,14 @@ export default definePlugin({
97
95
  configSchema: {
98
96
  type: "object",
99
97
  properties: {
100
- signingSecret: {
98
+ channelMappings: {
101
99
  type: "string",
102
- description: "Slack signing secret",
103
- format: "password",
100
+ description: "slackChannelId:openbotChannelId pairs",
104
101
  },
105
102
  },
106
- required: ["signingSecret"],
107
103
  },
108
104
  factory:
109
- ({ config }) =>
105
+ ({ storage }) =>
110
106
  (builder) => {
111
107
  builder.on("action:webhook", async function* (event) {
112
108
  const webhook = event as WebhookEvent;
@@ -146,10 +142,19 @@ OpenBot is oriented toward **complete messages**. Use the `agentOutput` helper t
146
142
 
147
143
  ### Implementation Strategies
148
144
 
149
- OpenBot plugins are designed for **AI agent behavior**, not just thin translation layers. You can implement this behavior in two primary ways:
145
+ OpenBot plugins are designed for **AI agent behavior**, not just thin translation layers. Prefer `defineMcpAgent` for MCP specialists and `defineAgentPlugin` for harnesses so invoke gating, thread ids, empty prompts, and error mapping stay consistent.
150
146
 
151
- 1. **Third-Party Agent Harness**: If your target platform provides a full agent stack (built-in tools, context management, and reasoning), you can wrap it directly. Examples include **Claude Code**, **Codex**, or other "full agent" SDKs. You connect their internal lifecycle to OpenBot via this SDK's events.
152
- 2. **Custom Agentic Logic**: If the third-party provider only offers a regular API, SDK, or CLI without agentic intelligence, it is recommended to use the [**Vercel AI SDK**](https://sdk.vercel.ai/docs) to build the agent loop. This allows you to add the necessary "intelligence" and tool-calling capabilities on top of the raw integration.
147
+ 1. **Harness**: If the target platform provides a full agent stack (Claude Code, Codex, Cursor, Pi), wrap it and return a text string.
148
+ 2. **Specialist**: Use `defineMcpAgent` (secret + MCP + system prompt). `run` is provided by the SDK.
149
+ 3. **Gateway**: Verify inbound webhooks, yield `webhookHttpResponse`, then emit `agent:invoke`.
150
+
151
+ LLM calls use a provider env key when set (BYOK), otherwise OpenBot Credits. Product API keys are stored as workspace variables and merged into `process.env` by the runtime — look them up with `lookupSecret({ envKeys })`. Missing secrets fail as text. Widgets, diffs, and API-key forms come later.
152
+
153
+ Declare the model picker with `models: { providers, default }` — do not copy `isCloudMode`, credits helpers, or model-registry fields into the plugin:
154
+
155
+ ```typescript
156
+ import { defineAgentPlugin, defineMcpAgent } from "@meetopenbot/plugin-sdk";
157
+ ```
153
158
 
154
159
  ### Storage
155
160
 
@@ -162,53 +167,38 @@ The `PluginContext` provides access to the `storage` interface for interacting w
162
167
 
163
168
  ### UI Widgets
164
169
 
165
- Plugins can render interactive UI widgets using the `uiWidget` helper and handle user interactions by subscribing to `client:ui:widget:response`:
166
-
167
- - `message`: Simple text message with optional actions.
168
- - `choice`: A set of buttons for the user to choose from.
169
- - `form`: A form with various field types.
170
- - `list`: A list of items with status indicators.
171
- - `media`: Images, video, audio, or files.
172
- - `diff`: File changes as a unified (or split) patch view.
173
-
174
- Coding agents should stack tool traces with `toolTraceWidget({ groupId })` and emit one `buildDiffWidget` after the run. Use `snapshotWorkspace` / `resolveRunDiffFiles` so workspace edits show up even when they came from a shell command.
170
+ MVP agents reply with text. Widget helpers remain in the SDK for later.
175
171
 
176
172
  ## Example: Hello World Agent
177
173
 
178
174
  This agent responds to any message with "Hello, World!".
179
175
 
180
176
  ```typescript
181
- import {
182
- definePlugin,
183
- shouldHandleInvoke,
184
- agentOutput,
185
- } from "@meetopenbot/plugin-sdk";
177
+ import { defineAgentPlugin } from "@meetopenbot/plugin-sdk";
186
178
 
187
- export default definePlugin({
188
- id: "hello-world",
179
+ const plugin = await defineAgentPlugin({
189
180
  name: "Hello World",
190
181
  description: "Responds with Hello World",
191
- factory: (context) => (builder) => {
192
- builder.on("agent:invoke", async function* (event) {
193
- if (shouldHandleInvoke(event, context.agentId)) {
194
- yield agentOutput({
195
- agentId: context.agentId,
196
- content: "Hello, World!",
197
- threadId: event.meta?.threadId,
198
- });
199
- }
200
- });
182
+ async run() {
183
+ return "Hello, World!";
201
184
  },
202
185
  });
186
+
187
+ export { plugin };
188
+ export default plugin;
203
189
  ```
204
190
 
205
191
  ## API Reference
206
192
 
207
193
  - [Plugin & Context](./src/plugin.ts)
194
+ - [Agent plugin factory](./src/agent-plugin.ts)
195
+ - [MCP specialist factory](./src/mcp-agent.ts)
196
+ - [Cloud auth & credits](./src/cloud-mode.ts) / [credits-auth.ts](./src/credits-auth.ts)
197
+ - [Model registry field](./src/model-registry.ts)
208
198
  - [Events & State](./src/events.ts)
209
199
  - [Storage Interface](./src/storage.ts)
210
200
  - [UI Widget Specs](./src/ui.ts)
211
- - [Helpers](./src/helpers.ts) (`decodeWebhookRawBody`, `getWebhookHeader`, `webhookHttpResponse`)
201
+ - [Helpers](./src/helpers.ts) (`lookupSecret`, `missingSecretMessage`, `threadSession`, `decodeWebhookRawBody`, `getWebhookHeader`, `webhookHttpResponse`)
212
202
 
213
203
  ## License
214
204
 
@@ -0,0 +1,55 @@
1
+ import type { AgentInvokeEvent, OpenBotEvent, UIWidgetResponseEvent } from './events.js';
2
+ import { type PluginContext, type PluginModule } from './plugin.js';
3
+ import type { PluginHandlerContext } from './runtime.js';
4
+ import type { RenderUIWidgetData } from './ui.js';
5
+ export type AgentTurnYield = {
6
+ kind: 'output' | 'reply';
7
+ content: string;
8
+ } | {
9
+ kind: 'widget';
10
+ widget: RenderUIWidgetData;
11
+ };
12
+ export type AgentTurnArgs = {
13
+ prompt: string;
14
+ threadId: string | undefined;
15
+ event: AgentInvokeEvent;
16
+ handlerCtx: PluginHandlerContext;
17
+ context: PluginContext;
18
+ };
19
+ export type AgentTurnResult = string | void | AsyncIterable<AgentTurnYield | OpenBotEvent>;
20
+ export type AgentWidgetResponseArgs = {
21
+ event: UIWidgetResponseEvent;
22
+ handlerCtx: PluginHandlerContext;
23
+ context: PluginContext;
24
+ };
25
+ /** Catalog slice shown in the shared model dropdown. */
26
+ export type AgentModelsSpec = {
27
+ providers: string[];
28
+ default?: string;
29
+ extraOptions?: Array<{
30
+ label: string;
31
+ value: string;
32
+ description?: string;
33
+ }>;
34
+ };
35
+ export type AgentPluginDefinition = Omit<PluginModule, 'factory'> & {
36
+ /** Registry providers for the model picker. Stamps `configSchema.properties.model`. */
37
+ models?: AgentModelsSpec;
38
+ /** Shown when invoke content is empty. When omitted, empty prompts are ignored. */
39
+ emptyPrompt?: string;
40
+ run: (args: AgentTurnArgs) => AgentTurnResult | Promise<AgentTurnResult>;
41
+ onWidgetResponse?: (args: AgentWidgetResponseArgs) => AsyncIterable<AgentTurnYield | OpenBotEvent>;
42
+ mapError?: (error: unknown, args: AgentTurnArgs) => AgentTurnYield | AgentTurnYield[] | OpenBotEvent | undefined;
43
+ /** Extra bus handlers (webhooks, tools). Invoked after the standard subscriptions. */
44
+ setup?: PluginModule['factory'];
45
+ };
46
+ export declare function toAgentTurnEvents(item: AgentTurnYield | OpenBotEvent, agentId: string, threadId: string | undefined, meta?: AgentInvokeEvent['meta']): OpenBotEvent[];
47
+ /**
48
+ * Define an agent plugin with a standard invoke loop.
49
+ *
50
+ * Handles `shouldHandleInvoke`, thread id, empty prompts, and a default catch.
51
+ * `run` may return a string, or yield `{ kind: 'reply', content }` as each
52
+ * assistant turn completes (see `emitTextReplies`).
53
+ */
54
+ export declare function defineAgentPlugin(definition: AgentPluginDefinition): Promise<PluginModule>;
55
+ //# sourceMappingURL=agent-plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-plugin.d.ts","sourceRoot":"","sources":["../src/agent-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAChB,YAAY,EACZ,qBAAqB,EACtB,MAAM,aAAa,CAAC;AAIrB,OAAO,EAAgB,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAClF,OAAO,KAAK,EAAiB,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAElD,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC7C;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,kBAAkB,CAAA;CAAE,CAAC;AAEnD,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,KAAK,EAAE,gBAAgB,CAAC;IACxB,UAAU,EAAE,oBAAoB,CAAC;IACjC,OAAO,EAAE,aAAa,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,IAAI,GAAG,aAAa,CAAC,cAAc,GAAG,YAAY,CAAC,CAAC;AAE3F,MAAM,MAAM,uBAAuB,GAAG;IACpC,KAAK,EAAE,qBAAqB,CAAC;IAC7B,UAAU,EAAE,oBAAoB,CAAC;IACjC,OAAO,EAAE,aAAa,CAAC;CACxB,CAAC;AAEF,wDAAwD;AACxD,MAAM,MAAM,eAAe,GAAG;IAC5B,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC9E,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG,IAAI,CAAC,YAAY,EAAE,SAAS,CAAC,GAAG;IAClE,uFAAuF;IACvF,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,mFAAmF;IACnF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IACzE,gBAAgB,CAAC,EAAE,CACjB,IAAI,EAAE,uBAAuB,KAC1B,aAAa,CAAC,cAAc,GAAG,YAAY,CAAC,CAAC;IAClD,QAAQ,CAAC,EAAE,CACT,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,aAAa,KAChB,cAAc,GAAG,cAAc,EAAE,GAAG,YAAY,GAAG,SAAS,CAAC;IAClE,sFAAsF;IACtF,KAAK,CAAC,EAAE,YAAY,CAAC,SAAS,CAAC,CAAC;CACjC,CAAC;AAYF,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,cAAc,GAAG,YAAY,EACnC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,IAAI,CAAC,EAAE,gBAAgB,CAAC,MAAM,CAAC,GAC9B,YAAY,EAAE,CAQhB;AAiBD;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,UAAU,EAAE,qBAAqB,GAChC,OAAO,CAAC,YAAY,CAAC,CA+FvB"}
@@ -0,0 +1,118 @@
1
+ import { creditsErrorMessage } from './credits-auth.js';
2
+ import { agentOutput, shouldHandleInvoke, uiWidget, withMeta } from './helpers.js';
3
+ import { modelConfigField } from './model-registry.js';
4
+ import { definePlugin } from './plugin.js';
5
+ function isBusEvent(value) {
6
+ return 'type' in value && typeof value.type === 'string';
7
+ }
8
+ function isAsyncIterable(value) {
9
+ return !!value && typeof value === 'object' && Symbol.asyncIterator in value;
10
+ }
11
+ export function toAgentTurnEvents(item, agentId, threadId, meta) {
12
+ if (isBusEvent(item)) {
13
+ return [withMeta({ meta: { ...meta, agentId, ...(threadId ? { threadId } : {}) } }, item)];
14
+ }
15
+ if (item.kind === 'widget') {
16
+ return [uiWidget({ agentId, threadId, widget: item.widget, meta })];
17
+ }
18
+ return [agentOutput({ agentId, threadId, content: item.content, meta })];
19
+ }
20
+ async function* emitTurn(items, agentId, threadId, meta) {
21
+ for await (const item of items) {
22
+ yield* toAgentTurnEvents(item, agentId, threadId, meta);
23
+ }
24
+ }
25
+ function errorText(error) {
26
+ return error instanceof Error ? error.message : String(error);
27
+ }
28
+ /**
29
+ * Define an agent plugin with a standard invoke loop.
30
+ *
31
+ * Handles `shouldHandleInvoke`, thread id, empty prompts, and a default catch.
32
+ * `run` may return a string, or yield `{ kind: 'reply', content }` as each
33
+ * assistant turn completes (see `emitTextReplies`).
34
+ */
35
+ export async function defineAgentPlugin(definition) {
36
+ const { emptyPrompt, run, onWidgetResponse, mapError, setup, models, configSchema, ...plugin } = definition;
37
+ const properties = { ...(configSchema?.properties ?? {}) };
38
+ if (models?.providers.length) {
39
+ properties.model = await modelConfigField({
40
+ providers: models.providers,
41
+ defaultValue: models.default,
42
+ extraOptions: models.extraOptions,
43
+ override: true,
44
+ });
45
+ }
46
+ const schema = Object.keys(properties).length > 0
47
+ ? { type: 'object', properties, required: configSchema?.required }
48
+ : configSchema;
49
+ return definePlugin({
50
+ ...plugin,
51
+ ...(schema ? { configSchema: schema } : {}),
52
+ factory: (context) => (builder) => {
53
+ builder.on('agent:invoke', async function* (event, handlerCtx) {
54
+ if (!shouldHandleInvoke(event, context.agentId))
55
+ return;
56
+ if (event.meta?.threadId) {
57
+ handlerCtx.state.threadId = event.meta.threadId;
58
+ }
59
+ const threadId = event.meta?.threadId ?? handlerCtx.state.threadId;
60
+ const prompt = (event.data.content ?? '').trim();
61
+ if (!prompt) {
62
+ if (emptyPrompt) {
63
+ yield agentOutput({
64
+ agentId: context.agentId,
65
+ content: emptyPrompt,
66
+ threadId,
67
+ meta: event.meta,
68
+ });
69
+ }
70
+ return;
71
+ }
72
+ const args = { prompt, threadId, event, handlerCtx, context };
73
+ try {
74
+ const result = await run(args);
75
+ if (result == null || result === '')
76
+ return;
77
+ if (typeof result === 'string') {
78
+ yield agentOutput({
79
+ agentId: context.agentId,
80
+ content: result,
81
+ threadId,
82
+ meta: event.meta,
83
+ });
84
+ return;
85
+ }
86
+ if (isAsyncIterable(result)) {
87
+ yield* emitTurn(result, context.agentId, threadId, event.meta);
88
+ }
89
+ }
90
+ catch (error) {
91
+ const mapped = mapError?.(error, args);
92
+ if (mapped) {
93
+ const items = Array.isArray(mapped) ? mapped : [mapped];
94
+ for (const item of items) {
95
+ yield* toAgentTurnEvents(item, context.agentId, threadId, event.meta);
96
+ }
97
+ return;
98
+ }
99
+ const message = errorText(error);
100
+ yield agentOutput({
101
+ agentId: context.agentId,
102
+ content: creditsErrorMessage(message, { agentName: plugin.name }) ??
103
+ (message || 'Agent failed for an unknown reason. Please try again.'),
104
+ threadId,
105
+ meta: event.meta,
106
+ });
107
+ }
108
+ });
109
+ if (onWidgetResponse) {
110
+ builder.on('client:ui:widget:response', async function* (event, handlerCtx) {
111
+ yield* emitTurn(onWidgetResponse({ event, handlerCtx, context }), context.agentId, event.meta?.threadId ?? handlerCtx.state.threadId, event.meta);
112
+ });
113
+ }
114
+ setup?.(context)(builder);
115
+ },
116
+ });
117
+ }
118
+ //# sourceMappingURL=agent-plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-plugin.js","sourceRoot":"","sources":["../src/agent-plugin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { ConfigSchema } from './plugin.js';
2
+ /** How an agent authenticates to LLM providers. */
3
+ export type AuthMode = 'credits' | 'byok';
4
+ /** True when this runtime is a platform-managed cloud deployment. */
5
+ export declare const isCloudMode: () => boolean;
6
+ /** Default auth mode: Credits on cloud, BYOK locally. */
7
+ export declare const defaultAuthMode: () => AuthMode;
8
+ /** Read `authMode` from plugin config, falling back to the deployment default. */
9
+ export declare function resolveAuthMode(config: Record<string, unknown>): AuthMode;
10
+ /** `authMode` configSchema properties. Empty on self-hosted runtimes. */
11
+ export declare function cloudAuthModeProperties(options?: {
12
+ description?: string;
13
+ }): ConfigSchema['properties'];
14
+ //# sourceMappingURL=cloud-mode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloud-mode.d.ts","sourceRoot":"","sources":["../src/cloud-mode.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,mDAAmD;AACnD,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC;AAE1C,qEAAqE;AACrE,eAAO,MAAM,WAAW,QAAO,OAAiD,CAAC;AAEjF,yDAAyD;AACzD,eAAO,MAAM,eAAe,QAAO,QAAgD,CAAC;AAEpF,kFAAkF;AAClF,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,QAAQ,CAKzE;AAED,yEAAyE;AACzE,wBAAgB,uBAAuB,CAAC,OAAO,CAAC,EAAE;IAChD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,GAAG,YAAY,CAAC,YAAY,CAAC,CAY7B"}
@@ -0,0 +1,26 @@
1
+ /** True when this runtime is a platform-managed cloud deployment. */
2
+ export const isCloudMode = () => process.env.OPENBOT_CLOUD_MODE === '1';
3
+ /** Default auth mode: Credits on cloud, BYOK locally. */
4
+ export const defaultAuthMode = () => (isCloudMode() ? 'credits' : 'byok');
5
+ /** Read `authMode` from plugin config, falling back to the deployment default. */
6
+ export function resolveAuthMode(config) {
7
+ if (config.authMode === 'byok' || config.authMode === 'credits') {
8
+ return config.authMode;
9
+ }
10
+ return defaultAuthMode();
11
+ }
12
+ /** `authMode` configSchema properties. Empty on self-hosted runtimes. */
13
+ export function cloudAuthModeProperties(options) {
14
+ if (!isCloudMode())
15
+ return {};
16
+ return {
17
+ authMode: {
18
+ type: 'string',
19
+ description: options?.description ??
20
+ 'Credits — use your workspace credit balance via OpenBot. BYOK — bring your own API key.',
21
+ enum: ['credits', 'byok'],
22
+ default: 'credits',
23
+ },
24
+ };
25
+ }
26
+ //# sourceMappingURL=cloud-mode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloud-mode.js","sourceRoot":"","sources":["../src/cloud-mode.ts"],"names":[],"mappings":"AAKA,qEAAqE;AACrE,MAAM,CAAC,MAAM,WAAW,GAAG,GAAY,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,KAAK,GAAG,CAAC;AAEjF,yDAAyD;AACzD,MAAM,CAAC,MAAM,eAAe,GAAG,GAAa,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AAEpF,kFAAkF;AAClF,MAAM,UAAU,eAAe,CAAC,MAA+B;IAC7D,IAAI,MAAM,CAAC,QAAQ,KAAK,MAAM,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QAChE,OAAO,MAAM,CAAC,QAAQ,CAAC;IACzB,CAAC;IACD,OAAO,eAAe,EAAE,CAAC;AAC3B,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,uBAAuB,CAAC,OAEvC;IACC,IAAI,CAAC,WAAW,EAAE;QAAE,OAAO,EAAE,CAAC;IAC9B,OAAO;QACL,QAAQ,EAAE;YACR,IAAI,EAAE,QAAQ;YACd,WAAW,EACT,OAAO,EAAE,WAAW;gBACpB,yFAAyF;YAC3F,IAAI,EAAE,CAAC,SAAS,EAAE,MAAM,CAAC;YACzB,OAAO,EAAE,SAAS;SACnB;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,47 @@
1
+ import type { AuthMode } from './cloud-mode.js';
2
+ export declare const INTEGRATIONS_TOKEN_HEADER = "x-openbot-integrations-token";
3
+ export declare const CREDITS_API_KEY_PLACEHOLDER = "openbot-credits";
4
+ export type CreditsProviderId = 'openai' | 'anthropic' | 'google' | 'deepseek';
5
+ export interface CreditsAuthConfig {
6
+ baseUrl: string;
7
+ token: string;
8
+ }
9
+ /** Gateway path after the integrations base URL for each provider. */
10
+ export declare const CREDITS_PROVIDER_PATHS: Record<CreditsProviderId, string>;
11
+ /** Workspace/env keys treated as BYOK for each LLM provider. */
12
+ export declare const BYOK_ENV_KEYS: Record<CreditsProviderId, readonly string[]>;
13
+ export declare const CREDITS_NOT_CONFIGURED_MESSAGE = "OpenBot Credits is not configured on this runtime. The cloud host must set OPENBOT_INTEGRATIONS_BASE_URL and OPENBOT_INTEGRATIONS_TOKEN (try redeploying the workspace).";
14
+ /** First non-empty provider API key from `process.env` (workspace variables are merged in). */
15
+ export declare function resolveByokApiKey(provider?: CreditsProviderId | string, extraEnvKeys?: readonly string[]): string | undefined;
16
+ export declare function llmAuthNotConfiguredMessage(envVar?: string): string;
17
+ /** True when a BYOK key is set, or (cloud only) the credits gateway is injected. */
18
+ export declare function hasLlmAuth(provider?: CreditsProviderId | string, extraEnvKeys?: readonly string[]): boolean;
19
+ /** Cloud host injects these when routing LLM calls through OpenBot Credits. */
20
+ export declare function resolveCreditsAuthConfig(): CreditsAuthConfig | undefined;
21
+ export declare function creditsProviderBaseUrl(config: CreditsAuthConfig, provider?: CreditsProviderId | string, pathOverrides?: Record<string, string>): string;
22
+ export declare function shouldUseCreditsAuth(options?: {
23
+ authMode?: AuthMode;
24
+ provider?: string;
25
+ }): boolean;
26
+ export declare function isCreditsErrorMessage(message: string): boolean;
27
+ export declare function isAuthErrorMessage(message: string): boolean;
28
+ export declare function isIntegrationsProviderError(message: string): boolean;
29
+ export declare function creditsProviderUnavailableMessage(providerLabel?: string): string;
30
+ export declare function creditsAuthFailedMessage(agentName?: string): string;
31
+ export type OpenAiClientOptions = {
32
+ apiKey: string;
33
+ baseURL?: string;
34
+ headers?: Record<string, string>;
35
+ };
36
+ /**
37
+ * OpenAI-compatible client options.
38
+ * Local and BYOK use `OPENAI_API_KEY`; cloud without a key uses the credits gateway.
39
+ */
40
+ export declare function creditsOpenAiClientOptions(): OpenAiClientOptions | undefined;
41
+ /** Map a provider/credits failure to user-facing copy, or `undefined` if unrelated. */
42
+ export declare function creditsErrorMessage(message: string, options?: {
43
+ agentName?: string;
44
+ providerLabel?: string;
45
+ provider?: string;
46
+ }): string | undefined;
47
+ //# sourceMappingURL=credits-auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credits-auth.d.ts","sourceRoot":"","sources":["../src/credits-auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAEhD,eAAO,MAAM,yBAAyB,iCAAiC,CAAC;AACxE,eAAO,MAAM,2BAA2B,oBAAoB,CAAC;AAE7D,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,WAAW,GAAG,QAAQ,GAAG,UAAU,CAAC;AAE/E,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,sEAAsE;AACtE,eAAO,MAAM,sBAAsB,EAAE,MAAM,CAAC,iBAAiB,EAAE,MAAM,CAKpE,CAAC;AAEF,gEAAgE;AAChE,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,iBAAiB,EAAE,SAAS,MAAM,EAAE,CAKtE,CAAC;AAEF,eAAO,MAAM,8BAA8B,6KACiI,CAAC;AAe7K,+FAA+F;AAC/F,wBAAgB,iBAAiB,CAC/B,QAAQ,GAAE,iBAAiB,GAAG,MAAiB,EAC/C,YAAY,GAAE,SAAS,MAAM,EAAO,GACnC,MAAM,GAAG,SAAS,CAOpB;AAED,wBAAgB,2BAA2B,CAAC,MAAM,SAAmB,GAAG,MAAM,CAK7E;AAED,oFAAoF;AACpF,wBAAgB,UAAU,CACxB,QAAQ,GAAE,iBAAiB,GAAG,MAAiB,EAC/C,YAAY,GAAE,SAAS,MAAM,EAAO,GACnC,OAAO,CAIT;AAED,+EAA+E;AAC/E,wBAAgB,wBAAwB,IAAI,iBAAiB,GAAG,SAAS,CAKxE;AAED,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,iBAAiB,EACzB,QAAQ,GAAE,iBAAiB,GAAG,MAAiB,EAC/C,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACrC,MAAM,CAMR;AAED,wBAAgB,oBAAoB,CAAC,OAAO,CAAC,EAAE;IAC7C,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAMV;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAO9D;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAa3D;AAED,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAMpE;AAED,wBAAgB,iCAAiC,CAAC,aAAa,SAAuB,GAAG,MAAM,CAI9F;AAED,wBAAgB,wBAAwB,CAAC,SAAS,SAAe,GAAG,MAAM,CAIzE;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC,CAAC;AAEF;;;GAGG;AACH,wBAAgB,0BAA0B,IAAI,mBAAmB,GAAG,SAAS,CAY5E;AAED,uFAAuF;AACvF,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAC1E,MAAM,GAAG,SAAS,CAUpB"}
@@ -0,0 +1,139 @@
1
+ export const INTEGRATIONS_TOKEN_HEADER = 'x-openbot-integrations-token';
2
+ export const CREDITS_API_KEY_PLACEHOLDER = 'openbot-credits';
3
+ /** Gateway path after the integrations base URL for each provider. */
4
+ export const CREDITS_PROVIDER_PATHS = {
5
+ openai: 'openai/v1',
6
+ anthropic: 'anthropic/v1',
7
+ google: 'google/v1',
8
+ deepseek: 'deepseek/v1',
9
+ };
10
+ /** Workspace/env keys treated as BYOK for each LLM provider. */
11
+ export const BYOK_ENV_KEYS = {
12
+ openai: ['OPENAI_API_KEY'],
13
+ anthropic: ['ANTHROPIC_API_KEY'],
14
+ google: ['GOOGLE_GENERATIVE_AI_API_KEY', 'GEMINI_API_KEY'],
15
+ deepseek: ['DEEPSEEK_API_KEY'],
16
+ };
17
+ export const CREDITS_NOT_CONFIGURED_MESSAGE = 'OpenBot Credits is not configured on this runtime. The cloud host must set OPENBOT_INTEGRATIONS_BASE_URL and OPENBOT_INTEGRATIONS_TOKEN (try redeploying the workspace).';
18
+ const INSUFFICIENT_CREDITS_MESSAGE = 'Insufficient workspace credits. Add credits in workspace settings.';
19
+ function inCloudMode() {
20
+ return process.env.OPENBOT_CLOUD_MODE === '1';
21
+ }
22
+ function normalizeProvider(provider) {
23
+ if (provider === 'gemini')
24
+ return 'google';
25
+ if (provider in BYOK_ENV_KEYS)
26
+ return provider;
27
+ return undefined;
28
+ }
29
+ /** First non-empty provider API key from `process.env` (workspace variables are merged in). */
30
+ export function resolveByokApiKey(provider = 'openai', extraEnvKeys = []) {
31
+ const id = normalizeProvider(provider);
32
+ for (const key of [...(id ? BYOK_ENV_KEYS[id] : []), ...extraEnvKeys]) {
33
+ const value = process.env[key]?.trim();
34
+ if (value)
35
+ return value;
36
+ }
37
+ return undefined;
38
+ }
39
+ export function llmAuthNotConfiguredMessage(envVar = 'OPENAI_API_KEY') {
40
+ return (`Set \`${envVar}\` in workspace settings to use your own key, ` +
41
+ 'or configure OpenBot Credits on this runtime (OPENBOT_INTEGRATIONS_BASE_URL and OPENBOT_INTEGRATIONS_TOKEN).');
42
+ }
43
+ /** True when a BYOK key is set, or (cloud only) the credits gateway is injected. */
44
+ export function hasLlmAuth(provider = 'openai', extraEnvKeys = []) {
45
+ if (resolveByokApiKey(provider, extraEnvKeys))
46
+ return true;
47
+ if (!inCloudMode())
48
+ return false;
49
+ return resolveCreditsAuthConfig() !== undefined;
50
+ }
51
+ /** Cloud host injects these when routing LLM calls through OpenBot Credits. */
52
+ export function resolveCreditsAuthConfig() {
53
+ const baseUrl = process.env.OPENBOT_INTEGRATIONS_BASE_URL?.trim();
54
+ const token = process.env.OPENBOT_INTEGRATIONS_TOKEN?.trim();
55
+ if (!baseUrl || !token)
56
+ return undefined;
57
+ return { baseUrl: baseUrl.replace(/\/$/, ''), token };
58
+ }
59
+ export function creditsProviderBaseUrl(config, provider = 'openai', pathOverrides) {
60
+ const path = pathOverrides?.[provider] ?? CREDITS_PROVIDER_PATHS[provider];
61
+ if (!path) {
62
+ throw new Error(`Unsupported credits provider: ${provider}`);
63
+ }
64
+ return `${config.baseUrl}/${path}`;
65
+ }
66
+ export function shouldUseCreditsAuth(options) {
67
+ if (options?.authMode === 'byok')
68
+ return false;
69
+ if (options?.authMode === 'credits')
70
+ return true;
71
+ if (!inCloudMode())
72
+ return false;
73
+ if (resolveByokApiKey(options?.provider ?? 'openai'))
74
+ return false;
75
+ return resolveCreditsAuthConfig() !== undefined;
76
+ }
77
+ export function isCreditsErrorMessage(message) {
78
+ const lower = message.toLowerCase();
79
+ return (lower.includes('insufficient_credits') ||
80
+ lower.includes('insufficient credits') ||
81
+ lower.includes('402'));
82
+ }
83
+ export function isAuthErrorMessage(message) {
84
+ const lower = message.toLowerCase();
85
+ return (lower.includes('api key') ||
86
+ lower.includes('apikey') ||
87
+ lower.includes('api_key') ||
88
+ lower.includes('401') ||
89
+ lower.includes('unauthorized') ||
90
+ lower.includes('authentication') ||
91
+ lower.includes('not logged in') ||
92
+ lower.includes('login') ||
93
+ lower.includes('oauth'));
94
+ }
95
+ export function isIntegrationsProviderError(message) {
96
+ const lower = message.toLowerCase();
97
+ return (lower.includes('provider api key not configured') ||
98
+ (lower.includes('503') && lower.includes('provider')));
99
+ }
100
+ export function creditsProviderUnavailableMessage(providerLabel = 'the model provider') {
101
+ return (`OpenBot Credits could not reach ${providerLabel} — the platform provider API key is not configured yet. Try again later.`);
102
+ }
103
+ export function creditsAuthFailedMessage(agentName = 'This agent') {
104
+ return (`${agentName} could not authenticate via OpenBot Credits. Check your workspace credit balance in settings.`);
105
+ }
106
+ /**
107
+ * OpenAI-compatible client options.
108
+ * Local and BYOK use `OPENAI_API_KEY`; cloud without a key uses the credits gateway.
109
+ */
110
+ export function creditsOpenAiClientOptions() {
111
+ const byok = resolveByokApiKey('openai');
112
+ if (byok)
113
+ return { apiKey: byok };
114
+ if (!inCloudMode())
115
+ return undefined;
116
+ const config = resolveCreditsAuthConfig();
117
+ if (!config)
118
+ return undefined;
119
+ return {
120
+ baseURL: creditsProviderBaseUrl(config),
121
+ apiKey: config.token || CREDITS_API_KEY_PLACEHOLDER,
122
+ headers: { [INTEGRATIONS_TOKEN_HEADER]: config.token },
123
+ };
124
+ }
125
+ /** Map a provider/credits failure to user-facing copy, or `undefined` if unrelated. */
126
+ export function creditsErrorMessage(message, options) {
127
+ if (isIntegrationsProviderError(message)) {
128
+ return creditsProviderUnavailableMessage(options?.providerLabel);
129
+ }
130
+ if (isCreditsErrorMessage(message))
131
+ return INSUFFICIENT_CREDITS_MESSAGE;
132
+ if (isAuthErrorMessage(message)) {
133
+ if (!inCloudMode() || resolveByokApiKey(options?.provider ?? 'openai'))
134
+ return undefined;
135
+ return creditsAuthFailedMessage(options?.agentName);
136
+ }
137
+ return undefined;
138
+ }
139
+ //# sourceMappingURL=credits-auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credits-auth.js","sourceRoot":"","sources":["../src/credits-auth.ts"],"names":[],"mappings":"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"}