@stagewhisper/stagewhisper 0.37.0 → 0.38.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.
@@ -2,7 +2,7 @@
2
2
  "id": "stagewhisper",
3
3
  "name": "StageWhisper",
4
4
  "description": "Turn live call moments into assistant tasks via StageWhisper",
5
- "version": "0.37.0",
5
+ "version": "0.38.0",
6
6
  "channels": [
7
7
  "stagewhisper"
8
8
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stagewhisper/stagewhisper",
3
- "version": "0.37.0",
3
+ "version": "0.38.0",
4
4
  "type": "module",
5
5
  "description": "OpenClaw channel plugin that connects StageWhisper live calls to your AI assistant",
6
6
  "license": "MIT",
package/src/channel.ts CHANGED
@@ -147,7 +147,19 @@ export const stagewhisperPlugin = createChatChannelPlugin<StageWhisperAccount>(
147
147
  threading: { topLevelReplyToMode: "reply" },
148
148
 
149
149
  outbound: {
150
- base: { deliveryMode: "direct" },
150
+ base: {
151
+ deliveryMode: "direct",
152
+ resolveTarget: (params: {
153
+ cfg?: OpenClawConfig;
154
+ to?: string;
155
+ allowFrom?: string[];
156
+ accountId?: string | null;
157
+ mode?: string;
158
+ }) => {
159
+ if (!params.to) return { ok: false as const, error: new Error("No delivery target") };
160
+ return { ok: true as const, to: params.to };
161
+ },
162
+ },
151
163
  attachedResults: {
152
164
  channel: "stagewhisper",
153
165
  sendText: async (ctx) => {
@@ -158,7 +170,10 @@ export const stagewhisperPlugin = createChatChannelPlugin<StageWhisperAccount>(
158
170
  account.relayToken,
159
171
  );
160
172
 
161
- const taskId = ctx.threadId as string | undefined;
173
+ const target = (ctx as Record<string, unknown>).to as string | undefined;
174
+ const threadId = ctx.threadId as string | undefined;
175
+ const raw = target ?? threadId ?? "";
176
+ const taskId = raw.replace(/^sw-task-/, "");
162
177
  if (!taskId) {
163
178
  return { messageId: `sw-noop-${Date.now()}`, ok: true };
164
179
  }
package/src/service.ts CHANGED
@@ -78,7 +78,7 @@ export function createRelayService(api: OpenClawPluginApi) {
78
78
  }
79
79
 
80
80
  function isTestTask(task: TaskPayload): boolean {
81
- return task.action_type === "test";
81
+ return task.action_type === "connectivity_test";
82
82
  }
83
83
 
84
84
  async function updateStatus(
@@ -136,12 +136,10 @@ export function createRelayService(api: OpenClawPluginApi) {
136
136
  return null;
137
137
  }
138
138
 
139
- async function handleTask(
139
+ async function handleNormalTask(
140
140
  task: TaskPayload,
141
141
  client: StageWhisperClient,
142
142
  ): Promise<void> {
143
- api.logger.info(`Received task: ${task.title} (${task.id})`);
144
-
145
143
  try {
146
144
  await updateStatus(client, task, "delivered");
147
145
  } catch (err) {
@@ -149,58 +147,101 @@ export function createRelayService(api: OpenClawPluginApi) {
149
147
  }
150
148
 
151
149
  const messageContent = buildTaskMessage(task);
150
+ const sessionKey = buildAgentSessionKey({
151
+ agentId: "default",
152
+ channel: "stagewhisper",
153
+ peer: { kind: "direct", id: `sw-task-${task.id}` },
154
+ });
155
+
156
+ const result = await api.runtime.subagent.run({
157
+ sessionKey,
158
+ message: messageContent,
159
+ deliver: true,
160
+ idempotencyKey: randomUUID(),
161
+ });
162
+
163
+ api.logger.info(
164
+ `Task ${task.id} dispatched to agent session (runId: ${result.runId})`,
165
+ );
152
166
 
153
167
  try {
154
- const sessionKey = buildAgentSessionKey({
155
- agentId: "default",
156
- channel: "stagewhisper",
157
- peer: { kind: "direct", id: `sw-task-${task.id}` },
158
- });
168
+ await updateStatus(client, task, "running");
169
+ } catch (err) {
170
+ api.logger.warn(`Failed to mark task as running: ${err}`);
171
+ }
159
172
 
160
- const result = await api.runtime.subagent.run({
161
- sessionKey,
162
- message: messageContent,
163
- deliver: false,
164
- idempotencyKey: randomUUID(),
173
+ api.runtime.subagent
174
+ .waitForRun({ runId: result.runId, timeoutMs: 120_000 })
175
+ .then(async (waitResult) => {
176
+ if (waitResult.status === "ok") {
177
+ await updateStatus(client, task, "completed").catch(() => {});
178
+ api.logger.info(`Task ${task.id} completed`);
179
+ } else {
180
+ api.logger.error(
181
+ `Agent run failed for task ${task.id}: ${waitResult.error}`,
182
+ );
183
+ await updateStatus(client, task, "failed").catch(() => {});
184
+ }
185
+ })
186
+ .catch((err) => {
187
+ api.logger.error(`Failed to track task ${task.id}: ${err}`);
165
188
  });
189
+ }
166
190
 
167
- api.logger.info(
168
- `Task ${task.id} dispatched to agent session (runId: ${result.runId})`,
169
- );
191
+ async function handleTestTask(
192
+ task: TaskPayload,
193
+ client: StageWhisperClient,
194
+ ): Promise<void> {
195
+ const messageContent = buildTaskMessage(task);
196
+ const sessionKey = buildAgentSessionKey({
197
+ agentId: "default",
198
+ channel: "stagewhisper",
199
+ peer: { kind: "direct", id: `sw-test-${task.id}` },
200
+ });
170
201
 
171
- try {
172
- await updateStatus(client, task, "running");
173
- } catch (err) {
174
- api.logger.warn(`Failed to mark task as running: ${err}`);
202
+ const result = await api.runtime.subagent.run({
203
+ sessionKey,
204
+ message: messageContent,
205
+ deliver: false,
206
+ idempotencyKey: randomUUID(),
207
+ });
208
+
209
+ api.logger.info(
210
+ `Test task ${task.id} dispatched (runId: ${result.runId})`,
211
+ );
212
+
213
+ const waitResult = await api.runtime.subagent.waitForRun({
214
+ runId: result.runId,
215
+ timeoutMs: 120_000,
216
+ });
217
+
218
+ if (waitResult.status === "ok") {
219
+ const reply = await extractReplyWithRetry(sessionKey);
220
+ if (reply) {
221
+ await client.testReply(task.id, reply);
222
+ api.logger.info(`Test task ${task.id} completed with reply`);
223
+ } else {
224
+ api.logger.warn(`Test task ${task.id} completed but no reply found`);
225
+ await client.testReply(task.id, "(no reply extracted)");
175
226
  }
227
+ } else {
228
+ api.logger.error(
229
+ `Agent run failed for test task ${task.id}: ${waitResult.error}`,
230
+ );
231
+ }
232
+ }
176
233
 
177
- const waitResult = await api.runtime.subagent.waitForRun({
178
- runId: result.runId,
179
- timeoutMs: 120_000,
180
- });
234
+ async function handleTask(
235
+ task: TaskPayload,
236
+ client: StageWhisperClient,
237
+ ): Promise<void> {
238
+ api.logger.info(`Received task: ${task.title} (${task.id})`);
181
239
 
182
- if (waitResult.status === "ok") {
183
- const reply = await extractReplyWithRetry(sessionKey);
184
- if (reply) {
185
- if (isTestTask(task)) {
186
- await client.testReply(task.id, reply);
187
- } else {
188
- await client.postReply(task.id, reply);
189
- }
190
- api.logger.info(`Task ${task.id} completed with reply`);
191
- } else {
192
- api.logger.warn(`Task ${task.id} completed but no assistant reply found`);
193
- if (isTestTask(task)) {
194
- await client.testReply(task.id, "(no reply extracted)");
195
- } else {
196
- await updateStatus(client, task, "completed").catch(() => {});
197
- }
198
- }
240
+ try {
241
+ if (isTestTask(task)) {
242
+ await handleTestTask(task, client);
199
243
  } else {
200
- api.logger.error(
201
- `Agent run failed for task ${task.id}: ${waitResult.error}`,
202
- );
203
- await updateStatus(client, task, "failed").catch(() => {});
244
+ await handleNormalTask(task, client);
204
245
  }
205
246
  } catch (err) {
206
247
  api.logger.error(`Failed to process task ${task.id}: ${err}`);
@@ -256,11 +297,9 @@ export function createRelayService(api: OpenClawPluginApi) {
256
297
 
257
298
  try {
258
299
  const task = JSON.parse(jsonStr) as TaskPayload;
259
- handleTask(task, client).catch((err) => {
260
- api.logger.error(`Unhandled error processing task: ${err}`);
261
- });
262
- } catch (parseErr) {
263
- api.logger.warn(`Failed to parse stream event: ${parseErr}`);
300
+ await handleTask(task, client);
301
+ } catch (err) {
302
+ api.logger.error(`Error processing task from stream: ${err}`);
264
303
  }
265
304
  }
266
305
  }