loopengine 0.1.95 → 0.1.97
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 +21 -2
- package/dist/bin/ability-manager.d.ts +4 -0
- package/dist/bin/ability-manager.js +34 -2
- package/dist/bin/cli.d.ts +1 -1
- package/dist/bin/cli.js +3 -0
- package/dist/core/ability-details.d.ts +31 -0
- package/dist/core/ability-details.js +140 -0
- package/dist/core/ability-sources.d.ts +59 -0
- package/dist/core/ability-sources.js +312 -0
- package/dist/core/agent-config.d.ts +21 -1
- package/dist/core/discover-agents.js +11 -1
- package/dist/core/http-notifier.d.ts +7 -1
- package/dist/core/http-notifier.js +68 -9
- package/dist/core/http-notify-triggers/email.d.ts +2 -2
- package/dist/core/http-notify-triggers/email.js +2 -4
- package/dist/core/http-notify-triggers/lark.d.ts +2 -2
- package/dist/core/http-notify-triggers/lark.js +2 -4
- package/dist/core/http-notify-triggers/slack.d.ts +2 -2
- package/dist/core/http-notify-triggers/slack.js +2 -4
- package/dist/core/http-notify-triggers/telegram.d.ts +28 -0
- package/dist/core/http-notify-triggers/telegram.js +71 -0
- package/dist/core/http-notify-triggers/webhook.d.ts +2 -2
- package/dist/core/http-notify-triggers/webhook.js +2 -4
- package/dist/core/model-calls/meta-model-call.d.ts +15 -0
- package/dist/core/model-calls/meta-model-call.js +48 -0
- package/dist/core/model-calls/openai-model-call.d.ts +5 -0
- package/dist/core/model-calls/openai-model-call.js +47 -1
- package/dist/core/model-calls/xai-model-call.d.ts +15 -0
- package/dist/core/model-calls/xai-model-call.js +45 -0
- package/dist/core/notifier-file.d.ts +40 -6
- package/dist/core/notifier-file.js +119 -25
- package/dist/core/system-agents/workflow-planner.d.ts +100 -0
- package/dist/core/system-agents/workflow-planner.js +278 -0
- package/dist/core/workflows.d.ts +26 -0
- package/dist/core/workflows.js +39 -0
- package/dist/core/workspace-abilities.d.ts +31 -0
- package/dist/core/workspace-abilities.js +110 -0
- package/dist/index.d.ts +18 -4
- package/dist/index.js +17 -3
- package/dist/web/ability-details-admin.d.ts +17 -0
- package/dist/web/ability-details-admin.js +45 -0
- package/dist/web/ability-sources-admin.d.ts +33 -0
- package/dist/web/ability-sources-admin.js +65 -0
- package/dist/web/agent-file-admin.d.ts +1 -1
- package/dist/web/agent-file-admin.js +3 -0
- package/dist/web/agents-config-page.js +600 -220
- package/dist/web/agents-list-page.js +49 -20
- package/dist/web/console-shell.js +244 -3
- package/dist/web/dev-ui-styles.js +12 -0
- package/dist/web/global-config-page.js +348 -95
- package/dist/web/global-config.d.ts +44 -1
- package/dist/web/global-config.js +162 -2
- package/dist/web/interview-admin.js +2 -2
- package/dist/web/messaging-icons.d.ts +2 -0
- package/dist/web/messaging-icons.js +7 -0
- package/dist/web/notifier-admin.d.ts +33 -15
- package/dist/web/notifier-admin.js +109 -65
- package/dist/web/provider-icons.d.ts +2 -0
- package/dist/web/provider-icons.js +10 -0
- package/dist/web/templates-admin.d.ts +3 -0
- package/dist/web/templates-admin.js +5 -1
- package/dist/web/workflow-admin.d.ts +124 -0
- package/dist/web/workflow-admin.js +308 -0
- package/dist/web/workflow-page.d.ts +1 -0
- package/dist/web/workflow-page.js +226 -0
- package/dist/web/workspace-abilities-admin.d.ts +24 -0
- package/dist/web/workspace-abilities-admin.js +118 -0
- package/package.json +13 -1
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
// Backs the global /config page's Models and Gateways sections (see
|
|
2
|
+
// web/agents-config-page.ts's left sidebar) — the account-wide,
|
|
3
|
+
// not-scoped-to-one-agent counterpart to that page's existing per-agent
|
|
4
|
+
// Overview/Skills/Tools/ActAuth tabs. "Global" here means: which model
|
|
5
|
+
// providers this deployment can actually call (an API-key-in-env-vars
|
|
6
|
+
// question, same everywhere regardless of which agent is running) and
|
|
7
|
+
// which gateway providers (Composio today) this machine's CLI session
|
|
8
|
+
// is authenticated against — neither is a property of any one
|
|
9
|
+
// AgentConfig.
|
|
10
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
11
|
+
import { resolve } from 'node:path';
|
|
12
|
+
import Anthropic from '@anthropic-ai/sdk';
|
|
13
|
+
import OpenAI from 'openai';
|
|
14
|
+
import { parse as parseYaml } from 'yaml';
|
|
1
15
|
import { getComposioAuthStatus } from '../core/gateway-tools.js';
|
|
2
16
|
import { moveScheduledTasksToTimeZone } from '../core/scheduler.js';
|
|
3
17
|
import { TIME_ZONE_ENV, isValidTimeZone, listTimeZones, serverTimeZone, workspaceTimeZone } from '../core/time-zone.js';
|
|
@@ -10,14 +24,17 @@ export class ModelKeyError extends Error {
|
|
|
10
24
|
// union from; adding a fourth provider means one more line here and one
|
|
11
25
|
// more arm in that union, not a rewrite.
|
|
12
26
|
const KNOWN_PROVIDERS = [
|
|
13
|
-
{ provider: 'anthropic', envVar: 'ANTHROPIC_API_KEY' },
|
|
14
27
|
{ provider: 'openai', envVar: 'OPENAI_API_KEY' },
|
|
28
|
+
{ provider: 'anthropic', envVar: 'ANTHROPIC_API_KEY' },
|
|
29
|
+
{ provider: 'gemini', envVar: 'GEMINI_API_KEY' },
|
|
30
|
+
// LiteLLM's name; see core/model-calls/meta-model-call.ts.
|
|
31
|
+
{ provider: 'meta', envVar: 'META_API_KEY' },
|
|
32
|
+
{ provider: 'xai', envVar: 'XAI_API_KEY' },
|
|
15
33
|
{ provider: 'deepseek', envVar: 'DEEPSEEK_API_KEY' },
|
|
16
34
|
// Moonshot AI's own env var name, not KIMI_API_KEY — see
|
|
17
35
|
// core/model-calls/kimi-model-call.ts's own header comment for why.
|
|
18
36
|
{ provider: 'kimi', envVar: 'MOONSHOT_API_KEY' },
|
|
19
37
|
{ provider: 'glm', envVar: 'GLM_API_KEY' },
|
|
20
|
-
{ provider: 'gemini', envVar: 'GEMINI_API_KEY' },
|
|
21
38
|
];
|
|
22
39
|
/** Every registered agent's resolved model, alongside whether each
|
|
23
40
|
* supported provider actually has credentials available in this
|
|
@@ -104,6 +121,149 @@ export async function clearModelProviderKey(provider) {
|
|
|
104
121
|
throw new ModelKeyError(`unknown provider '${provider}'`);
|
|
105
122
|
await unsetEnvVar(envVar);
|
|
106
123
|
}
|
|
124
|
+
// The OpenAI-compatible providers' base URLs, the same ones their
|
|
125
|
+
// model-calls/*.ts use (OpenAI's own comes from the SDK, so
|
|
126
|
+
// OPENAI_BASE_URL applies to both). Anthropic has its own models API.
|
|
127
|
+
const OPENAI_COMPATIBLE_BASE_URLS = {
|
|
128
|
+
deepseek: 'https://api.deepseek.com',
|
|
129
|
+
kimi: 'https://api.moonshot.ai/v1',
|
|
130
|
+
glm: 'https://open.bigmodel.cn/api/paas/v4/',
|
|
131
|
+
gemini: 'https://generativelanguage.googleapis.com/v1beta/openai/',
|
|
132
|
+
xai: 'https://api.x.ai/v1',
|
|
133
|
+
meta: 'https://api.meta.ai/v1',
|
|
134
|
+
};
|
|
135
|
+
// OpenAI and Gemini also list models a chat agent can't use.
|
|
136
|
+
const NON_CHAT_MODEL = /embed|tts|whisper|dall-e|davinci|babbage|moderation|transcribe|image|audio|realtime|search|aqa|imagen|veo|sora/i;
|
|
137
|
+
// Offered when the provider's own list isn't available (no key saved
|
|
138
|
+
// yet, or the provider refused) and models.yaml doesn't list it. Only
|
|
139
|
+
// names checked against the provider's docs (2026-10-31); other
|
|
140
|
+
// providers need a key to list theirs. Meta's "-contributor" variants are
|
|
141
|
+
// left out, since choosing one lets Meta train on the requests; type one
|
|
142
|
+
// under "Other" to use it.
|
|
143
|
+
const KNOWN_MODELS = {
|
|
144
|
+
anthropic: ['claude-fable-5-1', 'claude-opus-5-5', 'claude-sonnet-5-5', 'claude-haiku-5-5', 'claude-sonnet-5'],
|
|
145
|
+
deepseek: ['deepseek-v4-pro', 'deepseek-flash'],
|
|
146
|
+
meta: ['muse-spark-1.3', 'muse-wonder-1.0', 'muse-spark-1.2', 'muse-spark-1.1'],
|
|
147
|
+
};
|
|
148
|
+
const MODEL_LIST_TTL_MS = 10 * 60 * 1000;
|
|
149
|
+
const modelListCache = new Map();
|
|
150
|
+
export const MODELS_FILE_ENV = 'LOOPENGINE_MODELS_FILE';
|
|
151
|
+
/** models.yaml in the project root (where .env is), or the file
|
|
152
|
+
* LOOPENGINE_MODELS_FILE names (absolute, or relative to the root). */
|
|
153
|
+
export function modelsFilePath() {
|
|
154
|
+
return resolve(process.cwd(), process.env[MODELS_FILE_ENV]?.trim() || 'models.yaml');
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* The hand-edited model lists in models.yaml: provider name to the models
|
|
158
|
+
* its dropdown offers, in order.
|
|
159
|
+
*
|
|
160
|
+
* anthropic:
|
|
161
|
+
* - claude-opus-5-5
|
|
162
|
+
* - claude-sonnet-5-5
|
|
163
|
+
*
|
|
164
|
+
* Read fresh on every call (it's a few lines), so an edit shows the next
|
|
165
|
+
* time a dropdown loads. A missing file is no lists; a malformed one is
|
|
166
|
+
* reported in `error` and ignored as a whole, so a typo can't hide one
|
|
167
|
+
* provider's models while the rest still load.
|
|
168
|
+
*/
|
|
169
|
+
export function readModelsFile() {
|
|
170
|
+
const path = modelsFilePath();
|
|
171
|
+
if (!existsSync(path))
|
|
172
|
+
return { models: {} };
|
|
173
|
+
const name = process.env[MODELS_FILE_ENV]?.trim() || 'models.yaml';
|
|
174
|
+
let data;
|
|
175
|
+
try {
|
|
176
|
+
data = parseYaml(readFileSync(path, 'utf8'));
|
|
177
|
+
}
|
|
178
|
+
catch (err) {
|
|
179
|
+
return { models: {}, error: `${name} isn't valid YAML: ${err instanceof Error ? err.message : String(err)}` };
|
|
180
|
+
}
|
|
181
|
+
if (data == null)
|
|
182
|
+
return { models: {} };
|
|
183
|
+
if (typeof data !== 'object' || Array.isArray(data))
|
|
184
|
+
return { models: {}, error: `${name} should map each provider to a list of models.` };
|
|
185
|
+
const models = {};
|
|
186
|
+
for (const [provider, list] of Object.entries(data)) {
|
|
187
|
+
if (!modelKeyEnvVar(provider)) {
|
|
188
|
+
return { models: {}, error: `${name}: unknown provider '${provider}'. Use one of ${KNOWN_PROVIDERS.map((p) => p.provider).join(', ')}.` };
|
|
189
|
+
}
|
|
190
|
+
// An empty key ("openai:") means no list, same as leaving it out.
|
|
191
|
+
if (list == null)
|
|
192
|
+
continue;
|
|
193
|
+
if (!Array.isArray(list) || list.some((m) => typeof m !== 'string' || !m.trim())) {
|
|
194
|
+
return { models: {}, error: `${name}: '${provider}' should be a list of model names.` };
|
|
195
|
+
}
|
|
196
|
+
models[provider] = [...new Set(list.map((m) => m.trim()))];
|
|
197
|
+
}
|
|
198
|
+
return { models };
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* The models a provider offers, for the model dropdown in the New agent
|
|
202
|
+
* and Model forms. A provider listed in models.yaml (readModelsFile)
|
|
203
|
+
* offers exactly that list, with no key needed. Otherwise this asks the
|
|
204
|
+
* provider itself with the saved key (cached for ten minutes per key),
|
|
205
|
+
* so new models show up without a release. Never throws for a provider
|
|
206
|
+
* problem: the view carries an `error` instead, and the form lets the
|
|
207
|
+
* model name be typed. Throws ModelKeyError for an unknown provider.
|
|
208
|
+
*/
|
|
209
|
+
export async function listProviderModels(provider, options = {}) {
|
|
210
|
+
const envVar = modelKeyEnvVar(provider);
|
|
211
|
+
if (!envVar)
|
|
212
|
+
throw new ModelKeyError(`unknown provider '${provider}'`);
|
|
213
|
+
const file = readModelsFile();
|
|
214
|
+
const fromFile = file.models[provider];
|
|
215
|
+
if (fromFile)
|
|
216
|
+
return { provider, models: fromFile };
|
|
217
|
+
const view = await listProviderModelsLive(provider, envVar, options);
|
|
218
|
+
return file.error ? { ...view, error: view.error ? `${file.error} ${view.error}` : file.error } : view;
|
|
219
|
+
}
|
|
220
|
+
async function listProviderModelsLive(provider, envVar, options) {
|
|
221
|
+
const key = process.env[envVar];
|
|
222
|
+
if (!key) {
|
|
223
|
+
const known = KNOWN_MODELS[provider] ?? [];
|
|
224
|
+
return {
|
|
225
|
+
provider,
|
|
226
|
+
models: known,
|
|
227
|
+
error: known.length
|
|
228
|
+
? `Showing common ${provider} models. Save ${envVar} on the Models page to list all of them.`
|
|
229
|
+
: `No ${envVar} saved. Save it on the Models page to list ${provider}'s models, or choose Other.`,
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
const cached = modelListCache.get(provider);
|
|
233
|
+
if (cached && cached.key === key && Date.now() - cached.at < MODEL_LIST_TTL_MS)
|
|
234
|
+
return { provider, models: cached.models };
|
|
235
|
+
const clientOptions = { apiKey: key, timeout: 10_000, maxRetries: 0, ...(options.fetch ? { fetch: options.fetch } : {}) };
|
|
236
|
+
try {
|
|
237
|
+
const listed = [];
|
|
238
|
+
if (provider === 'anthropic') {
|
|
239
|
+
// Already newest first.
|
|
240
|
+
for await (const model of new Anthropic(clientOptions).models.list({ limit: 1000 })) {
|
|
241
|
+
listed.push({ id: model.id, created: 0 });
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
const client = new OpenAI({ ...clientOptions, baseURL: OPENAI_COMPATIBLE_BASE_URLS[provider] });
|
|
246
|
+
for await (const model of client.models.list()) {
|
|
247
|
+
// Gemini's ids come back as "models/gemini-...", but its chat
|
|
248
|
+
// endpoint takes the bare name.
|
|
249
|
+
listed.push({ id: model.id.replace(/^models\//, ''), created: model.created ?? 0 });
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
const models = listed
|
|
253
|
+
.filter((model) => (provider === 'openai' || provider === 'gemini' ? !NON_CHAT_MODEL.test(model.id) : true))
|
|
254
|
+
.sort((a, b) => b.created - a.created)
|
|
255
|
+
.map((model) => model.id)
|
|
256
|
+
.filter((id, index, ids) => ids.indexOf(id) === index);
|
|
257
|
+
modelListCache.set(provider, { key, at: Date.now(), models });
|
|
258
|
+
return { provider, models };
|
|
259
|
+
}
|
|
260
|
+
catch (err) {
|
|
261
|
+
const known = KNOWN_MODELS[provider];
|
|
262
|
+
if (known)
|
|
263
|
+
return { provider, models: known };
|
|
264
|
+
return { provider, models: [], error: `Couldn't list ${provider}'s models: ${err instanceof Error ? err.message : String(err)}` };
|
|
265
|
+
}
|
|
266
|
+
}
|
|
107
267
|
export class TimeZoneError extends Error {
|
|
108
268
|
}
|
|
109
269
|
export function describeTimeZone() {
|
|
@@ -126,7 +126,7 @@ export function setupChecklist(candidate, agentName) {
|
|
|
126
126
|
case 'ability':
|
|
127
127
|
return { label: `Install the ${need.name ?? need.description} ability`, href: tab('abilities') };
|
|
128
128
|
case 'api':
|
|
129
|
-
return { label: `Connect ${need.description} (an HTTP tool, or an MCP server)`, href: tab('
|
|
129
|
+
return { label: `Connect ${need.description} (an HTTP tool, or an MCP server)`, href: tab('advanced') };
|
|
130
130
|
case 'key':
|
|
131
131
|
return { label: `Add ${need.description}`, href: tab('env') };
|
|
132
132
|
case 'messaging':
|
|
@@ -239,7 +239,7 @@ export function interviewTools(agents) {
|
|
|
239
239
|
return results.slice(0, 10).map((r) => ({ name: r.name, ...(r.description ? { description: r.description } : {}) }));
|
|
240
240
|
},
|
|
241
241
|
async listConnections() {
|
|
242
|
-
const providers = ['anthropic', '
|
|
242
|
+
const providers = ['openai', 'anthropic', 'gemini', 'meta', 'xai', 'deepseek', 'kimi', 'glm'].filter((p) => {
|
|
243
243
|
const envVar = modelKeyEnvVar(p);
|
|
244
244
|
return envVar ? Boolean(process.env[envVar]) : false;
|
|
245
245
|
});
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export const MESSAGING_ICONS = {
|
|
2
|
+
webhook: '<svg class="le-channel-icon" aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" > <path d="M18 16.98h-5.99c-1.1 0-1.95.94-2.48 1.9A4 4 0 0 1 2 17c.01-.7.2-1.4.57-2" /> <path d="m6 17 3.13-5.78c.53-.97.1-2.18-.5-3.1a4 4 0 1 1 6.89-4.06" /> <path d="m12 6 3.13 5.73C15.66 12.7 16.9 13 18 13a4 4 0 0 1 0 8" /> </svg>',
|
|
3
|
+
telegram: '<svg class="le-channel-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="#26A5E4"><path d="M11.944 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0a12 12 0 0 0-.056 0zm4.962 7.224c.1-.002.321.023.465.14a.506.506 0 0 1 .171.325c.016.093.036.306.02.472-.18 1.898-.962 6.502-1.36 8.627-.168.9-.499 1.201-.82 1.23-.696.065-1.225-.46-1.9-.902-1.056-.693-1.653-1.124-2.678-1.8-1.185-.78-.417-1.21.258-1.91.177-.184 3.247-2.977 3.307-3.23.007-.032.014-.15-.056-.212s-.174-.041-.249-.024c-.106.024-1.793 1.14-5.061 3.345-.48.33-.913.49-1.302.48-.428-.008-1.252-.241-1.865-.44-.752-.245-1.349-.374-1.297-.789.027-.216.325-.437.893-.663 3.498-1.524 5.83-2.529 6.998-3.014 3.332-1.386 4.025-1.627 4.476-1.635z"/></svg>',
|
|
4
|
+
slack: '<svg class="le-channel-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="currentColor"><path d="M5.042 15.165a2.528 2.528 0 0 1-2.52 2.523A2.528 2.528 0 0 1 0 15.165a2.527 2.527 0 0 1 2.522-2.52h2.52v2.52zM6.313 15.165a2.527 2.527 0 0 1 2.521-2.52 2.527 2.527 0 0 1 2.521 2.52v6.313A2.528 2.528 0 0 1 8.834 24a2.528 2.528 0 0 1-2.521-2.522v-6.313zM8.834 5.042a2.528 2.528 0 0 1-2.521-2.52A2.528 2.528 0 0 1 8.834 0a2.528 2.528 0 0 1 2.521 2.522v2.52H8.834zM8.834 6.313a2.528 2.528 0 0 1 2.521 2.521 2.528 2.528 0 0 1-2.521 2.521H2.522A2.528 2.528 0 0 1 0 8.834a2.528 2.528 0 0 1 2.522-2.521h6.312zM18.956 8.834a2.528 2.528 0 0 1 2.522-2.521A2.528 2.528 0 0 1 24 8.834a2.528 2.528 0 0 1-2.522 2.521h-2.522V8.834zM17.688 8.834a2.528 2.528 0 0 1-2.523 2.521 2.527 2.527 0 0 1-2.52-2.521V2.522A2.527 2.527 0 0 1 15.165 0a2.528 2.528 0 0 1 2.523 2.522v6.312zM15.165 18.956a2.528 2.528 0 0 1 2.523 2.522A2.528 2.528 0 0 1 15.165 24a2.527 2.527 0 0 1-2.52-2.522v-2.522h2.52zM15.165 17.688a2.527 2.527 0 0 1-2.52-2.523 2.526 2.526 0 0 1 2.52-2.52h6.313A2.527 2.527 0 0 1 24 15.165a2.528 2.528 0 0 1-2.522 2.523h-6.313z"/></svg>',
|
|
5
|
+
lark: '<svg class="le-channel-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12.9238 12.8029C12.9427 12.784 12.9616 12.7682 12.9806 12.7493C13.0184 12.7146 13.0563 12.6767 13.091 12.6389L13.1667 12.5631L13.397 12.336L14.7315 11.0173L15.0659 10.686C15.129 10.6229 15.1952 10.563 15.2615 10.5031C15.3845 10.3926 15.5076 10.2854 15.6369 10.1813C15.7536 10.0866 15.8767 9.99514 15.9997 9.9068C16.1732 9.78376 16.3499 9.67019 16.5329 9.55977C16.7127 9.45251 16.8957 9.35471 17.085 9.26322C17.2616 9.17804 17.4415 9.09917 17.6276 9.02661C17.7317 8.9856 17.8326 8.94774 17.9399 8.91304C17.9935 8.89411 18.044 8.87834 18.0977 8.86256C17.6276 7.00439 16.7632 5.3008 15.5991 3.84959C15.3719 3.56566 15.0249 3.40161 14.6589 3.40161H5.0084C4.83489 3.40161 4.76233 3.6256 4.90114 3.72656C8.18528 6.13997 10.9236 9.24114 12.9017 12.825C12.908 12.8187 12.9175 12.8124 12.9238 12.8029Z" fill="#00D6B9" /><path d="M9.09696 21.2986C14.0815 21.2986 18.4225 18.5476 20.6877 14.4843C20.7666 14.3423 20.8454 14.1972 20.918 14.052C20.8044 14.2729 20.6751 14.4811 20.5394 14.6767C20.4889 14.7461 20.4385 14.8155 20.388 14.8818C20.3217 14.9669 20.2555 15.049 20.1861 15.1278C20.1324 15.1909 20.0757 15.2509 20.0189 15.3108C19.9021 15.4307 19.7823 15.5474 19.6561 15.6547C19.5867 15.7146 19.5141 15.7714 19.4415 15.8282C19.3564 15.8944 19.268 15.9575 19.1797 16.0143C19.1229 16.0522 19.0661 16.09 19.0093 16.1247C18.9494 16.1626 18.8895 16.1973 18.8264 16.232C18.7002 16.3014 18.574 16.3645 18.4446 16.4245C18.3311 16.4749 18.2175 16.5223 18.1008 16.5633C17.9746 16.6106 17.8452 16.6516 17.7159 16.6863C17.5234 16.7399 17.3247 16.7809 17.1259 16.8125C16.9808 16.8346 16.8357 16.8504 16.6874 16.863C16.5328 16.8724 16.3751 16.8787 16.2173 16.8756C16.0438 16.8724 15.8703 16.863 15.6936 16.844C15.5643 16.8314 15.435 16.8125 15.3056 16.7873C15.192 16.7683 15.0785 16.7431 14.9649 16.7178C14.9049 16.7021 14.845 16.6895 14.7851 16.6737C14.6179 16.6295 14.4538 16.5822 14.2898 16.5349C14.2077 16.5096 14.1257 16.4875 14.0437 16.4623C13.9206 16.4245 13.7976 16.3897 13.6777 16.3519C13.5768 16.3203 13.479 16.2888 13.378 16.2572C13.2834 16.2257 13.1887 16.1942 13.0941 16.1626C13.031 16.1405 12.9647 16.1184 12.9016 16.0964C12.8228 16.0711 12.7471 16.0427 12.6682 16.0143C12.6114 15.9954 12.5578 15.9765 12.501 15.9544C12.3906 15.9134 12.2802 15.8755 12.1729 15.8345C12.1098 15.8093 12.0467 15.7872 11.9836 15.7619C11.8984 15.7304 11.8132 15.6957 11.7312 15.6641C11.6429 15.6294 11.5514 15.5947 11.4631 15.5569C11.4063 15.5348 11.3463 15.5096 11.2895 15.4875C11.217 15.4591 11.1476 15.4275 11.075 15.3991C11.0214 15.3771 10.9646 15.3518 10.911 15.3297C10.8542 15.3045 10.7974 15.2793 10.7406 15.254C10.6901 15.2319 10.6428 15.2099 10.5923 15.1878C10.5482 15.1688 10.5008 15.1468 10.4567 15.1278C10.4094 15.1057 10.3652 15.0868 10.3179 15.0647C10.2705 15.0427 10.2232 15.0206 10.1759 14.9985C10.116 14.9701 10.056 14.9417 9.99608 14.9165C9.93299 14.8881 9.87304 14.8565 9.80995 14.8281C9.7437 14.7966 9.67745 14.765 9.6112 14.7303C9.55441 14.7019 9.49762 14.6735 9.44084 14.6483C6.45324 13.1592 3.80321 11.1717 1.54438 8.76145C1.43081 8.64157 1.23206 8.72044 1.23206 8.88449L1.23836 18.0933C1.23836 18.494 1.43712 18.8726 1.77153 19.0934C3.86631 20.4878 6.38699 21.2986 9.09696 21.2986Z" fill="#3370FF" /><path d="M23.7322 9.29488C22.7226 8.79642 21.5838 8.5188 20.3818 8.5188C19.6688 8.5188 18.9747 8.6166 18.3217 8.80273C18.246 8.82481 18.1703 8.8469 18.0977 8.86898C18.0441 8.88476 17.9905 8.90368 17.94 8.91946C17.8359 8.95416 17.7318 8.99202 17.6276 9.03303C17.4447 9.10559 17.2617 9.18446 17.085 9.26964C16.8957 9.36113 16.7128 9.45893 16.5329 9.56619C16.35 9.67345 16.1701 9.79018 15.9998 9.91322C15.8767 10.0016 15.7569 10.093 15.637 10.1877C15.5076 10.2918 15.3846 10.3991 15.2616 10.5095C15.1953 10.5694 15.1322 10.6325 15.066 10.6925L14.7315 11.0206L13.3939 12.3424L13.1636 12.5696L13.0879 12.6453C13.05 12.6831 13.0122 12.7178 12.9775 12.7557C12.9586 12.7746 12.9396 12.7904 12.9207 12.8093C12.8923 12.8377 12.8639 12.863 12.8355 12.8882C12.804 12.9166 12.7724 12.9481 12.7409 12.9765C11.9143 13.7368 10.9931 14.3899 9.99304 14.923C10.053 14.9514 10.1129 14.9798 10.1729 15.0051C10.2202 15.0271 10.2675 15.0492 10.3148 15.0713C10.359 15.0934 10.4063 15.1123 10.4536 15.1344C10.4978 15.1533 10.5451 15.1754 10.5893 15.1943C10.6398 15.2164 10.6871 15.2385 10.7376 15.2606C10.7944 15.2858 10.8511 15.3111 10.9079 15.3363C10.9616 15.3584 11.0184 15.3836 11.072 15.4057C11.1445 15.4373 11.2139 15.4657 11.2865 15.4941C11.3433 15.5193 11.4032 15.5414 11.46 15.5635C11.5484 15.5982 11.6367 15.636 11.7282 15.6707C11.8134 15.7023 11.8954 15.737 11.9806 15.7685C12.0437 15.7938 12.1068 15.8158 12.1699 15.8411C12.2803 15.8821 12.3875 15.9231 12.498 15.961C12.5547 15.9799 12.6084 16.002 12.6652 16.0209C12.744 16.0493 12.8197 16.0745 12.8986 16.1029C12.9617 16.125 13.028 16.1471 13.0911 16.1692C13.1857 16.2007 13.2803 16.2323 13.375 16.2638C13.4728 16.2954 13.5737 16.3269 13.6747 16.3585C13.7977 16.3963 13.9176 16.4342 14.0406 16.4689C14.1227 16.4941 14.2047 16.5162 14.2867 16.5414C14.4508 16.5888 14.618 16.6361 14.782 16.6803C14.842 16.696 14.9019 16.7118 14.9618 16.7244C15.0754 16.7528 15.189 16.7749 15.3026 16.7938C15.4319 16.8159 15.5613 16.8348 15.6906 16.8506C15.8673 16.8695 16.0408 16.8822 16.2143 16.8822C16.372 16.8853 16.5298 16.879 16.6844 16.8695C16.8326 16.8601 16.9778 16.8412 17.1229 16.8191C17.3248 16.7875 17.5204 16.7465 17.7128 16.6929C17.8422 16.6582 17.9715 16.6172 18.0977 16.5698C18.2144 16.5257 18.328 16.4815 18.4416 16.4279C18.5709 16.3679 18.7003 16.3048 18.8233 16.2354C18.8833 16.2007 18.9464 16.166 19.0063 16.1282C19.0631 16.0935 19.1199 16.0556 19.1767 16.0178C19.265 15.9578 19.3533 15.8947 19.4385 15.8316C19.5111 15.7748 19.5836 15.718 19.653 15.6581C19.7792 15.5508 19.8991 15.4341 20.0158 15.3142C20.0726 15.2543 20.1294 15.1943 20.183 15.1313C20.2524 15.0524 20.3187 14.9704 20.3849 14.8852C20.4354 14.8189 20.4859 14.7495 20.5364 14.6801C20.672 14.4845 20.7982 14.2763 20.9118 14.0586L21.0411 13.7999L22.2084 11.4748L22.2053 11.4812C22.5807 10.6578 23.1012 9.91953 23.7322 9.29488Z" fill="#133C9A" /></svg>',
|
|
6
|
+
email: '<svg class="le-channel-icon" aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" > <rect width="20" height="16" x="2" y="4" rx="2" /> <path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7" /> </svg>',
|
|
7
|
+
};
|
|
@@ -13,6 +13,10 @@ export interface DefaultWebhook {
|
|
|
13
13
|
}
|
|
14
14
|
export declare function describeAgentNotifier(config: AgentConfig, defaultWebhook?: DefaultWebhook): {
|
|
15
15
|
source: string;
|
|
16
|
+
channels: NotifierFileChannel[];
|
|
17
|
+
primaryChannels: NotifierFileChannel[];
|
|
18
|
+
connections: NotifierFile[];
|
|
19
|
+
primary: NotifierFileChannel | null;
|
|
16
20
|
defaultWebhookUrl: string | null;
|
|
17
21
|
publicUrl: string | null;
|
|
18
22
|
plan: string | null;
|
|
@@ -33,10 +37,16 @@ export declare function describeAgentNotifier(config: AgentConfig, defaultWebhoo
|
|
|
33
37
|
file?: NotifierFile;
|
|
34
38
|
missingSecret?: string;
|
|
35
39
|
error?: string;
|
|
40
|
+
active?: Array<{
|
|
41
|
+
channel: NotifierFileChannel;
|
|
42
|
+
missingSecret?: string;
|
|
43
|
+
}>;
|
|
36
44
|
};
|
|
37
|
-
/**
|
|
38
|
-
*
|
|
39
|
-
*
|
|
45
|
+
/** Saves one app's connection in agents/<name>/messaging.yml from its
|
|
46
|
+
* section of the Messaging tab (the first one saved becomes primary;
|
|
47
|
+
* `primary: true` in the body makes this one primary) and, when the form
|
|
48
|
+
* includes one, its secret into the agent's own env. Throws
|
|
49
|
+
* NotifierFileError for an invalid form. */
|
|
40
50
|
export declare function saveAgentNotifier(config: AgentConfig, body: Record<string, unknown>): Promise<void>;
|
|
41
51
|
/** The bot token and signing secret behind an agent's Slack notifier —
|
|
42
52
|
* from AgentConfig.httpNotifier when it's Slack, else from the agent's
|
|
@@ -60,25 +70,33 @@ export declare function slackClickAllowed(config: AgentConfig, user: string | un
|
|
|
60
70
|
allowed: boolean;
|
|
61
71
|
message?: string;
|
|
62
72
|
};
|
|
63
|
-
/** Replaces the approver list on the agent's saved Slack connection
|
|
64
|
-
* Throws NotifierFileError when there's no Slack
|
|
73
|
+
/** Replaces the approver list on the agent's saved Slack connection,
|
|
74
|
+
* primary or not. Throws NotifierFileError when there's no Slack
|
|
75
|
+
* connection to add them to. */
|
|
65
76
|
export declare function setAgentApprovers(config: AgentConfig, approvers: unknown): MessagingApprover[];
|
|
66
77
|
/** The people in the agent's Slack channel, for picking approvers. */
|
|
67
78
|
export declare function listAgentSlackMembers(config: AgentConfig): Promise<SlackMember[]>;
|
|
68
79
|
/** Channels for the console's picker, with the token being typed in or,
|
|
69
80
|
* when none is given, the one already saved. */
|
|
70
81
|
export declare function listAgentSlackChannels(config: AgentConfig, botToken?: string): Promise<SlackChannel[]>;
|
|
71
|
-
/** Removes
|
|
72
|
-
*
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
*
|
|
77
|
-
|
|
82
|
+
/** Removes one app's connection, or every connection when no app is
|
|
83
|
+
* named. Removing the primary leaves none primary. Stored secrets are
|
|
84
|
+
* left alone, so setting an app up again doesn't need them re-entered. */
|
|
85
|
+
export declare function removeAgentNotifier(config: AgentConfig, channel?: string): void;
|
|
86
|
+
/** Makes one saved connection the one in use. Throws NotifierFileError
|
|
87
|
+
* when that app isn't set up. */
|
|
88
|
+
export declare function setAgentPrimaryNotifier(config: AgentConfig, channel: unknown): void;
|
|
89
|
+
/** Posts a plain announcement through the agent's notifiers (the webhook
|
|
90
|
+
* and the primary messaging app) — a scheduled task's result, for one —
|
|
91
|
+
* regardless of which events they subscribed to. A webhook gets a signed
|
|
92
|
+
* `run_finish` payload with `data` merged in; the apps get `text`.
|
|
93
|
+
* Returns whether any notifier took it. */
|
|
78
94
|
export declare function announceToNotifier(config: AgentConfig, text: string, data: Record<string, unknown>, defaultWebhook?: DefaultWebhook): boolean;
|
|
79
|
-
/** Sends a test through
|
|
80
|
-
*
|
|
81
|
-
|
|
95
|
+
/** Sends a test through one app's saved connection when `channel` is
|
|
96
|
+
* given (primary or not, so it can be tried before it's made primary),
|
|
97
|
+
* else through whichever notifier applies to this agent; reports what
|
|
98
|
+
* the receiver answered. */
|
|
99
|
+
export declare function testAgentNotifier(config: AgentConfig, defaultWebhook?: DefaultWebhook, channel?: string): Promise<DeliveryResult & {
|
|
82
100
|
channel?: string;
|
|
83
101
|
}>;
|
|
84
102
|
/** Every decision still waiting for this agent, oldest first, each with
|
|
@@ -5,8 +5,9 @@ import { sendTestSlackMessage } from '../core/http-notify-triggers/slack.js';
|
|
|
5
5
|
import { postLifecycleWebhook, sendTestWebhook } from '../core/http-notify-triggers/webhook.js';
|
|
6
6
|
import { SlackNotifier } from '../core/http-notify-triggers/slack.js';
|
|
7
7
|
import { LarkNotifier } from '../core/http-notify-triggers/lark.js';
|
|
8
|
+
import { TelegramNotifier, sendTestTelegramMessage } from '../core/http-notify-triggers/telegram.js';
|
|
8
9
|
import { listDeliveries } from '../core/notifier-deliveries.js';
|
|
9
|
-
import { NOTIFIER_SECRET_VARS, NOTIFIER_SLACK_SIGNING_SECRET_VAR, NotifierFileError, notifierConfigFromFile, readNotifierFile, removeNotifierFile, writeNotifierFile } from '../core/notifier-file.js';
|
|
10
|
+
import { NOTIFIER_CHANNELS, NOTIFIER_SECRET_VARS, PRIMARY_CHANNELS, NOTIFIER_SLACK_SIGNING_SECRET_VAR, NotifierFileError, notifierConfigFromFile, readActiveConnections, readMessagingConnections, readNotifierFile, removeMessagingConnection, removeNotifierFile, setPrimaryConnection, writeNotifierFile } from '../core/notifier-file.js';
|
|
10
11
|
import { listSlackChannelMembers, listSlackChannels, slackAppManifest } from '../core/messaging/connectors/slack/index.js';
|
|
11
12
|
import { setAgentEnvVar } from './env-admin.js';
|
|
12
13
|
export function describeAgentNotifier(config, defaultWebhook) {
|
|
@@ -14,9 +15,22 @@ export function describeAgentNotifier(config, defaultWebhook) {
|
|
|
14
15
|
const env = createAgentEnv(config.name, agentDirFor(config));
|
|
15
16
|
const secretsSet = Object.fromEntries(Object.keys(NOTIFIER_SECRET_VARS).map((channel) => [channel, env.get(NOTIFIER_SECRET_VARS[channel]) !== undefined]));
|
|
16
17
|
const source = described.source === 'none' && defaultWebhook ? 'default' : described.source;
|
|
18
|
+
// Every saved connection, one per app, for the tab's section for each;
|
|
19
|
+
// only `primary` is used. An unreadable file shows as none here (the
|
|
20
|
+
// error itself comes through `described`).
|
|
21
|
+
let saved = { connections: [] };
|
|
22
|
+
try {
|
|
23
|
+
saved = readMessagingConnections(agentDirFor(config));
|
|
24
|
+
}
|
|
25
|
+
catch { }
|
|
17
26
|
return {
|
|
18
27
|
...described,
|
|
19
28
|
source,
|
|
29
|
+
channels: NOTIFIER_CHANNELS,
|
|
30
|
+
// Only these take turns as primary; a webhook always sends.
|
|
31
|
+
primaryChannels: PRIMARY_CHANNELS,
|
|
32
|
+
connections: saved.connections,
|
|
33
|
+
primary: saved.primary ?? null,
|
|
20
34
|
defaultWebhookUrl: defaultWebhook?.webhookUrl ?? null,
|
|
21
35
|
publicUrl: process.env.LOOPENGINE_PUBLIC_URL ?? null,
|
|
22
36
|
// LOOPENGINE_PLAN ('free' on LoopEngine Cloud's free plan): the
|
|
@@ -38,22 +52,27 @@ export function describeAgentNotifier(config, defaultWebhook) {
|
|
|
38
52
|
deliveries: listDeliveries(config.name),
|
|
39
53
|
};
|
|
40
54
|
}
|
|
41
|
-
/**
|
|
42
|
-
|
|
43
|
-
* Throws NotifierFileError for an invalid form. */
|
|
44
|
-
export async function saveAgentNotifier(config, body) {
|
|
45
|
-
// The form doesn't carry the approvers (they have their own section),
|
|
46
|
-
// so saving it keeps them.
|
|
47
|
-
let existing;
|
|
55
|
+
/** The agent's saved connection for one app, primary or not. */
|
|
56
|
+
function savedConnection(config, channel) {
|
|
48
57
|
try {
|
|
49
|
-
|
|
58
|
+
return readMessagingConnections(agentDirFor(config)).connections.find((c) => c.channel === channel);
|
|
50
59
|
}
|
|
51
|
-
catch {
|
|
52
|
-
|
|
53
|
-
if (body.approvers === undefined && existing.approvers)
|
|
54
|
-
body = { ...body, approvers: existing.approvers };
|
|
60
|
+
catch {
|
|
61
|
+
return undefined;
|
|
55
62
|
}
|
|
56
|
-
|
|
63
|
+
}
|
|
64
|
+
/** Saves one app's connection in agents/<name>/messaging.yml from its
|
|
65
|
+
* section of the Messaging tab (the first one saved becomes primary;
|
|
66
|
+
* `primary: true` in the body makes this one primary) and, when the form
|
|
67
|
+
* includes one, its secret into the agent's own env. Throws
|
|
68
|
+
* NotifierFileError for an invalid form. */
|
|
69
|
+
export async function saveAgentNotifier(config, body) {
|
|
70
|
+
// The form doesn't carry the approvers (they have their own section),
|
|
71
|
+
// so saving it keeps them.
|
|
72
|
+
const existing = typeof body.channel === 'string' ? savedConnection(config, body.channel) : undefined;
|
|
73
|
+
if (existing?.approvers && body.approvers === undefined)
|
|
74
|
+
body = { ...body, approvers: existing.approvers };
|
|
75
|
+
const file = writeNotifierFile(agentDirFor(config), body, { makePrimary: body.primary === true });
|
|
57
76
|
if (typeof body.secret === 'string' && body.secret.trim()) {
|
|
58
77
|
await setAgentEnvVar(config.name, NOTIFIER_SECRET_VARS[file.channel], body.secret.trim());
|
|
59
78
|
}
|
|
@@ -104,19 +123,19 @@ export function slackClickAllowed(config, user) {
|
|
|
104
123
|
return { allowed: true };
|
|
105
124
|
return { allowed: false, message: `Only approvers can decide this: ${approvers.map((a) => `<@${a.user}>`).join(', ')}.` };
|
|
106
125
|
}
|
|
107
|
-
/** Replaces the approver list on the agent's saved Slack connection
|
|
108
|
-
* Throws NotifierFileError when there's no Slack
|
|
126
|
+
/** Replaces the approver list on the agent's saved Slack connection,
|
|
127
|
+
* primary or not. Throws NotifierFileError when there's no Slack
|
|
128
|
+
* connection to add them to. */
|
|
109
129
|
export function setAgentApprovers(config, approvers) {
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
if (!file || file.channel !== 'slack')
|
|
130
|
+
const file = savedConnection(config, 'slack');
|
|
131
|
+
if (!file)
|
|
113
132
|
throw new NotifierFileError('Save a Slack connection first');
|
|
114
|
-
return writeNotifierFile(
|
|
133
|
+
return writeNotifierFile(agentDirFor(config), { ...file, approvers: Array.isArray(approvers) ? approvers : [] }).approvers ?? [];
|
|
115
134
|
}
|
|
116
135
|
/** The people in the agent's Slack channel, for picking approvers. */
|
|
117
136
|
export async function listAgentSlackMembers(config) {
|
|
118
137
|
const { botToken } = slackCredentialsFor(config);
|
|
119
|
-
const channelId = config.httpNotifier?.channel === 'slack' ? config.httpNotifier.config.channelId :
|
|
138
|
+
const channelId = config.httpNotifier?.channel === 'slack' ? config.httpNotifier.config.channelId : savedConnection(config, 'slack')?.channelId;
|
|
120
139
|
if (!botToken || !channelId)
|
|
121
140
|
throw new Error('Save the Slack bot token and channel first');
|
|
122
141
|
return listSlackChannelMembers(botToken, channelId);
|
|
@@ -129,61 +148,83 @@ export async function listAgentSlackChannels(config, botToken) {
|
|
|
129
148
|
throw new Error('Enter the bot token first');
|
|
130
149
|
return listSlackChannels(token);
|
|
131
150
|
}
|
|
132
|
-
/** Removes
|
|
133
|
-
*
|
|
134
|
-
|
|
135
|
-
|
|
151
|
+
/** Removes one app's connection, or every connection when no app is
|
|
152
|
+
* named. Removing the primary leaves none primary. Stored secrets are
|
|
153
|
+
* left alone, so setting an app up again doesn't need them re-entered. */
|
|
154
|
+
export function removeAgentNotifier(config, channel) {
|
|
155
|
+
if (channel)
|
|
156
|
+
removeMessagingConnection(agentDirFor(config), channel);
|
|
157
|
+
else
|
|
158
|
+
removeNotifierFile(agentDirFor(config));
|
|
159
|
+
}
|
|
160
|
+
/** Makes one saved connection the one in use. Throws NotifierFileError
|
|
161
|
+
* when that app isn't set up. */
|
|
162
|
+
export function setAgentPrimaryNotifier(config, channel) {
|
|
163
|
+
if (typeof channel !== 'string' || !NOTIFIER_CHANNELS.includes(channel)) {
|
|
164
|
+
throw new NotifierFileError(`channel must be one of: ${NOTIFIER_CHANNELS.join(', ')}`);
|
|
165
|
+
}
|
|
166
|
+
setPrimaryConnection(agentDirFor(config), channel);
|
|
136
167
|
}
|
|
137
|
-
/** The
|
|
138
|
-
*
|
|
139
|
-
* deployment-wide default webhook. */
|
|
140
|
-
function
|
|
168
|
+
/** The notifiers that apply to an agent: its code httpNotifier; else its
|
|
169
|
+
* messaging.yml's webhook and primary messaging app (each once its
|
|
170
|
+
* secret is set); else the deployment-wide default webhook. */
|
|
171
|
+
function activeNotifierTargets(config, defaultWebhook) {
|
|
141
172
|
if (config.httpNotifier)
|
|
142
|
-
return config.httpNotifier;
|
|
173
|
+
return [config.httpNotifier];
|
|
143
174
|
const dir = agentDirFor(config);
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
* Slack and Lark get `text`. Does nothing when no notifier applies. */
|
|
175
|
+
const env = createAgentEnv(config.name, dir);
|
|
176
|
+
const fromFile = readActiveConnections(dir).flatMap((file) => notifierConfigFromFile(file, env, config.name).config ?? []);
|
|
177
|
+
if (fromFile.length)
|
|
178
|
+
return fromFile;
|
|
179
|
+
return defaultWebhook ? [{ channel: 'webhook', config: { webhookUrl: defaultWebhook.webhookUrl, webhookSecret: defaultWebhook.webhookSecret }, events: ['run_finish'] }] : [];
|
|
180
|
+
}
|
|
181
|
+
/** Posts a plain announcement through the agent's notifiers (the webhook
|
|
182
|
+
* and the primary messaging app) — a scheduled task's result, for one —
|
|
183
|
+
* regardless of which events they subscribed to. A webhook gets a signed
|
|
184
|
+
* `run_finish` payload with `data` merged in; the apps get `text`.
|
|
185
|
+
* Returns whether any notifier took it. */
|
|
156
186
|
export function announceToNotifier(config, text, data, defaultWebhook) {
|
|
157
|
-
let
|
|
187
|
+
let targets;
|
|
158
188
|
try {
|
|
159
|
-
|
|
189
|
+
targets = activeNotifierTargets(config, defaultWebhook);
|
|
160
190
|
}
|
|
161
191
|
catch {
|
|
162
192
|
return false;
|
|
163
193
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
194
|
+
let sent = false;
|
|
195
|
+
for (const target of targets) {
|
|
196
|
+
switch (target.channel) {
|
|
197
|
+
case 'webhook':
|
|
198
|
+
postLifecycleWebhook(target.config.webhookUrl, target.config.webhookSecret, 'run_finish', { agent: config.name, text, ...data });
|
|
199
|
+
sent = true;
|
|
200
|
+
break;
|
|
201
|
+
case 'slack':
|
|
202
|
+
new SlackNotifier({ botToken: target.config.botToken, channelId: target.config.channelId }).postMessage(text);
|
|
203
|
+
sent = true;
|
|
204
|
+
break;
|
|
205
|
+
case 'lark':
|
|
206
|
+
new LarkNotifier({ appId: target.config.appId, appSecret: target.config.appSecret, chatId: target.config.chatId }).postMessage(text);
|
|
207
|
+
sent = true;
|
|
208
|
+
break;
|
|
209
|
+
case 'telegram':
|
|
210
|
+
new TelegramNotifier({ botToken: target.config.botToken, chatId: target.config.chatId }).postMessage(text);
|
|
211
|
+
sent = true;
|
|
212
|
+
break;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return sent;
|
|
216
|
+
}
|
|
217
|
+
/** Sends a test through one app's saved connection when `channel` is
|
|
218
|
+
* given (primary or not, so it can be tried before it's made primary),
|
|
219
|
+
* else through whichever notifier applies to this agent; reports what
|
|
220
|
+
* the receiver answered. */
|
|
221
|
+
export async function testAgentNotifier(config, defaultWebhook, channel) {
|
|
222
|
+
let target = channel ? undefined : config.httpNotifier;
|
|
223
|
+
if (channel && !savedConnection(config, channel))
|
|
224
|
+
return { ok: false, channel, error: `Save the ${channel} connection first` };
|
|
184
225
|
if (!target) {
|
|
185
226
|
const dir = agentDirFor(config);
|
|
186
|
-
const file = readNotifierFile(dir);
|
|
227
|
+
const file = channel ? savedConnection(config, channel) : readNotifierFile(dir);
|
|
187
228
|
if (file) {
|
|
188
229
|
const { config: fromFile, missingSecret } = notifierConfigFromFile(file, createAgentEnv(config.name, dir), config.name);
|
|
189
230
|
if (!fromFile)
|
|
@@ -202,6 +243,9 @@ export async function testAgentNotifier(config, defaultWebhook) {
|
|
|
202
243
|
if (target.channel === 'slack') {
|
|
203
244
|
return { channel: 'slack', ...(await sendTestSlackMessage(target.config.botToken, target.config.channelId, `Test from LoopEngine: approvals for ${config.name} will be posted here.`)) };
|
|
204
245
|
}
|
|
246
|
+
if (target.channel === 'telegram') {
|
|
247
|
+
return { channel: 'telegram', ...(await sendTestTelegramMessage(target.config.botToken, target.config.chatId, `Test from LoopEngine: approvals for ${config.name} will be posted here.`)) };
|
|
248
|
+
}
|
|
205
249
|
if (target.channel === 'email') {
|
|
206
250
|
try {
|
|
207
251
|
await target.config.sendEmail(target.config.to, `Test from LoopEngine: ${config.name}`, `<p>This is a test. Approval requests and questions from <b>${config.name}</b> will be emailed here, each with a link to approve, deny or answer.</p>`, { kind: 'test' });
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export const PROVIDER_ICONS = {
|
|
2
|
+
openai: '<svg class="le-provider-icon" aria-hidden="true" focusable="false" fill="currentColor" fill-rule="evenodd" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M9.205 8.658v-2.26c0-.19.072-.333.238-.428l4.543-2.616c.619-.357 1.356-.523 2.117-.523 2.854 0 4.662 2.212 4.662 4.566 0 .167 0 .357-.024.547l-4.71-2.759a.797.797 0 00-.856 0l-5.97 3.473zm10.609 8.8V12.06c0-.333-.143-.57-.429-.737l-5.97-3.473 1.95-1.118a.433.433 0 01.476 0l4.543 2.617c1.309.76 2.189 2.378 2.189 3.948 0 1.808-1.07 3.473-2.76 4.163zM7.802 12.703l-1.95-1.142c-.167-.095-.239-.238-.239-.428V5.899c0-2.545 1.95-4.472 4.591-4.472 1 0 1.927.333 2.712.928L8.23 5.067c-.285.166-.428.404-.428.737v6.898zM12 15.128l-2.795-1.57v-3.33L12 8.658l2.795 1.57v3.33L12 15.128zm1.796 7.23c-1 0-1.927-.332-2.712-.927l4.686-2.712c.285-.166.428-.404.428-.737v-6.898l1.974 1.142c.167.095.238.238.238.428v5.233c0 2.545-1.974 4.472-4.614 4.472zm-5.637-5.303l-4.544-2.617c-1.308-.761-2.188-2.378-2.188-3.948A4.482 4.482 0 014.21 6.327v5.423c0 .333.143.571.428.738l5.947 3.449-1.95 1.118a.432.432 0 01-.476 0zm-.262 3.9c-2.688 0-4.662-2.021-4.662-4.519 0-.19.024-.38.047-.57l4.686 2.71c.286.167.571.167.856 0l5.97-3.448v2.26c0 .19-.07.333-.237.428l-4.543 2.616c-.619.357-1.356.523-2.117.523zm5.899 2.83a5.947 5.947 0 005.827-4.756C22.287 18.339 24 15.84 24 13.296c0-1.665-.713-3.282-1.998-4.448.119-.5.19-.999.19-1.498 0-3.401-2.759-5.947-5.946-5.947-.642 0-1.26.095-1.88.31A5.962 5.962 0 0010.205 0a5.947 5.947 0 00-5.827 4.757C1.713 5.447 0 7.945 0 10.49c0 1.666.713 3.283 1.998 4.448-.119.5-.19 1-.19 1.499 0 3.401 2.759 5.946 5.946 5.946.642 0 1.26-.095 1.88-.309a5.96 5.96 0 004.162 1.713z"></path></svg>',
|
|
3
|
+
anthropic: '<svg class="le-provider-icon" aria-hidden="true" focusable="false" fill="currentColor" fill-rule="evenodd" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M13.827 3.52h3.603L24 20h-3.603l-6.57-16.48zm-7.258 0h3.767L16.906 20h-3.674l-1.343-3.461H5.017l-1.344 3.46H0L6.57 3.522zm4.132 9.959L8.453 7.687 6.205 13.48H10.7z"></path></svg>',
|
|
4
|
+
gemini: '<svg class="le-provider-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M20.616 10.835a14.147 14.147 0 01-4.45-3.001 14.111 14.111 0 01-3.678-6.452.503.503 0 00-.975 0 14.134 14.134 0 01-3.679 6.452 14.155 14.155 0 01-4.45 3.001c-.65.28-1.318.505-2.002.678a.502.502 0 000 .975c.684.172 1.35.397 2.002.677a14.147 14.147 0 014.45 3.001 14.112 14.112 0 013.679 6.453.502.502 0 00.975 0c.172-.685.397-1.351.677-2.003a14.145 14.145 0 013.001-4.45 14.113 14.113 0 016.453-3.678.503.503 0 000-.975 13.245 13.245 0 01-2.003-.678z" fill="#3186FF"></path><path d="M20.616 10.835a14.147 14.147 0 01-4.45-3.001 14.111 14.111 0 01-3.678-6.452.503.503 0 00-.975 0 14.134 14.134 0 01-3.679 6.452 14.155 14.155 0 01-4.45 3.001c-.65.28-1.318.505-2.002.678a.502.502 0 000 .975c.684.172 1.35.397 2.002.677a14.147 14.147 0 014.45 3.001 14.112 14.112 0 013.679 6.453.502.502 0 00.975 0c.172-.685.397-1.351.677-2.003a14.145 14.145 0 013.001-4.45 14.113 14.113 0 016.453-3.678.503.503 0 000-.975 13.245 13.245 0 01-2.003-.678z" fill="url(#lobe-icons-gemini-0-_R_0_)"></path><path d="M20.616 10.835a14.147 14.147 0 01-4.45-3.001 14.111 14.111 0 01-3.678-6.452.503.503 0 00-.975 0 14.134 14.134 0 01-3.679 6.452 14.155 14.155 0 01-4.45 3.001c-.65.28-1.318.505-2.002.678a.502.502 0 000 .975c.684.172 1.35.397 2.002.677a14.147 14.147 0 014.45 3.001 14.112 14.112 0 013.679 6.453.502.502 0 00.975 0c.172-.685.397-1.351.677-2.003a14.145 14.145 0 013.001-4.45 14.113 14.113 0 016.453-3.678.503.503 0 000-.975 13.245 13.245 0 01-2.003-.678z" fill="url(#lobe-icons-gemini-1-_R_0_)"></path><path d="M20.616 10.835a14.147 14.147 0 01-4.45-3.001 14.111 14.111 0 01-3.678-6.452.503.503 0 00-.975 0 14.134 14.134 0 01-3.679 6.452 14.155 14.155 0 01-4.45 3.001c-.65.28-1.318.505-2.002.678a.502.502 0 000 .975c.684.172 1.35.397 2.002.677a14.147 14.147 0 014.45 3.001 14.112 14.112 0 013.679 6.453.502.502 0 00.975 0c.172-.685.397-1.351.677-2.003a14.145 14.145 0 013.001-4.45 14.113 14.113 0 016.453-3.678.503.503 0 000-.975 13.245 13.245 0 01-2.003-.678z" fill="url(#lobe-icons-gemini-2-_R_0_)"></path><defs><linearGradient gradientUnits="userSpaceOnUse" id="lobe-icons-gemini-0-_R_0_" x1="7" x2="11" y1="15.5" y2="12"><stop stop-color="#08B962"></stop><stop offset="1" stop-color="#08B962" stop-opacity="0"></stop></linearGradient><linearGradient gradientUnits="userSpaceOnUse" id="lobe-icons-gemini-1-_R_0_" x1="8" x2="11.5" y1="5.5" y2="11"><stop stop-color="#F94543"></stop><stop offset="1" stop-color="#F94543" stop-opacity="0"></stop></linearGradient><linearGradient gradientUnits="userSpaceOnUse" id="lobe-icons-gemini-2-_R_0_" x1="3.5" x2="17.5" y1="13.5" y2="12"><stop stop-color="#FABC12"></stop><stop offset=".46" stop-color="#FABC12" stop-opacity="0"></stop></linearGradient></defs></svg>',
|
|
5
|
+
meta: '<svg class="le-provider-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M6.897 4h-.024l-.031 2.615h.022c1.715 0 3.046 1.357 5.94 6.246l.175.297.012.02 1.62-2.438-.012-.019a48.763 48.763 0 00-1.098-1.716 28.01 28.01 0 00-1.175-1.629C10.413 4.932 8.812 4 6.896 4z" fill="url(#lobe-icons-meta-0-_R_0_)"></path><path d="M6.873 4C4.95 4.01 3.247 5.258 2.02 7.17a4.352 4.352 0 00-.01.017l2.254 1.231.011-.017c.718-1.083 1.61-1.774 2.568-1.785h.021L6.896 4h-.023z" fill="url(#lobe-icons-meta-1-_R_0_)"></path><path d="M2.019 7.17l-.011.017C1.2 8.447.598 9.995.274 11.664l-.005.022 2.534.6.004-.022c.27-1.467.786-2.828 1.456-3.845l.011-.017L2.02 7.17z" fill="url(#lobe-icons-meta-2-_R_0_)"></path><path d="M2.807 12.264l-2.533-.6-.005.022c-.177.918-.267 1.851-.269 2.786v.023l2.598.233v-.023a12.591 12.591 0 01.21-2.44z" fill="url(#lobe-icons-meta-3-_R_0_)"></path><path d="M2.677 15.537a5.462 5.462 0 01-.079-.813v-.022L0 14.468v.024a8.89 8.89 0 00.146 1.652l2.535-.585a4.106 4.106 0 01-.004-.022z" fill="url(#lobe-icons-meta-4-_R_0_)"></path><path d="M3.27 16.89c-.284-.31-.484-.756-.589-1.328l-.004-.021-2.535.585.004.021c.192 1.01.568 1.85 1.106 2.487l.014.017 2.018-1.745a2.106 2.106 0 01-.015-.016z" fill="url(#lobe-icons-meta-5-_R_0_)"></path><path d="M10.78 9.654c-1.528 2.35-2.454 3.825-2.454 3.825-2.035 3.2-2.739 3.917-3.871 3.917a1.545 1.545 0 01-1.186-.508l-2.017 1.744.014.017C2.01 19.518 3.058 20 4.356 20c1.963 0 3.374-.928 5.884-5.33l1.766-3.13a41.283 41.283 0 00-1.227-1.886z" fill="#0082FB"></path><path d="M13.502 5.946l-.016.016c-.4.43-.786.908-1.16 1.416.378.483.768 1.024 1.175 1.63.48-.743.928-1.345 1.367-1.807l.016-.016-1.382-1.24z" fill="url(#lobe-icons-meta-6-_R_0_)"></path><path d="M20.918 5.713C19.853 4.633 18.583 4 17.225 4c-1.432 0-2.637.787-3.723 1.944l-.016.016 1.382 1.24.016-.017c.715-.747 1.408-1.12 2.176-1.12.826 0 1.6.39 2.27 1.075l.015.016 1.589-1.425-.016-.016z" fill="#0082FB"></path><path d="M23.998 14.125c-.06-3.467-1.27-6.566-3.064-8.396l-.016-.016-1.588 1.424.015.016c1.35 1.392 2.277 3.98 2.361 6.971v.023h2.292v-.022z" fill="url(#lobe-icons-meta-7-_R_0_)"></path><path d="M23.998 14.15v-.023h-2.292v.022c.004.14.006.282.006.424 0 .815-.121 1.474-.368 1.95l-.011.022 1.708 1.782.013-.02c.62-.96.946-2.293.946-3.91 0-.083 0-.165-.002-.247z" fill="url(#lobe-icons-meta-8-_R_0_)"></path><path d="M21.344 16.52l-.011.02c-.214.402-.519.67-.917.787l.778 2.462a3.493 3.493 0 00.438-.182 3.558 3.558 0 001.366-1.218l.044-.065.012-.02-1.71-1.784z" fill="url(#lobe-icons-meta-9-_R_0_)"></path><path d="M19.92 17.393c-.262 0-.492-.039-.718-.14l-.798 2.522c.449.153.927.222 1.46.222.492 0 .943-.073 1.352-.215l-.78-2.462c-.167.05-.341.075-.517.073z" fill="url(#lobe-icons-meta-10-_R_0_)"></path><path d="M18.323 16.534l-.014-.017-1.836 1.914.016.017c.637.682 1.246 1.105 1.937 1.337l.797-2.52c-.291-.125-.573-.353-.9-.731z" fill="url(#lobe-icons-meta-11-_R_0_)"></path><path d="M18.309 16.515c-.55-.642-1.232-1.712-2.303-3.44l-1.396-2.336-.011-.02-1.62 2.438.012.02.989 1.668c.959 1.61 1.74 2.774 2.493 3.585l.016.016 1.834-1.914a2.353 2.353 0 01-.014-.017z" fill="url(#lobe-icons-meta-12-_R_0_)"></path><defs><linearGradient id="lobe-icons-meta-0-_R_0_" x1="75.897%" x2="26.312%" y1="89.199%" y2="12.194%"><stop offset=".06%" stop-color="#0867DF"></stop><stop offset="45.39%" stop-color="#0668E1"></stop><stop offset="85.91%" stop-color="#0064E0"></stop></linearGradient><linearGradient id="lobe-icons-meta-1-_R_0_" x1="21.67%" x2="97.068%" y1="75.874%" y2="23.985%"><stop offset="13.23%" stop-color="#0064DF"></stop><stop offset="99.88%" stop-color="#0064E0"></stop></linearGradient><linearGradient id="lobe-icons-meta-2-_R_0_" x1="38.263%" x2="60.895%" y1="89.127%" y2="16.131%"><stop offset="1.47%" stop-color="#0072EC"></stop><stop offset="68.81%" stop-color="#0064DF"></stop></linearGradient><linearGradient id="lobe-icons-meta-3-_R_0_" x1="47.032%" x2="52.15%" y1="90.19%" y2="15.745%"><stop offset="7.31%" stop-color="#007CF6"></stop><stop offset="99.43%" stop-color="#0072EC"></stop></linearGradient><linearGradient id="lobe-icons-meta-4-_R_0_" x1="52.155%" x2="47.591%" y1="58.301%" y2="37.004%"><stop offset="7.31%" stop-color="#007FF9"></stop><stop offset="100%" stop-color="#007CF6"></stop></linearGradient><linearGradient id="lobe-icons-meta-5-_R_0_" x1="37.689%" x2="61.961%" y1="12.502%" y2="63.624%"><stop offset="7.31%" stop-color="#007FF9"></stop><stop offset="100%" stop-color="#0082FB"></stop></linearGradient><linearGradient id="lobe-icons-meta-6-_R_0_" x1="34.808%" x2="62.313%" y1="68.859%" y2="23.174%"><stop offset="27.99%" stop-color="#007FF8"></stop><stop offset="91.41%" stop-color="#0082FB"></stop></linearGradient><linearGradient id="lobe-icons-meta-7-_R_0_" x1="43.762%" x2="57.602%" y1="6.235%" y2="98.514%"><stop offset="0%" stop-color="#0082FB"></stop><stop offset="99.95%" stop-color="#0081FA"></stop></linearGradient><linearGradient id="lobe-icons-meta-8-_R_0_" x1="60.055%" x2="39.88%" y1="4.661%" y2="69.077%"><stop offset="6.19%" stop-color="#0081FA"></stop><stop offset="100%" stop-color="#0080F9"></stop></linearGradient><linearGradient id="lobe-icons-meta-9-_R_0_" x1="30.282%" x2="61.081%" y1="59.32%" y2="33.244%"><stop offset="0%" stop-color="#027AF3"></stop><stop offset="100%" stop-color="#0080F9"></stop></linearGradient><linearGradient id="lobe-icons-meta-10-_R_0_" x1="20.433%" x2="82.112%" y1="50.001%" y2="50.001%"><stop offset="0%" stop-color="#0377EF"></stop><stop offset="99.94%" stop-color="#0279F1"></stop></linearGradient><linearGradient id="lobe-icons-meta-11-_R_0_" x1="40.303%" x2="72.394%" y1="35.298%" y2="57.811%"><stop offset=".19%" stop-color="#0471E9"></stop><stop offset="100%" stop-color="#0377EF"></stop></linearGradient><linearGradient id="lobe-icons-meta-12-_R_0_" x1="32.254%" x2="68.003%" y1="19.719%" y2="84.908%"><stop offset="27.65%" stop-color="#0867DF"></stop><stop offset="100%" stop-color="#0471E9"></stop></linearGradient></defs></svg>',
|
|
6
|
+
xai: '<svg class="le-provider-icon" aria-hidden="true" focusable="false" fill="currentColor" fill-rule="evenodd" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M6.469 8.776L16.512 23h-4.464L2.005 8.776H6.47zm-.004 7.9l2.233 3.164L6.467 23H2l4.465-6.324zM22 2.582V23h-3.659V7.764L22 2.582zM22 1l-9.952 14.095-2.233-3.163L17.533 1H22z"></path></svg>',
|
|
7
|
+
deepseek: '<svg class="le-provider-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M23.748 4.482c-.254-.124-.364.113-.512.234-.051.039-.094.09-.137.136-.372.397-.806.657-1.373.626-.829-.046-1.537.214-2.163.848-.133-.782-.575-1.248-1.247-1.548-.352-.156-.708-.311-.955-.65-.172-.241-.219-.51-.305-.774-.055-.16-.11-.323-.293-.35-.2-.031-.278.136-.356.276-.313.572-.434 1.202-.422 1.84.027 1.436.633 2.58 1.838 3.393.137.093.172.187.129.323-.082.28-.18.552-.266.833-.055.179-.137.217-.329.14a5.526 5.526 0 01-1.736-1.18c-.857-.828-1.631-1.742-2.597-2.458a11.365 11.365 0 00-.689-.471c-.985-.957.13-1.743.388-1.836.27-.098.093-.432-.779-.428-.872.004-1.67.295-2.687.684a3.055 3.055 0 01-.465.137 9.597 9.597 0 00-2.883-.102c-1.885.21-3.39 1.102-4.497 2.623C.082 8.606-.231 10.684.152 12.85c.403 2.284 1.569 4.175 3.36 5.653 1.858 1.533 3.997 2.284 6.438 2.14 1.482-.085 3.133-.284 4.994-1.86.47.234.962.327 1.78.397.63.059 1.236-.03 1.705-.128.735-.156.684-.837.419-.961-2.155-1.004-1.682-.595-2.113-.926 1.096-1.296 2.746-2.642 3.392-7.003.05-.347.007-.565 0-.845-.004-.17.035-.237.23-.256a4.173 4.173 0 001.545-.475c1.396-.763 1.96-2.015 2.093-3.517.02-.23-.004-.467-.247-.588zM11.581 18c-2.089-1.642-3.102-2.183-3.52-2.16-.392.024-.321.471-.235.763.09.288.207.486.371.739.114.167.192.416-.113.603-.673.416-1.842-.14-1.897-.167-1.361-.802-2.5-1.86-3.301-3.307-.774-1.393-1.224-2.887-1.298-4.482-.02-.386.093-.522.477-.592a4.696 4.696 0 011.529-.039c2.132.312 3.946 1.265 5.468 2.774.868.86 1.525 1.887 2.202 2.891.72 1.066 1.494 2.082 2.48 2.914.348.292.625.514.891.677-.802.09-2.14.11-3.054-.614zm1-6.44a.306.306 0 01.415-.287.302.302 0 01.2.288.306.306 0 01-.31.307.303.303 0 01-.304-.308zm3.11 1.596c-.2.081-.399.151-.59.16a1.245 1.245 0 01-.798-.254c-.274-.23-.47-.358-.552-.758a1.73 1.73 0 01.016-.588c.07-.327-.008-.537-.239-.727-.187-.156-.426-.199-.688-.199a.559.559 0 01-.254-.078c-.11-.054-.2-.19-.114-.358.028-.054.16-.186.192-.21.356-.202.767-.136 1.146.016.352.144.618.408 1.001.782.391.451.462.576.685.914.176.265.336.537.445.848.067.195-.019.354-.25.452z" fill="#4D6BFE"></path></svg>',
|
|
8
|
+
kimi: '<svg class="le-provider-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M21.846 0a1.923 1.923 0 110 3.846H20.15a.226.226 0 01-.227-.226V1.923C19.923.861 20.784 0 21.846 0z" fill="#1783FF"></path><path d="M11.065 11.199l7.257-7.2c.137-.136.06-.41-.116-.41H14.3a.164.164 0 00-.117.051l-7.82 7.756c-.122.12-.302.013-.302-.179V3.82c0-.127-.083-.23-.185-.23H3.186c-.103 0-.186.103-.186.23V19.77c0 .128.083.23.186.23h2.69c.103 0 .186-.102.186-.23v-3.25c0-.069.025-.135.069-.178l2.424-2.406a.158.158 0 01.205-.023l6.484 4.772a7.677 7.677 0 003.453 1.283c.108.012.2-.095.2-.23v-3.06c0-.117-.07-.212-.164-.227a5.028 5.028 0 01-2.027-.807l-5.613-4.064c-.117-.078-.132-.279-.028-.381z" fill="currentColor"></path></svg>',
|
|
9
|
+
glm: '<svg class="le-provider-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M11.991 23.503a.24.24 0 00-.244.248.24.24 0 00.244.249.24.24 0 00.245-.249.24.24 0 00-.22-.247l-.025-.001zM9.671 5.365a1.697 1.697 0 011.099 2.132l-.071.172-.016.04-.018.054c-.07.16-.104.32-.104.498-.035.71.47 1.279 1.186 1.314h.366c1.309.053 2.338 1.173 2.286 2.523-.052 1.332-1.152 2.38-2.478 2.327h-.174c-.715.018-1.274.64-1.239 1.368 0 .124.018.23.053.337.209.373.54.658.96.8.75.23 1.517-.125 1.9-.782l.018-.035c.402-.64 1.17-.96 1.92-.711.854.284 1.378 1.226 1.099 2.167a1.661 1.661 0 01-2.077 1.102 1.711 1.711 0 01-.907-.711l-.017-.035c-.2-.323-.463-.58-.851-.711l-.056-.018a1.646 1.646 0 00-1.954.746 1.66 1.66 0 01-1.065.764 1.677 1.677 0 01-1.989-1.279c-.209-.906.332-1.83 1.257-2.043a1.51 1.51 0 01.296-.035h.018c.68-.071 1.151-.622 1.116-1.333a1.307 1.307 0 00-.227-.693 2.515 2.515 0 01-.366-1.403 2.39 2.39 0 01.366-1.208c.14-.195.21-.444.227-.693.018-.71-.506-1.261-1.186-1.332l-.07-.018a1.43 1.43 0 01-.299-.07l-.05-.019a1.7 1.7 0 01-1.047-2.114 1.68 1.68 0 012.094-1.101zm-5.575 10.11c.26-.264.639-.367.994-.27.355.096.633.379.728.74.095.362-.007.748-.267 1.013-.402.41-1.053.41-1.455 0a1.062 1.062 0 010-1.482zm14.845-.294c.359-.09.738.024.992.297.254.274.344.665.237 1.025-.107.36-.396.634-.756.718-.551.128-1.1-.22-1.23-.781a1.05 1.05 0 01.757-1.26zm-.064-4.39c.314.32.49.753.49 1.206 0 .452-.176.886-.49 1.206-.315.32-.74.5-1.185.5-.444 0-.87-.18-1.184-.5a1.727 1.727 0 010-2.412 1.654 1.654 0 012.369 0zm-11.243.163c.364.484.447 1.128.218 1.691a1.665 1.665 0 01-2.188.923c-.855-.36-1.26-1.358-.907-2.228a1.68 1.68 0 011.33-1.038c.593-.08 1.183.169 1.547.652zm11.545-4.221c.368 0 .708.2.892.524.184.324.184.724 0 1.048a1.026 1.026 0 01-.892.524c-.568 0-1.03-.47-1.03-1.048 0-.579.462-1.048 1.03-1.048zm-14.358 0c.368 0 .707.2.891.524.184.324.184.724 0 1.048a1.026 1.026 0 01-.891.524c-.569 0-1.03-.47-1.03-1.048 0-.579.461-1.048 1.03-1.048zm10.031-1.475c.925 0 1.675.764 1.675 1.706s-.75 1.705-1.675 1.705-1.674-.763-1.674-1.705c0-.942.75-1.706 1.674-1.706zm-2.626-.684c.362-.082.653-.356.761-.718a1.062 1.062 0 00-.238-1.028 1.017 1.017 0 00-.996-.294c-.547.14-.881.7-.752 1.257.13.558.675.907 1.225.783zm0 16.876c.359-.087.644-.36.75-.72a1.062 1.062 0 00-.237-1.019 1.018 1.018 0 00-.985-.301 1.037 1.037 0 00-.762.717c-.108.361-.017.754.239 1.028.245.263.606.377.953.305l.043-.01zM17.19 3.5a.631.631 0 00.628-.64c0-.355-.279-.64-.628-.64a.631.631 0 00-.628.64c0 .355.28.64.628.64zm-10.38 0a.631.631 0 00.628-.64c0-.355-.28-.64-.628-.64a.631.631 0 00-.628.64c0 .355.279.64.628.64zm-5.182 7.852a.631.631 0 00-.628.64c0 .354.28.639.628.639a.63.63 0 00.627-.606l.001-.034a.62.62 0 00-.628-.64zm5.182 9.13a.631.631 0 00-.628.64c0 .355.279.64.628.64a.631.631 0 00.628-.64c0-.355-.28-.64-.628-.64zm10.38.018a.631.631 0 00-.628.64c0 .355.28.64.628.64a.631.631 0 00.628-.64c0-.355-.279-.64-.628-.64zm5.182-9.148a.631.631 0 00-.628.64c0 .354.279.639.628.639a.631.631 0 00.628-.64c0-.355-.28-.64-.628-.64zm-.384-4.992a.24.24 0 00.244-.249.24.24 0 00-.244-.249.24.24 0 00-.244.249c0 .142.122.249.244.249zM11.991.497a.24.24 0 00.245-.248A.24.24 0 0011.99 0a.24.24 0 00-.244.249c0 .133.108.236.223.247l.021.001zM2.011 6.36a.24.24 0 00.245-.249.24.24 0 00-.244-.249.24.24 0 00-.244.249.24.24 0 00.244.249zm0 11.263a.24.24 0 00-.243.248.24.24 0 00.244.249.24.24 0 00.244-.249.252.252 0 00-.244-.248zm19.995-.018a.24.24 0 00-.245.248.24.24 0 00.245.25.24.24 0 00.244-.25.252.252 0 00-.244-.248z" fill="#3859FF" fill-rule="nonzero"></path></svg>',
|
|
10
|
+
};
|
|
@@ -92,3 +92,6 @@ export declare function templateChecklist(template: StarterTemplate, name: strin
|
|
|
92
92
|
/** Creates a new agent from the template, with its whole setup, under the
|
|
93
93
|
* first free name, so the same template can be used more than once. */
|
|
94
94
|
export declare function createFromTemplate(id: string, deps: TemplateCreateDeps | LegacyTemplateCreateDeps): Promise<CreatedTemplateAgent>;
|
|
95
|
+
/** createFromTemplate for a template that isn't one of the built-in ones:
|
|
96
|
+
* a workflow planned from a description (web/workflow-admin.ts). */
|
|
97
|
+
export declare function createFromTemplateObject(template: StarterTemplate, deps: TemplateCreateDeps): Promise<CreatedTemplateAgent>;
|