@alfe.ai/openclaw 0.0.45 → 0.2.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.
- package/README.md +5 -0
- package/dist/plugin2.cjs +100 -3
- package/dist/plugin2.js +100 -3
- package/openclaw.plugin.json +2 -1
- package/package.json +13 -3
package/README.md
CHANGED
|
@@ -73,3 +73,8 @@ Register tools **before** this guard so they're available for CLI introspection.
|
|
|
73
73
|
Integration management (install, remove, configure, health) is handled by
|
|
74
74
|
the gateway service directly — this plugin does not process integration
|
|
75
75
|
commands.
|
|
76
|
+
|
|
77
|
+
## Links
|
|
78
|
+
|
|
79
|
+
- 🌐 Website: <https://alfe.ai>
|
|
80
|
+
- 📚 Docs: <https://docs.alfe.ai>
|
package/dist/plugin2.cjs
CHANGED
|
@@ -3089,6 +3089,13 @@ async function registerWithDaemon(client, log, pluginName = "@alfe.ai/openclaw")
|
|
|
3089
3089
|
const pkg = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href)("../package.json");
|
|
3090
3090
|
const DEFAULT_SOCKET_PATH = (0, node_path.join)((0, node_os.homedir)(), ".alfe", "gateway.sock");
|
|
3091
3091
|
let ipcClient = null;
|
|
3092
|
+
/**
|
|
3093
|
+
* The local AI proxy (packages/ai-proxy-local) runs alongside the daemon on a
|
|
3094
|
+
* fixed loopback port in every runtime mode (managed VM / docker / self-hosted),
|
|
3095
|
+
* injects the agent's Alfe key, and forwards arbitrary paths to the cloud AI
|
|
3096
|
+
* proxy. openclaw-chat hardcodes the same host for /__alfe/set-identity.
|
|
3097
|
+
*/
|
|
3098
|
+
const LOCAL_AI_PROXY_URL = process.env.ALFE_AI_PROXY_URL ?? "http://127.0.0.1:18193";
|
|
3092
3099
|
function ok(result) {
|
|
3093
3100
|
return { content: [{
|
|
3094
3101
|
type: "text",
|
|
@@ -3181,6 +3188,95 @@ function buildIntegrationTools(client) {
|
|
|
3181
3188
|
})
|
|
3182
3189
|
];
|
|
3183
3190
|
}
|
|
3191
|
+
function buildVoiceTools(client) {
|
|
3192
|
+
return [
|
|
3193
|
+
defineTool({
|
|
3194
|
+
name: "list_voices",
|
|
3195
|
+
description: "List the available voices this agent can speak with (the ElevenLabs catalogue). Use this to pick or confirm a voice before calling set_voice with the chosen id.",
|
|
3196
|
+
parameters: Type.Object({}),
|
|
3197
|
+
handler: async () => {
|
|
3198
|
+
const { voices } = await client.listVoices();
|
|
3199
|
+
return { voices: voices.map((v) => ({
|
|
3200
|
+
id: v.id,
|
|
3201
|
+
name: v.name,
|
|
3202
|
+
description: v.description,
|
|
3203
|
+
labels: v.labels,
|
|
3204
|
+
category: v.category,
|
|
3205
|
+
previewUrl: v.previewUrl
|
|
3206
|
+
})) };
|
|
3207
|
+
}
|
|
3208
|
+
}),
|
|
3209
|
+
defineTool({
|
|
3210
|
+
name: "set_voice",
|
|
3211
|
+
description: "Change this agent's OWN voice. Pass a `voiceId` from list_voices. Optionally set `enabled` to turn voice on/off. Returns the updated voice config.",
|
|
3212
|
+
parameters: Type.Object({
|
|
3213
|
+
voiceId: Type.String({ description: "The ElevenLabs voice id to use, from list_voices (e.g. the `id` field)." }),
|
|
3214
|
+
enabled: Type.Optional(Type.Boolean({ description: "Enable or disable voice. Omit to leave the current on/off state unchanged." }))
|
|
3215
|
+
}),
|
|
3216
|
+
handler: async (params) => {
|
|
3217
|
+
const voiceId = params.voiceId;
|
|
3218
|
+
const enabled = params.enabled;
|
|
3219
|
+
return {
|
|
3220
|
+
updated: true,
|
|
3221
|
+
voiceConfig: (await client.updateSelf({ voiceConfig: {
|
|
3222
|
+
voiceId,
|
|
3223
|
+
...enabled === void 0 ? {} : { enabled }
|
|
3224
|
+
} })).voiceConfig
|
|
3225
|
+
};
|
|
3226
|
+
}
|
|
3227
|
+
}),
|
|
3228
|
+
defineTool({
|
|
3229
|
+
name: "generate_image",
|
|
3230
|
+
description: "Generate an image from a text prompt. Returns a URL to the generated PNG. To show the image to the user, embed it in your reply as markdown: . Optional `model` picks the image model (default gpt-image-1).",
|
|
3231
|
+
parameters: Type.Object({
|
|
3232
|
+
prompt: Type.String({ description: "Text description of the image to generate." }),
|
|
3233
|
+
model: Type.Optional(Type.String({ description: "Image model id (default \"gpt-image-1\"). Others may be available, e.g. dall-e-3." })),
|
|
3234
|
+
size: Type.Optional(Type.String({ description: "Image size, e.g. \"1024x1024\" (provider-dependent)." })),
|
|
3235
|
+
quality: Type.Optional(Type.String({ description: "Image quality hint (provider-dependent)." }))
|
|
3236
|
+
}),
|
|
3237
|
+
handler: async (params) => {
|
|
3238
|
+
const prompt = params.prompt;
|
|
3239
|
+
const model = params.model ?? "gpt-image-1";
|
|
3240
|
+
const size = params.size;
|
|
3241
|
+
const quality = params.quality;
|
|
3242
|
+
const genRes = await fetch(`${LOCAL_AI_PROXY_URL}/v1/images/generations`, {
|
|
3243
|
+
method: "POST",
|
|
3244
|
+
headers: { "Content-Type": "application/json" },
|
|
3245
|
+
body: JSON.stringify({
|
|
3246
|
+
model,
|
|
3247
|
+
prompt,
|
|
3248
|
+
...size ? { size } : {},
|
|
3249
|
+
...quality ? { quality } : {}
|
|
3250
|
+
})
|
|
3251
|
+
});
|
|
3252
|
+
const genJson = await genRes.json().catch(() => ({}));
|
|
3253
|
+
if (!genRes.ok) throw new Error(`image generation failed (${String(genRes.status)}): ${genJson.message ?? genJson.error ?? "unknown error"}`);
|
|
3254
|
+
const b64 = genJson.data?.[0]?.b64_json;
|
|
3255
|
+
if (!b64) throw new Error("image generation returned no image data");
|
|
3256
|
+
const buffer = Buffer.from(b64, "base64");
|
|
3257
|
+
const filename = `generated-image-${String(Date.now())}.png`;
|
|
3258
|
+
const { attachments } = await client.presignAttachments([{
|
|
3259
|
+
filename,
|
|
3260
|
+
mimeType: "image/png",
|
|
3261
|
+
size: buffer.length
|
|
3262
|
+
}]);
|
|
3263
|
+
if (attachments.length === 0) throw new Error("failed to presign upload for the generated image");
|
|
3264
|
+
const att = attachments[0];
|
|
3265
|
+
const putRes = await fetch(att.uploadUrl, {
|
|
3266
|
+
method: "PUT",
|
|
3267
|
+
headers: { "Content-Type": "image/png" },
|
|
3268
|
+
body: buffer
|
|
3269
|
+
});
|
|
3270
|
+
if (!putRes.ok) throw new Error(`failed to upload the generated image (${String(putRes.status)})`);
|
|
3271
|
+
return {
|
|
3272
|
+
imageUrl: att.downloadUrl,
|
|
3273
|
+
model,
|
|
3274
|
+
instruction: "Show this image to the user by including it in your reply as markdown: ."
|
|
3275
|
+
};
|
|
3276
|
+
}
|
|
3277
|
+
})
|
|
3278
|
+
];
|
|
3279
|
+
}
|
|
3184
3280
|
const plugin = {
|
|
3185
3281
|
id: "@alfe.ai/openclaw",
|
|
3186
3282
|
name: "Alfe OpenClaw Plugin",
|
|
@@ -3195,12 +3291,13 @@ const plugin = {
|
|
|
3195
3291
|
log.warn(`Integration tools not registered — config not available: ${err.message}`);
|
|
3196
3292
|
}
|
|
3197
3293
|
if (cfg) {
|
|
3198
|
-
const
|
|
3294
|
+
const client = new _alfe_ai_agent_api_client.AgentApiClient({
|
|
3199
3295
|
apiKey: cfg.apiKey,
|
|
3200
3296
|
apiUrl: cfg.apiUrl
|
|
3201
|
-
})
|
|
3297
|
+
});
|
|
3298
|
+
const tools = [...buildIntegrationTools(client), ...buildVoiceTools(client)];
|
|
3202
3299
|
for (const tool of tools) api.registerTool(tool);
|
|
3203
|
-
log.info(`Registered ${String(tools.length)}
|
|
3300
|
+
log.info(`Registered ${String(tools.length)} agent tools: ${tools.map((t) => t.name).join(", ")}`);
|
|
3204
3301
|
}
|
|
3205
3302
|
const startDaemonIpc = () => {
|
|
3206
3303
|
if (globalThis.__alfeOpenclawPluginActivated === true) {
|
package/dist/plugin2.js
CHANGED
|
@@ -3090,6 +3090,13 @@ async function registerWithDaemon(client, log, pluginName = "@alfe.ai/openclaw")
|
|
|
3090
3090
|
const pkg = createRequire(import.meta.url)("../package.json");
|
|
3091
3091
|
const DEFAULT_SOCKET_PATH = join(homedir(), ".alfe", "gateway.sock");
|
|
3092
3092
|
let ipcClient = null;
|
|
3093
|
+
/**
|
|
3094
|
+
* The local AI proxy (packages/ai-proxy-local) runs alongside the daemon on a
|
|
3095
|
+
* fixed loopback port in every runtime mode (managed VM / docker / self-hosted),
|
|
3096
|
+
* injects the agent's Alfe key, and forwards arbitrary paths to the cloud AI
|
|
3097
|
+
* proxy. openclaw-chat hardcodes the same host for /__alfe/set-identity.
|
|
3098
|
+
*/
|
|
3099
|
+
const LOCAL_AI_PROXY_URL = process.env.ALFE_AI_PROXY_URL ?? "http://127.0.0.1:18193";
|
|
3093
3100
|
function ok(result) {
|
|
3094
3101
|
return { content: [{
|
|
3095
3102
|
type: "text",
|
|
@@ -3182,6 +3189,95 @@ function buildIntegrationTools(client) {
|
|
|
3182
3189
|
})
|
|
3183
3190
|
];
|
|
3184
3191
|
}
|
|
3192
|
+
function buildVoiceTools(client) {
|
|
3193
|
+
return [
|
|
3194
|
+
defineTool({
|
|
3195
|
+
name: "list_voices",
|
|
3196
|
+
description: "List the available voices this agent can speak with (the ElevenLabs catalogue). Use this to pick or confirm a voice before calling set_voice with the chosen id.",
|
|
3197
|
+
parameters: Type.Object({}),
|
|
3198
|
+
handler: async () => {
|
|
3199
|
+
const { voices } = await client.listVoices();
|
|
3200
|
+
return { voices: voices.map((v) => ({
|
|
3201
|
+
id: v.id,
|
|
3202
|
+
name: v.name,
|
|
3203
|
+
description: v.description,
|
|
3204
|
+
labels: v.labels,
|
|
3205
|
+
category: v.category,
|
|
3206
|
+
previewUrl: v.previewUrl
|
|
3207
|
+
})) };
|
|
3208
|
+
}
|
|
3209
|
+
}),
|
|
3210
|
+
defineTool({
|
|
3211
|
+
name: "set_voice",
|
|
3212
|
+
description: "Change this agent's OWN voice. Pass a `voiceId` from list_voices. Optionally set `enabled` to turn voice on/off. Returns the updated voice config.",
|
|
3213
|
+
parameters: Type.Object({
|
|
3214
|
+
voiceId: Type.String({ description: "The ElevenLabs voice id to use, from list_voices (e.g. the `id` field)." }),
|
|
3215
|
+
enabled: Type.Optional(Type.Boolean({ description: "Enable or disable voice. Omit to leave the current on/off state unchanged." }))
|
|
3216
|
+
}),
|
|
3217
|
+
handler: async (params) => {
|
|
3218
|
+
const voiceId = params.voiceId;
|
|
3219
|
+
const enabled = params.enabled;
|
|
3220
|
+
return {
|
|
3221
|
+
updated: true,
|
|
3222
|
+
voiceConfig: (await client.updateSelf({ voiceConfig: {
|
|
3223
|
+
voiceId,
|
|
3224
|
+
...enabled === void 0 ? {} : { enabled }
|
|
3225
|
+
} })).voiceConfig
|
|
3226
|
+
};
|
|
3227
|
+
}
|
|
3228
|
+
}),
|
|
3229
|
+
defineTool({
|
|
3230
|
+
name: "generate_image",
|
|
3231
|
+
description: "Generate an image from a text prompt. Returns a URL to the generated PNG. To show the image to the user, embed it in your reply as markdown: . Optional `model` picks the image model (default gpt-image-1).",
|
|
3232
|
+
parameters: Type.Object({
|
|
3233
|
+
prompt: Type.String({ description: "Text description of the image to generate." }),
|
|
3234
|
+
model: Type.Optional(Type.String({ description: "Image model id (default \"gpt-image-1\"). Others may be available, e.g. dall-e-3." })),
|
|
3235
|
+
size: Type.Optional(Type.String({ description: "Image size, e.g. \"1024x1024\" (provider-dependent)." })),
|
|
3236
|
+
quality: Type.Optional(Type.String({ description: "Image quality hint (provider-dependent)." }))
|
|
3237
|
+
}),
|
|
3238
|
+
handler: async (params) => {
|
|
3239
|
+
const prompt = params.prompt;
|
|
3240
|
+
const model = params.model ?? "gpt-image-1";
|
|
3241
|
+
const size = params.size;
|
|
3242
|
+
const quality = params.quality;
|
|
3243
|
+
const genRes = await fetch(`${LOCAL_AI_PROXY_URL}/v1/images/generations`, {
|
|
3244
|
+
method: "POST",
|
|
3245
|
+
headers: { "Content-Type": "application/json" },
|
|
3246
|
+
body: JSON.stringify({
|
|
3247
|
+
model,
|
|
3248
|
+
prompt,
|
|
3249
|
+
...size ? { size } : {},
|
|
3250
|
+
...quality ? { quality } : {}
|
|
3251
|
+
})
|
|
3252
|
+
});
|
|
3253
|
+
const genJson = await genRes.json().catch(() => ({}));
|
|
3254
|
+
if (!genRes.ok) throw new Error(`image generation failed (${String(genRes.status)}): ${genJson.message ?? genJson.error ?? "unknown error"}`);
|
|
3255
|
+
const b64 = genJson.data?.[0]?.b64_json;
|
|
3256
|
+
if (!b64) throw new Error("image generation returned no image data");
|
|
3257
|
+
const buffer = Buffer.from(b64, "base64");
|
|
3258
|
+
const filename = `generated-image-${String(Date.now())}.png`;
|
|
3259
|
+
const { attachments } = await client.presignAttachments([{
|
|
3260
|
+
filename,
|
|
3261
|
+
mimeType: "image/png",
|
|
3262
|
+
size: buffer.length
|
|
3263
|
+
}]);
|
|
3264
|
+
if (attachments.length === 0) throw new Error("failed to presign upload for the generated image");
|
|
3265
|
+
const att = attachments[0];
|
|
3266
|
+
const putRes = await fetch(att.uploadUrl, {
|
|
3267
|
+
method: "PUT",
|
|
3268
|
+
headers: { "Content-Type": "image/png" },
|
|
3269
|
+
body: buffer
|
|
3270
|
+
});
|
|
3271
|
+
if (!putRes.ok) throw new Error(`failed to upload the generated image (${String(putRes.status)})`);
|
|
3272
|
+
return {
|
|
3273
|
+
imageUrl: att.downloadUrl,
|
|
3274
|
+
model,
|
|
3275
|
+
instruction: "Show this image to the user by including it in your reply as markdown: ."
|
|
3276
|
+
};
|
|
3277
|
+
}
|
|
3278
|
+
})
|
|
3279
|
+
];
|
|
3280
|
+
}
|
|
3185
3281
|
const plugin = {
|
|
3186
3282
|
id: "@alfe.ai/openclaw",
|
|
3187
3283
|
name: "Alfe OpenClaw Plugin",
|
|
@@ -3196,12 +3292,13 @@ const plugin = {
|
|
|
3196
3292
|
log.warn(`Integration tools not registered — config not available: ${err.message}`);
|
|
3197
3293
|
}
|
|
3198
3294
|
if (cfg) {
|
|
3199
|
-
const
|
|
3295
|
+
const client = new AgentApiClient({
|
|
3200
3296
|
apiKey: cfg.apiKey,
|
|
3201
3297
|
apiUrl: cfg.apiUrl
|
|
3202
|
-
})
|
|
3298
|
+
});
|
|
3299
|
+
const tools = [...buildIntegrationTools(client), ...buildVoiceTools(client)];
|
|
3203
3300
|
for (const tool of tools) api.registerTool(tool);
|
|
3204
|
-
log.info(`Registered ${String(tools.length)}
|
|
3301
|
+
log.info(`Registered ${String(tools.length)} agent tools: ${tools.map((t) => t.name).join(", ")}`);
|
|
3205
3302
|
}
|
|
3206
3303
|
const startDaemonIpc = () => {
|
|
3207
3304
|
if (globalThis.__alfeOpenclawPluginActivated === true) {
|
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alfe.ai/openclaw",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "OpenClaw plugin for Alfe — connects to local gateway daemon via IPC for integration management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -26,8 +26,8 @@
|
|
|
26
26
|
"@auriclabs/logger": "^0.1.1",
|
|
27
27
|
"@sinclair/typebox": "^0.34.48",
|
|
28
28
|
"zod": "^4.1.5",
|
|
29
|
-
"@alfe.ai/agent-api-client": "^0.
|
|
30
|
-
"@alfe.ai/config": "^0.
|
|
29
|
+
"@alfe.ai/agent-api-client": "^0.4.0",
|
|
30
|
+
"@alfe.ai/config": "^0.2.0"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
33
|
"openclaw": ">=2026.3.0"
|
|
@@ -42,6 +42,16 @@
|
|
|
42
42
|
"openclaw.plugin.json"
|
|
43
43
|
],
|
|
44
44
|
"license": "UNLICENSED",
|
|
45
|
+
"homepage": "https://alfe.ai",
|
|
46
|
+
"author": "Alfe (https://alfe.ai)",
|
|
47
|
+
"keywords": [
|
|
48
|
+
"alfe",
|
|
49
|
+
"ai-agents",
|
|
50
|
+
"agent",
|
|
51
|
+
"llm",
|
|
52
|
+
"openclaw",
|
|
53
|
+
"plugin"
|
|
54
|
+
],
|
|
45
55
|
"scripts": {
|
|
46
56
|
"build": "tsdown",
|
|
47
57
|
"dev": "tsdown --watch",
|