@meetopenbot/slack 0.0.1 → 0.0.2
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/README.md +4 -2
- package/dist/cloud-mode.js +10 -0
- package/dist/config.js +59 -10
- package/dist/credits-auth.js +53 -0
- package/dist/index.js +44 -35
- package/dist/model-registry.js +40 -0
- package/dist/model.js +24 -0
- package/dist/slack-agent.js +6 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -24,11 +24,13 @@ plugins:
|
|
|
24
24
|
signingSecret: your-signing-secret
|
|
25
25
|
botToken: xoxb-your-bot-token
|
|
26
26
|
teamId: T01234567
|
|
27
|
-
|
|
28
|
-
model: gpt-4o-mini
|
|
27
|
+
authMode: credits
|
|
28
|
+
model: openai/gpt-4o-mini
|
|
29
29
|
channelMappings: "C01234567:engineering,C89ABCDEF:support"
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
+
On cloud, `authMode: credits` uses your workspace credit balance. For BYOK (bring your own key), set `authMode: byok` and add `OPENAI_API_KEY` under workspace settings — no API key field in plugin config.
|
|
33
|
+
|
|
32
34
|
### Channel routing (webhook ingress)
|
|
33
35
|
|
|
34
36
|
When a Slack message arrives via the Events API webhook, the plugin delegates to the OpenBot **system** agent in a target channel. Set `channelMappings` as comma-separated `slackChannelId:openbotChannelId` pairs:
|
|
@@ -0,0 +1,10 @@
|
|
|
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
|
+
export function resolveAuthMode(config) {
|
|
6
|
+
if (config.authMode === "byok" || config.authMode === "credits") {
|
|
7
|
+
return config.authMode;
|
|
8
|
+
}
|
|
9
|
+
return defaultAuthMode();
|
|
10
|
+
}
|
package/dist/config.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { resolveAuthMode } from "./cloud-mode.js";
|
|
2
|
+
import { shouldUseCreditsAuth } from "./credits-auth.js";
|
|
1
3
|
export const DEFAULT_OPENBOT_CHANNEL_ID = "uncategorized";
|
|
2
4
|
/** Parse `C0123:engineering,C0456:support` into a lookup index. */
|
|
3
5
|
export function buildSlackChannelMappingIndex(config) {
|
|
@@ -30,13 +32,58 @@ export function resolveOpenBotChannelId(slackChannelId, config) {
|
|
|
30
32
|
const mapped = buildSlackChannelMappingIndex(config).get(normalized);
|
|
31
33
|
return mapped ?? DEFAULT_OPENBOT_CHANNEL_ID;
|
|
32
34
|
}
|
|
33
|
-
function
|
|
34
|
-
const
|
|
35
|
-
|
|
35
|
+
function variableValue(variables, key) {
|
|
36
|
+
const entry = variables[key];
|
|
37
|
+
if (typeof entry === "string")
|
|
38
|
+
return entry || undefined;
|
|
39
|
+
return entry?.value || undefined;
|
|
40
|
+
}
|
|
41
|
+
export function readSlackConfig(config) {
|
|
42
|
+
return {
|
|
43
|
+
signingSecret: typeof config.signingSecret === "string" && config.signingSecret.trim()
|
|
44
|
+
? config.signingSecret.trim()
|
|
45
|
+
: undefined,
|
|
46
|
+
botToken: typeof config.botToken === "string" && config.botToken.trim()
|
|
47
|
+
? config.botToken.trim()
|
|
48
|
+
: undefined,
|
|
49
|
+
teamId: typeof config.teamId === "string" && config.teamId.trim()
|
|
50
|
+
? config.teamId.trim()
|
|
51
|
+
: undefined,
|
|
52
|
+
channelMappings: typeof config.channelMappings === "string" &&
|
|
53
|
+
config.channelMappings.trim()
|
|
54
|
+
? config.channelMappings.trim()
|
|
55
|
+
: undefined,
|
|
56
|
+
authMode: resolveAuthMode(config),
|
|
57
|
+
model: typeof config.model === "string" && config.model.trim()
|
|
58
|
+
? config.model.trim()
|
|
59
|
+
: undefined,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
export function formatMissingCredentials(missing, authMode) {
|
|
63
|
+
const lines = [
|
|
64
|
+
"Slack agent setup is incomplete. Configure the following in plugin config, workspace settings, or environment variables:",
|
|
65
|
+
];
|
|
66
|
+
if (missing.includes("botToken")) {
|
|
67
|
+
lines.push("- `botToken` / `SLACK_BOT_TOKEN` — Slack bot OAuth token (`xoxb-…`)");
|
|
68
|
+
}
|
|
69
|
+
if (missing.includes("teamId")) {
|
|
70
|
+
lines.push("- `teamId` / `SLACK_TEAM_ID` — workspace team id (`T…`)");
|
|
71
|
+
}
|
|
72
|
+
if (missing.includes("openaiApiKey")) {
|
|
73
|
+
if (authMode === "credits") {
|
|
74
|
+
lines.push("- OpenAI API key is required in BYOK mode — add `OPENAI_API_KEY` under workspace settings, or switch `authMode` to `credits` on cloud");
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
lines.push("- `OPENAI_API_KEY` — OpenAI API key for the agent loop (BYOK mode), or switch `authMode` to `credits` on cloud");
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return lines.join("\n");
|
|
36
81
|
}
|
|
37
82
|
export async function resolveSlackCredentials(config, storage, options) {
|
|
38
|
-
const
|
|
39
|
-
const
|
|
83
|
+
const authMode = config.authMode ?? resolveAuthMode({});
|
|
84
|
+
const useCredits = shouldUseCreditsAuth({ authMode });
|
|
85
|
+
const requireOpenAi = options?.requireOpenAi ?? !useCredits;
|
|
86
|
+
const variables = (await storage.getVariables().catch(() => ({})));
|
|
40
87
|
const resolve = (configKey, envKey) => {
|
|
41
88
|
const fromConfig = config[configKey];
|
|
42
89
|
if (typeof fromConfig === "string" && fromConfig.trim()) {
|
|
@@ -44,16 +91,17 @@ export async function resolveSlackCredentials(config, storage, options) {
|
|
|
44
91
|
}
|
|
45
92
|
if (process.env[envKey]?.trim())
|
|
46
93
|
return process.env[envKey].trim();
|
|
47
|
-
return
|
|
94
|
+
return variableValue(variables, envKey)?.trim();
|
|
48
95
|
};
|
|
49
96
|
const signingSecret = (typeof config.signingSecret === "string" && config.signingSecret.trim()) ||
|
|
50
97
|
process.env.SLACK_SIGNING_SECRET?.trim() ||
|
|
51
|
-
|
|
98
|
+
variableValue(variables, "SLACK_SIGNING_SECRET") ||
|
|
52
99
|
"";
|
|
53
100
|
const botToken = resolve("botToken", "SLACK_BOT_TOKEN");
|
|
54
101
|
const teamId = resolve("teamId", "SLACK_TEAM_ID");
|
|
55
|
-
const openaiApiKey =
|
|
56
|
-
|
|
102
|
+
const openaiApiKey = process.env.OPENAI_API_KEY?.trim() ||
|
|
103
|
+
variableValue(variables, "OPENAI_API_KEY");
|
|
104
|
+
const model = resolve("model", "OPENAI_MODEL") ?? "openai/gpt-4o-mini";
|
|
57
105
|
const missing = [];
|
|
58
106
|
if (!botToken)
|
|
59
107
|
missing.push("botToken");
|
|
@@ -70,7 +118,8 @@ export async function resolveSlackCredentials(config, storage, options) {
|
|
|
70
118
|
signingSecret,
|
|
71
119
|
botToken: botToken,
|
|
72
120
|
teamId: teamId,
|
|
73
|
-
|
|
121
|
+
authMode,
|
|
122
|
+
openaiApiKey: openaiApiKey || undefined,
|
|
74
123
|
model,
|
|
75
124
|
},
|
|
76
125
|
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { isCloudMode } from "./cloud-mode.js";
|
|
2
|
+
export const INTEGRATIONS_TOKEN_HEADER = "x-openbot-integrations-token";
|
|
3
|
+
export const CREDITS_API_KEY_PLACEHOLDER = "openbot-credits";
|
|
4
|
+
/** Cloud host injects these when routing LLM calls through OpenBot Credits. */
|
|
5
|
+
export function resolveCreditsAuthConfig() {
|
|
6
|
+
const baseUrl = process.env.OPENBOT_INTEGRATIONS_BASE_URL?.trim();
|
|
7
|
+
const token = process.env.OPENBOT_INTEGRATIONS_TOKEN?.trim();
|
|
8
|
+
if (!baseUrl || !token)
|
|
9
|
+
return undefined;
|
|
10
|
+
return { baseUrl: baseUrl.replace(/\/$/, ""), token };
|
|
11
|
+
}
|
|
12
|
+
export function creditsProviderBaseUrl(config) {
|
|
13
|
+
return `${config.baseUrl}/openai/v1`;
|
|
14
|
+
}
|
|
15
|
+
export function shouldUseCreditsAuth(options) {
|
|
16
|
+
if (options?.authMode === "byok")
|
|
17
|
+
return false;
|
|
18
|
+
if (options?.authMode === "credits")
|
|
19
|
+
return true;
|
|
20
|
+
return isCloudMode() && resolveCreditsAuthConfig() !== undefined;
|
|
21
|
+
}
|
|
22
|
+
export function isCreditsErrorMessage(message) {
|
|
23
|
+
const lower = message.toLowerCase();
|
|
24
|
+
return (lower.includes("insufficient_credits") ||
|
|
25
|
+
lower.includes("insufficient credits") ||
|
|
26
|
+
lower.includes("402"));
|
|
27
|
+
}
|
|
28
|
+
export function isAuthErrorMessage(message) {
|
|
29
|
+
const lower = message.toLowerCase();
|
|
30
|
+
return (lower.includes("api key") ||
|
|
31
|
+
lower.includes("401") ||
|
|
32
|
+
lower.includes("unauthorized") ||
|
|
33
|
+
lower.includes("authentication"));
|
|
34
|
+
}
|
|
35
|
+
export function isIntegrationsProviderError(message) {
|
|
36
|
+
const lower = message.toLowerCase();
|
|
37
|
+
return (lower.includes("provider api key not configured") ||
|
|
38
|
+
(lower.includes("503") && lower.includes("provider")));
|
|
39
|
+
}
|
|
40
|
+
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).";
|
|
41
|
+
export const CREDITS_PROVIDER_UNAVAILABLE_MESSAGE = "OpenBot Credits could not reach OpenAI — the platform provider API key is not configured yet. Try again later or switch this agent to BYOK mode.";
|
|
42
|
+
export const CREDITS_AUTH_FAILED_MESSAGE = "Slack could not authenticate via OpenBot Credits. Check your workspace credit balance in settings, or switch this agent to BYOK mode.";
|
|
43
|
+
export function creditsErrorMessage(message) {
|
|
44
|
+
if (isIntegrationsProviderError(message)) {
|
|
45
|
+
return CREDITS_PROVIDER_UNAVAILABLE_MESSAGE;
|
|
46
|
+
}
|
|
47
|
+
if (isCreditsErrorMessage(message)) {
|
|
48
|
+
return "Insufficient workspace credits. Add credits in workspace settings or switch this agent to BYOK mode.";
|
|
49
|
+
}
|
|
50
|
+
if (isAuthErrorMessage(message))
|
|
51
|
+
return CREDITS_AUTH_FAILED_MESSAGE;
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { agentOutput, definePlugin, decodeWebhookRawBody, getWebhookHeader, shouldHandleInvoke, webhookHttpResponse, } from "@meetopenbot/plugin-sdk";
|
|
3
|
-
import {
|
|
3
|
+
import { isCloudMode } from "./cloud-mode.js";
|
|
4
|
+
import { CREDITS_NOT_CONFIGURED_MESSAGE, creditsErrorMessage, resolveCreditsAuthConfig, } from "./credits-auth.js";
|
|
5
|
+
import { DEFAULT_OPENBOT_CHANNEL_ID, formatMissingCredentials, readSlackConfig, resolveOpenBotChannelId, resolveSlackCredentials, } from "./config.js";
|
|
6
|
+
import { resolveModelConfigField } from "./model-registry.js";
|
|
4
7
|
import { postSlackMessage } from "./slack-post.js";
|
|
5
8
|
import { runSlackAgent } from "./slack-agent.js";
|
|
6
9
|
import { verifySlackSignature } from "./slack-verify.js";
|
|
@@ -51,21 +54,6 @@ function getSlackThreadMeta(meta) {
|
|
|
51
54
|
return undefined;
|
|
52
55
|
return slack;
|
|
53
56
|
}
|
|
54
|
-
function formatMissingCredentials(missing) {
|
|
55
|
-
const lines = [
|
|
56
|
-
"Slack agent setup is incomplete. Configure the following in plugin config or environment variables:",
|
|
57
|
-
];
|
|
58
|
-
if (missing.includes("botToken")) {
|
|
59
|
-
lines.push("- `botToken` / `SLACK_BOT_TOKEN` — Slack bot OAuth token (`xoxb-…`)");
|
|
60
|
-
}
|
|
61
|
-
if (missing.includes("teamId")) {
|
|
62
|
-
lines.push("- `teamId` / `SLACK_TEAM_ID` — workspace team id (`T…`)");
|
|
63
|
-
}
|
|
64
|
-
if (missing.includes("openaiApiKey")) {
|
|
65
|
-
lines.push("- `openaiApiKey` / `OPENAI_API_KEY` — OpenAI API key for the agent loop");
|
|
66
|
-
}
|
|
67
|
-
return lines.join("\n");
|
|
68
|
-
}
|
|
69
57
|
async function* bridgeSystemAgentRun(args) {
|
|
70
58
|
const runId = `slack_${randomUUID()}`;
|
|
71
59
|
const slackMeta = getSlackThreadMeta(args.meta);
|
|
@@ -146,36 +134,41 @@ async function* bridgeSystemAgentRun(args) {
|
|
|
146
134
|
}
|
|
147
135
|
await runPromise;
|
|
148
136
|
}
|
|
137
|
+
const modelField = await resolveModelConfigField();
|
|
149
138
|
const slackPluginConfigSchema = {
|
|
150
139
|
type: "object",
|
|
151
140
|
properties: {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
141
|
+
...(isCloudMode()
|
|
142
|
+
? {
|
|
143
|
+
authMode: {
|
|
144
|
+
type: "string",
|
|
145
|
+
description: "Outbound — Credits uses your workspace credit balance via OpenBot. BYOK uses `OPENAI_API_KEY` from workspace settings.",
|
|
146
|
+
enum: ["credits", "byok"],
|
|
147
|
+
default: "credits",
|
|
148
|
+
},
|
|
149
|
+
}
|
|
150
|
+
: {}),
|
|
151
|
+
model: {
|
|
152
|
+
...modelField,
|
|
153
|
+
description: "Outbound — OpenAI model for direct Slack agent invocations",
|
|
156
154
|
},
|
|
157
155
|
botToken: {
|
|
158
156
|
type: "string",
|
|
159
|
-
description: "Slack bot token (OAuth & Permissions → Bot User OAuth Token)",
|
|
157
|
+
description: "Outbound — Slack bot token (OAuth & Permissions → Bot User OAuth Token)",
|
|
160
158
|
format: "password",
|
|
161
159
|
},
|
|
162
160
|
teamId: {
|
|
163
161
|
type: "string",
|
|
164
|
-
description: "Slack workspace team id (starts with T)",
|
|
165
|
-
},
|
|
166
|
-
channelMappings: {
|
|
167
|
-
type: "string",
|
|
168
|
-
description: "Webhook ingress routing. Comma-separated slackChannelId:openbotChannelId pairs (e.g. C01234567:engineering,C89ABCDEF:support). Unmapped Slack channels use uncategorized.",
|
|
162
|
+
description: "Outbound — Slack workspace team id (starts with T)",
|
|
169
163
|
},
|
|
170
|
-
|
|
164
|
+
signingSecret: {
|
|
171
165
|
type: "string",
|
|
172
|
-
description: "
|
|
166
|
+
description: "Inbound — Slack app signing secret (Basic Information → App Credentials)",
|
|
173
167
|
format: "password",
|
|
174
168
|
},
|
|
175
|
-
|
|
169
|
+
channelMappings: {
|
|
176
170
|
type: "string",
|
|
177
|
-
description: "
|
|
178
|
-
default: "gpt-4o-mini",
|
|
171
|
+
description: "Inbound — webhook routing. Comma-separated slackChannelId:openbotChannelId pairs (e.g. C01234567:engineering,C89ABCDEF:support). Unmapped Slack channels use uncategorized.",
|
|
179
172
|
},
|
|
180
173
|
},
|
|
181
174
|
required: ["signingSecret"],
|
|
@@ -186,7 +179,7 @@ export default definePlugin({
|
|
|
186
179
|
configSchema: slackPluginConfigSchema,
|
|
187
180
|
factory: (pluginContext) => (builder) => {
|
|
188
181
|
const { agentId, config, storage } = pluginContext;
|
|
189
|
-
const slackConfig = config;
|
|
182
|
+
const slackConfig = readSlackConfig(config);
|
|
190
183
|
const host = pluginContext.host;
|
|
191
184
|
const publicBaseUrl = pluginContext.publicBaseUrl ?? "";
|
|
192
185
|
builder.on("action:webhook", async function* (event, ctx) {
|
|
@@ -301,7 +294,9 @@ export default definePlugin({
|
|
|
301
294
|
if (!auth.ok) {
|
|
302
295
|
yield {
|
|
303
296
|
type: "agent:output",
|
|
304
|
-
data: {
|
|
297
|
+
data: {
|
|
298
|
+
content: formatMissingCredentials(auth.missing, slackConfig.authMode),
|
|
299
|
+
},
|
|
305
300
|
meta: {
|
|
306
301
|
agentId: ROUTING_AGENT_ID,
|
|
307
302
|
threadId,
|
|
@@ -361,7 +356,17 @@ export default definePlugin({
|
|
|
361
356
|
if (!auth.ok) {
|
|
362
357
|
yield agentOutput({
|
|
363
358
|
agentId,
|
|
364
|
-
content: formatMissingCredentials(auth.missing),
|
|
359
|
+
content: formatMissingCredentials(auth.missing, slackConfig.authMode),
|
|
360
|
+
threadId,
|
|
361
|
+
meta: event.meta,
|
|
362
|
+
});
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
if (auth.credentials.authMode === "credits" &&
|
|
366
|
+
!resolveCreditsAuthConfig()) {
|
|
367
|
+
yield agentOutput({
|
|
368
|
+
agentId,
|
|
369
|
+
content: CREDITS_NOT_CONFIGURED_MESSAGE,
|
|
365
370
|
threadId,
|
|
366
371
|
meta: event.meta,
|
|
367
372
|
});
|
|
@@ -370,6 +375,7 @@ export default definePlugin({
|
|
|
370
375
|
try {
|
|
371
376
|
const reply = await runSlackAgent({
|
|
372
377
|
prompt: userMessage,
|
|
378
|
+
authMode: auth.credentials.authMode,
|
|
373
379
|
openaiApiKey: auth.credentials.openaiApiKey,
|
|
374
380
|
botToken: auth.credentials.botToken,
|
|
375
381
|
teamId: auth.credentials.teamId,
|
|
@@ -384,9 +390,12 @@ export default definePlugin({
|
|
|
384
390
|
}
|
|
385
391
|
catch (error) {
|
|
386
392
|
const message = error instanceof Error ? error.message : String(error);
|
|
393
|
+
const creditsMessage = auth.credentials.authMode === "credits"
|
|
394
|
+
? creditsErrorMessage(message)
|
|
395
|
+
: undefined;
|
|
387
396
|
yield agentOutput({
|
|
388
397
|
agentId,
|
|
389
|
-
content: `Slack agent error: ${message}`,
|
|
398
|
+
content: creditsMessage ?? `Slack agent error: ${message}`,
|
|
390
399
|
threadId,
|
|
391
400
|
meta: event.meta,
|
|
392
401
|
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
const REGISTRY_URL = "https://raw.githubusercontent.com/meetopenbot/openbot-registry/main/registry.json";
|
|
2
|
+
const OPENAI_PROVIDER = "openai";
|
|
3
|
+
const freeInputModelField = () => ({
|
|
4
|
+
type: "string",
|
|
5
|
+
override: true,
|
|
6
|
+
description: "OpenAI model in provider/model-id format (e.g. openai/gpt-4o-mini).",
|
|
7
|
+
default: "openai/gpt-4o-mini",
|
|
8
|
+
});
|
|
9
|
+
/** Registry-backed model field for plugin configSchema (`enum` + labeled `options`). */
|
|
10
|
+
export async function resolveModelConfigField() {
|
|
11
|
+
try {
|
|
12
|
+
const res = await fetch(REGISTRY_URL, {
|
|
13
|
+
headers: { Accept: "application/json" },
|
|
14
|
+
signal: AbortSignal.timeout(15_000),
|
|
15
|
+
});
|
|
16
|
+
if (!res.ok)
|
|
17
|
+
return freeInputModelField();
|
|
18
|
+
const registry = (await res.json());
|
|
19
|
+
const provider = registry.providers?.[OPENAI_PROVIDER];
|
|
20
|
+
const models = provider?.models ?? [];
|
|
21
|
+
if (models.length === 0)
|
|
22
|
+
return freeInputModelField();
|
|
23
|
+
const defaultModel = models.find((model) => model.id === "gpt-4o-mini")?.id ?? models[0].id;
|
|
24
|
+
return {
|
|
25
|
+
type: "string",
|
|
26
|
+
override: true,
|
|
27
|
+
description: "OpenAI model from the OpenBot registry.",
|
|
28
|
+
default: `${OPENAI_PROVIDER}/${defaultModel}`,
|
|
29
|
+
enum: models.map((model) => `${OPENAI_PROVIDER}/${model.id}`),
|
|
30
|
+
options: models.map((model) => ({
|
|
31
|
+
label: `${provider?.label ?? "OpenAI"} — ${model.label}`,
|
|
32
|
+
value: `${OPENAI_PROVIDER}/${model.id}`,
|
|
33
|
+
description: model.description,
|
|
34
|
+
})),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return freeInputModelField();
|
|
39
|
+
}
|
|
40
|
+
}
|
package/dist/model.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { createOpenAI } from "@ai-sdk/openai";
|
|
2
|
+
import { CREDITS_API_KEY_PLACEHOLDER, INTEGRATIONS_TOKEN_HEADER, creditsProviderBaseUrl, resolveCreditsAuthConfig, shouldUseCreditsAuth, } from "./credits-auth.js";
|
|
3
|
+
function normalizeOpenAiModelId(model) {
|
|
4
|
+
return model.includes("/") ? model.split("/").slice(1).join("/") : model;
|
|
5
|
+
}
|
|
6
|
+
export function resolveOpenAiModel(model, options) {
|
|
7
|
+
const modelId = normalizeOpenAiModelId(model);
|
|
8
|
+
const useCredits = shouldUseCreditsAuth(options);
|
|
9
|
+
if (useCredits) {
|
|
10
|
+
const config = resolveCreditsAuthConfig();
|
|
11
|
+
if (!config) {
|
|
12
|
+
throw new Error("OpenBot Credits is not configured. The cloud host must set OPENBOT_INTEGRATIONS_BASE_URL and OPENBOT_INTEGRATIONS_TOKEN.");
|
|
13
|
+
}
|
|
14
|
+
const baseURL = creditsProviderBaseUrl(config);
|
|
15
|
+
const headers = { [INTEGRATIONS_TOKEN_HEADER]: config.token };
|
|
16
|
+
const apiKey = config.token || CREDITS_API_KEY_PLACEHOLDER;
|
|
17
|
+
return createOpenAI({ baseURL, apiKey, headers })(modelId);
|
|
18
|
+
}
|
|
19
|
+
const apiKey = options?.openaiApiKey?.trim();
|
|
20
|
+
if (!apiKey) {
|
|
21
|
+
throw new Error("OpenAI API key is required in BYOK mode. Add `OPENAI_API_KEY` under workspace settings or switch `authMode` to `credits` on cloud.");
|
|
22
|
+
}
|
|
23
|
+
return createOpenAI({ apiKey })(modelId);
|
|
24
|
+
}
|
package/dist/slack-agent.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import { createOpenAI } from "@ai-sdk/openai";
|
|
2
1
|
import { generateText, stepCountIs } from "ai";
|
|
2
|
+
import { resolveOpenAiModel } from "./model.js";
|
|
3
3
|
import { createSlackMcpClient } from "./slack-mcp.js";
|
|
4
4
|
const SYSTEM_PROMPT = `You are the OpenBot Slack specialist agent.
|
|
5
5
|
Use Slack MCP tools to post messages, list channels, read history, and perform other workspace actions when needed.
|
|
6
6
|
Summarize results clearly in plain text for the user. Be concise and friendly.`;
|
|
7
7
|
export async function runSlackAgent(args) {
|
|
8
|
-
const
|
|
8
|
+
const model = resolveOpenAiModel(args.model ?? "openai/gpt-4o-mini", {
|
|
9
|
+
authMode: args.authMode,
|
|
10
|
+
openaiApiKey: args.openaiApiKey,
|
|
11
|
+
});
|
|
9
12
|
const mcpClient = await createSlackMcpClient({
|
|
10
13
|
botToken: args.botToken,
|
|
11
14
|
teamId: args.teamId,
|
|
@@ -13,7 +16,7 @@ export async function runSlackAgent(args) {
|
|
|
13
16
|
try {
|
|
14
17
|
const tools = await mcpClient.tools();
|
|
15
18
|
const result = await generateText({
|
|
16
|
-
model
|
|
19
|
+
model,
|
|
17
20
|
system: SYSTEM_PROMPT,
|
|
18
21
|
prompt: args.prompt,
|
|
19
22
|
tools,
|