@folotoy/folotoy-openclaw-plugin 0.2.1 → 0.3.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@folotoy/folotoy-openclaw-plugin",
3
- "version": "0.2.1",
3
+ "version": "0.3.1",
4
4
  "description": "Empower your FoloToy with OpenClaw AI capabilities.",
5
5
  "keywords": [
6
6
  "folotoy",
package/src/index.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { OpenClawPluginApi, ChannelPlugin } from 'openclaw/plugin-sdk/core'
2
- import { resolveCredentials, createMqttClient, buildInboundTopic, buildOutboundTopic } from './mqtt.js'
2
+ import { resolveCredentials, createMqttClient, buildInboundTopic, buildOutboundTopic, buildNotificationTopic } from './mqtt.js'
3
3
  import { DEFAULT_MQTT_HOST, DEFAULT_MQTT_PORT, flatToPluginConfig } from './config.js'
4
4
  import type { FlatChannelConfig } from './config.js'
5
5
  import type { MqttClient } from 'mqtt'
@@ -16,6 +16,36 @@ type OutboundMessage = {
16
16
  outParams: { content: string; recording_id: number; order: number; is_finished: boolean }
17
17
  }
18
18
 
19
+ type NotificationMessage = {
20
+ msgId: number
21
+ identifier: 'send_notification'
22
+ outParams: { text: string }
23
+ }
24
+
25
+ /** Pick a soothing acknowledgment that loosely matches the input. */
26
+ function pickSoothingReply(text: string): string {
27
+ const t = text.toLowerCase()
28
+
29
+ if (/难过|伤心|哭|不开心|sad|upset|cry/.test(t))
30
+ return '抱抱你,我在听呢,让我想想怎么帮你。'
31
+ if (/害怕|恐惧|怕|scared|afraid/.test(t))
32
+ return '别怕,有我在呢,让我想一想。'
33
+ if (/生气|愤怒|烦|angry|mad/.test(t))
34
+ return '我理解你的感受,让我来帮你想想办法。'
35
+ if (/累|疲|困|tired|exhausted/.test(t))
36
+ return '辛苦了,休息一下,我来帮你想。'
37
+ if (/无聊|没意思|bored/.test(t))
38
+ return '我来陪你聊聊吧,让我想想。'
39
+ if (/谢|感谢|thank/.test(t))
40
+ return '不客气呀,让我想想还能帮你什么。'
41
+ if (/你好|嗨|hello|hi|hey/.test(t))
42
+ return '你好呀!让我想想怎么回答你。'
43
+ if (/帮|help|怎么办/.test(t))
44
+ return '没问题,让我帮你想想办法。'
45
+
46
+ return '好的,让我想一想,马上回复你。'
47
+ }
48
+
19
49
  // Per-account MQTT clients and msgId counters
20
50
  const activeClients = new Map<string, { client: MqttClient; toy_sn: string; nextMsgId: number }>()
21
51
 
@@ -104,7 +134,16 @@ const folotoyChannel: ChannelPlugin<FlatChannelConfig> = {
104
134
  if (msg.identifier !== 'chat_input' || typeof msg.inputParams?.text !== 'string') return
105
135
 
106
136
  const { msgId, inputParams: { text, recording_id } } = msg
107
- let order = 0
137
+ let order = 1
138
+
139
+ // Send a quick soothing acknowledgment before AI processing (order=1).
140
+ // AI replies continue from order=2.
141
+ const ackMsg: OutboundMessage = {
142
+ msgId,
143
+ identifier: 'chat_output',
144
+ outParams: { content: pickSoothingReply(text), recording_id, order, is_finished: false },
145
+ }
146
+ client.publish(outboundTopic, JSON.stringify(ackMsg))
108
147
 
109
148
  const inboundCtx = channelRuntime.reply.finalizeInboundContext({
110
149
  Body: text,
@@ -172,9 +211,9 @@ const folotoyChannel: ChannelPlugin<FlatChannelConfig> = {
172
211
 
173
212
  const outboundTopic = buildOutboundTopic(entry.toy_sn)
174
213
  const msgId = entry.nextMsgId++
175
- const outMsg: OutboundMessage = {
214
+ const outMsg = {
176
215
  msgId,
177
- identifier: 'chat_output',
216
+ identifier: 'chat_output' as const,
178
217
  outParams: { content: text },
179
218
  }
180
219
  entry.client.publish(outboundTopic, JSON.stringify(outMsg))
@@ -183,6 +222,22 @@ const folotoyChannel: ChannelPlugin<FlatChannelConfig> = {
183
222
  },
184
223
  }
185
224
 
225
+ export function sendNotification({ text, accountId }: { text: string; accountId?: string }) {
226
+ const key = accountId ?? 'default'
227
+ const entry = activeClients.get(key)
228
+ if (!entry) throw new Error(`No active MQTT client for account "${key}"`)
229
+
230
+ const notificationTopic = buildNotificationTopic(entry.toy_sn)
231
+ const msgId = entry.nextMsgId++
232
+ const notifMsg: NotificationMessage = {
233
+ msgId,
234
+ identifier: 'send_notification',
235
+ outParams: { text },
236
+ }
237
+ entry.client.publish(notificationTopic, JSON.stringify(notifMsg))
238
+ return { channel: 'folotoy', messageId: String(msgId) }
239
+ }
240
+
186
241
  export default (api: OpenClawPluginApi) => {
187
242
  api.registerChannel({ plugin: folotoyChannel })
188
243
  }
package/src/mqtt.ts CHANGED
@@ -52,6 +52,10 @@ export function buildOutboundTopic(toy_sn: string): string {
52
52
  return `/openapi/folotoy/${toy_sn}/thing/command/callAck`
53
53
  }
54
54
 
55
+ export function buildNotificationTopic(toy_sn: string): string {
56
+ return `/openapi/folotoy/${toy_sn}/thing/event/post`
57
+ }
58
+
55
59
  export async function createMqttClient(config: PluginConfig, credentials: MqttCredentials): Promise<MqttClient> {
56
60
  const { host, port } = config.mqtt
57
61
  const { username, password } = credentials