@stagewhisper/stagewhisper 0.36.0 → 0.37.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.36.0",
5
+ "version": "0.37.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.36.0",
3
+ "version": "0.37.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/client.ts CHANGED
@@ -118,4 +118,19 @@ export class StageWhisperClient {
118
118
  streamHeaders(): Record<string, string> {
119
119
  return { Authorization: `Bearer ${this.relayToken}` };
120
120
  }
121
+
122
+ async testReply(testId: string, content: string): Promise<void> {
123
+ const res = await fetch(
124
+ `${this.baseUrl}/api/v1/openclaw/integrations/${this.integrationId}/test-reply`,
125
+ {
126
+ method: "POST",
127
+ headers: this.headers(),
128
+ body: JSON.stringify({ test_id: testId, content }),
129
+ },
130
+ );
131
+ if (!res.ok) {
132
+ const text = await res.text();
133
+ throw new Error(`Test reply failed (${res.status}): ${text}`);
134
+ }
135
+ }
121
136
  }
package/src/service.ts CHANGED
@@ -96,13 +96,46 @@ export function createRelayService(api: OpenClawPluginApi) {
96
96
  for (let i = messages.length - 1; i >= 0; i--) {
97
97
  const msg = messages[i] as Record<string, unknown> | undefined;
98
98
  if (!msg) continue;
99
- if (msg["role"] === "assistant" && typeof msg["content"] === "string") {
100
- return msg["content"];
99
+ const role = msg["role"];
100
+ if (role !== "assistant" && role !== "model") continue;
101
+
102
+ const content = msg["content"];
103
+ if (typeof content === "string") return content;
104
+
105
+ if (Array.isArray(content)) {
106
+ for (const part of content) {
107
+ if (
108
+ typeof part === "object" &&
109
+ part !== null &&
110
+ (part as Record<string, unknown>)["type"] === "text" &&
111
+ typeof (part as Record<string, unknown>)["text"] === "string"
112
+ ) {
113
+ return (part as Record<string, unknown>)["text"] as string;
114
+ }
115
+ }
101
116
  }
102
117
  }
103
118
  return null;
104
119
  }
105
120
 
121
+ async function extractReplyWithRetry(
122
+ sessionKey: string,
123
+ maxAttempts: number = 3,
124
+ ): Promise<string | null> {
125
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
126
+ if (attempt > 0) {
127
+ await new Promise((r) => setTimeout(r, 1500));
128
+ }
129
+ const session = await api.runtime.subagent.getSessionMessages({
130
+ sessionKey,
131
+ limit: 20,
132
+ });
133
+ const reply = extractAssistantReply(session.messages);
134
+ if (reply) return reply;
135
+ }
136
+ return null;
137
+ }
138
+
106
139
  async function handleTask(
107
140
  task: TaskPayload,
108
141
  client: StageWhisperClient,
@@ -147,20 +180,21 @@ export function createRelayService(api: OpenClawPluginApi) {
147
180
  });
148
181
 
149
182
  if (waitResult.status === "ok") {
150
- const session = await api.runtime.subagent.getSessionMessages({
151
- sessionKey,
152
- limit: 20,
153
- });
154
-
155
- const reply = extractAssistantReply(session.messages);
183
+ const reply = await extractReplyWithRetry(sessionKey);
156
184
  if (reply) {
157
- if (!isTestTask(task)) {
185
+ if (isTestTask(task)) {
186
+ await client.testReply(task.id, reply);
187
+ } else {
158
188
  await client.postReply(task.id, reply);
159
189
  }
160
190
  api.logger.info(`Task ${task.id} completed with reply`);
161
191
  } else {
162
192
  api.logger.warn(`Task ${task.id} completed but no assistant reply found`);
163
- await updateStatus(client, task, "completed").catch(() => {});
193
+ if (isTestTask(task)) {
194
+ await client.testReply(task.id, "(no reply extracted)");
195
+ } else {
196
+ await updateStatus(client, task, "completed").catch(() => {});
197
+ }
164
198
  }
165
199
  } else {
166
200
  api.logger.error(