@alfe.ai/openclaw 0.1.0 → 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/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",
@@ -3182,40 +3189,93 @@ function buildIntegrationTools(client) {
3182
3189
  ];
3183
3190
  }
3184
3191
  function buildVoiceTools(client) {
3185
- return [defineTool({
3186
- name: "list_voices",
3187
- 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.",
3188
- parameters: Type.Object({}),
3189
- handler: async () => {
3190
- const { voices } = await client.listVoices();
3191
- return { voices: voices.map((v) => ({
3192
- id: v.id,
3193
- name: v.name,
3194
- description: v.description,
3195
- labels: v.labels,
3196
- category: v.category,
3197
- previewUrl: v.previewUrl
3198
- })) };
3199
- }
3200
- }), defineTool({
3201
- name: "set_voice",
3202
- 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.",
3203
- parameters: Type.Object({
3204
- voiceId: Type.String({ description: "The ElevenLabs voice id to use, from list_voices (e.g. the `id` field)." }),
3205
- enabled: Type.Optional(Type.Boolean({ description: "Enable or disable voice. Omit to leave the current on/off state unchanged." }))
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
+ }
3206
3208
  }),
3207
- handler: async (params) => {
3208
- const voiceId = params.voiceId;
3209
- const enabled = params.enabled;
3210
- return {
3211
- updated: true,
3212
- voiceConfig: (await client.updateSelf({ voiceConfig: {
3213
- voiceId,
3214
- ...enabled === void 0 ? {} : { enabled }
3215
- } })).voiceConfig
3216
- };
3217
- }
3218
- })];
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: ![description](imageUrl). 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: ![image](imageUrl)."
3275
+ };
3276
+ }
3277
+ })
3278
+ ];
3219
3279
  }
3220
3280
  const plugin = {
3221
3281
  id: "@alfe.ai/openclaw",
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",
@@ -3183,40 +3190,93 @@ function buildIntegrationTools(client) {
3183
3190
  ];
3184
3191
  }
3185
3192
  function buildVoiceTools(client) {
3186
- return [defineTool({
3187
- name: "list_voices",
3188
- 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.",
3189
- parameters: Type.Object({}),
3190
- handler: async () => {
3191
- const { voices } = await client.listVoices();
3192
- return { voices: voices.map((v) => ({
3193
- id: v.id,
3194
- name: v.name,
3195
- description: v.description,
3196
- labels: v.labels,
3197
- category: v.category,
3198
- previewUrl: v.previewUrl
3199
- })) };
3200
- }
3201
- }), defineTool({
3202
- name: "set_voice",
3203
- 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.",
3204
- parameters: Type.Object({
3205
- voiceId: Type.String({ description: "The ElevenLabs voice id to use, from list_voices (e.g. the `id` field)." }),
3206
- enabled: Type.Optional(Type.Boolean({ description: "Enable or disable voice. Omit to leave the current on/off state unchanged." }))
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
+ }
3207
3209
  }),
3208
- handler: async (params) => {
3209
- const voiceId = params.voiceId;
3210
- const enabled = params.enabled;
3211
- return {
3212
- updated: true,
3213
- voiceConfig: (await client.updateSelf({ voiceConfig: {
3214
- voiceId,
3215
- ...enabled === void 0 ? {} : { enabled }
3216
- } })).voiceConfig
3217
- };
3218
- }
3219
- })];
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: ![description](imageUrl). 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: ![image](imageUrl)."
3276
+ };
3277
+ }
3278
+ })
3279
+ ];
3220
3280
  }
3221
3281
  const plugin = {
3222
3282
  id: "@alfe.ai/openclaw",
@@ -11,7 +11,8 @@
11
11
  "update_integration_config",
12
12
  "install_integration",
13
13
  "remove_integration",
14
- "browse_integration_registry"
14
+ "browse_integration_registry",
15
+ "generate_image"
15
16
  ]
16
17
  },
17
18
  "configSchema": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alfe.ai/openclaw",
3
- "version": "0.1.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",