@stagewhisper/stagewhisper 0.47.0 → 0.49.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/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/plugin-main.ts +1 -2
- package/src/service.ts +132 -13
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
package/plugin-main.ts
CHANGED
|
@@ -38,8 +38,6 @@ export default definePluginEntry({
|
|
|
38
38
|
register(api) {
|
|
39
39
|
api.registerChannel({ plugin: stagewhisperPlugin });
|
|
40
40
|
|
|
41
|
-
ensureResponsesEndpoint(api);
|
|
42
|
-
|
|
43
41
|
api.registerCli(
|
|
44
42
|
({ program }) => {
|
|
45
43
|
const sw = program
|
|
@@ -336,6 +334,7 @@ export default definePluginEntry({
|
|
|
336
334
|
|
|
337
335
|
if (api.registrationMode !== "full") return;
|
|
338
336
|
|
|
337
|
+
ensureResponsesEndpoint(api);
|
|
339
338
|
setRuntime(api.runtime);
|
|
340
339
|
const service = createRelayService(api);
|
|
341
340
|
api.registerService(service);
|
package/src/service.ts
CHANGED
|
@@ -302,12 +302,101 @@ export function createRelayService(api: OpenClawPluginApi) {
|
|
|
302
302
|
}
|
|
303
303
|
}
|
|
304
304
|
|
|
305
|
+
async function handleCapabilityProbe(
|
|
306
|
+
job: ReasoningJobEnvelope,
|
|
307
|
+
client: StageWhisperClient,
|
|
308
|
+
): Promise<void> {
|
|
309
|
+
const correlationId = job.correlation_id;
|
|
310
|
+
const displayModel = health.get().displayModel ?? null;
|
|
311
|
+
const prompt =
|
|
312
|
+
((job.payload as Record<string, unknown>)?.prompt as string) ??
|
|
313
|
+
"Briefly describe your capabilities, personality, tools, expertise, goals, and constraints. Plain text, no JSON.";
|
|
314
|
+
|
|
315
|
+
const sessionKey = buildAgentSessionKey({
|
|
316
|
+
agentId: "default",
|
|
317
|
+
channel: "stagewhisper",
|
|
318
|
+
peer: { kind: "direct", id: `sw-probe-${job.job_id}` },
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
try {
|
|
322
|
+
const result = await api.runtime.subagent.run({
|
|
323
|
+
sessionKey,
|
|
324
|
+
message: prompt,
|
|
325
|
+
deliver: false,
|
|
326
|
+
idempotencyKey: `sw-probe-${job.job_id}`,
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
const waitResult = await api.runtime.subagent.waitForRun({
|
|
330
|
+
runId: result.runId,
|
|
331
|
+
timeoutMs: 35_000,
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
if (waitResult.status === "ok") {
|
|
335
|
+
const reply = await extractReplyWithRetry(sessionKey);
|
|
336
|
+
|
|
337
|
+
await client.postReasoningResult(
|
|
338
|
+
job.job_id,
|
|
339
|
+
{
|
|
340
|
+
job_id: job.job_id,
|
|
341
|
+
status: "completed",
|
|
342
|
+
provider_run_id: result.runId,
|
|
343
|
+
model_ref: displayModel,
|
|
344
|
+
usage: null,
|
|
345
|
+
output: { raw_description: (reply ?? "").slice(0, 2000) },
|
|
346
|
+
error_code: null,
|
|
347
|
+
error_message: null,
|
|
348
|
+
},
|
|
349
|
+
correlationId,
|
|
350
|
+
);
|
|
351
|
+
api.logger.info(`Capability probe ${job.job_id} completed`);
|
|
352
|
+
} else {
|
|
353
|
+
await client.postReasoningResult(
|
|
354
|
+
job.job_id,
|
|
355
|
+
{
|
|
356
|
+
job_id: job.job_id,
|
|
357
|
+
status: "failed",
|
|
358
|
+
provider_run_id: result.runId,
|
|
359
|
+
model_ref: displayModel,
|
|
360
|
+
usage: null,
|
|
361
|
+
output: null,
|
|
362
|
+
error_code: "agent_error",
|
|
363
|
+
error_message: waitResult.error ?? "Agent run failed",
|
|
364
|
+
},
|
|
365
|
+
correlationId,
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
} catch (err) {
|
|
369
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
370
|
+
api.logger.error(`Capability probe ${job.job_id} failed: ${errMsg}`);
|
|
371
|
+
try {
|
|
372
|
+
await client.postReasoningResult(
|
|
373
|
+
job.job_id,
|
|
374
|
+
{
|
|
375
|
+
job_id: job.job_id,
|
|
376
|
+
status: "failed",
|
|
377
|
+
provider_run_id: null,
|
|
378
|
+
model_ref: displayModel,
|
|
379
|
+
usage: null,
|
|
380
|
+
output: null,
|
|
381
|
+
error_code: "execution_error",
|
|
382
|
+
error_message: errMsg,
|
|
383
|
+
},
|
|
384
|
+
correlationId,
|
|
385
|
+
);
|
|
386
|
+
} catch (postErr) {
|
|
387
|
+
api.logger.error(`Failed to report probe failure: ${postErr}`);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
305
392
|
async function handleReasoningJob(
|
|
306
393
|
job: ReasoningJobEnvelope,
|
|
307
394
|
client: StageWhisperClient,
|
|
308
395
|
): Promise<void> {
|
|
309
396
|
const correlationId = job.correlation_id;
|
|
310
|
-
api.logger.info(
|
|
397
|
+
api.logger.info(
|
|
398
|
+
`Received reasoning job: ${job.job_id} (purpose: ${job.purpose}, correlation: ${correlationId ?? "none"})`,
|
|
399
|
+
);
|
|
311
400
|
|
|
312
401
|
if (completedReasoningJobs.has(job.job_id)) {
|
|
313
402
|
api.logger.info(`Skipping completed reasoning job: ${job.job_id}`);
|
|
@@ -319,6 +408,16 @@ export function createRelayService(api: OpenClawPluginApi) {
|
|
|
319
408
|
}
|
|
320
409
|
processingReasoningJobs.add(job.job_id);
|
|
321
410
|
|
|
411
|
+
if (job.purpose === "capability_probe") {
|
|
412
|
+
try {
|
|
413
|
+
await handleCapabilityProbe(job, client);
|
|
414
|
+
completedReasoningJobs.set(job.job_id, Date.now());
|
|
415
|
+
} finally {
|
|
416
|
+
processingReasoningJobs.delete(job.job_id);
|
|
417
|
+
}
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
|
|
322
421
|
try {
|
|
323
422
|
const displayModel = health.get().displayModel ?? null;
|
|
324
423
|
|
|
@@ -331,16 +430,20 @@ export function createRelayService(api: OpenClawPluginApi) {
|
|
|
331
430
|
api.logger.error(`Reasoning job ${job.job_id} failed: ${errMsg}`);
|
|
332
431
|
|
|
333
432
|
try {
|
|
334
|
-
await client.postReasoningResult(
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
433
|
+
await client.postReasoningResult(
|
|
434
|
+
job.job_id,
|
|
435
|
+
{
|
|
436
|
+
job_id: job.job_id,
|
|
437
|
+
status: "failed",
|
|
438
|
+
provider_run_id: null,
|
|
439
|
+
model_ref: displayModel,
|
|
440
|
+
usage: null,
|
|
441
|
+
output: null,
|
|
442
|
+
error_code: "execution_error",
|
|
443
|
+
error_message: errMsg,
|
|
444
|
+
},
|
|
445
|
+
correlationId,
|
|
446
|
+
);
|
|
344
447
|
} catch (postErr) {
|
|
345
448
|
api.logger.error(`Failed to report reasoning failure: ${postErr}`);
|
|
346
449
|
}
|
|
@@ -358,7 +461,11 @@ export function createRelayService(api: OpenClawPluginApi) {
|
|
|
358
461
|
}
|
|
359
462
|
|
|
360
463
|
try {
|
|
361
|
-
await client.postReasoningResult(
|
|
464
|
+
await client.postReasoningResult(
|
|
465
|
+
job.job_id,
|
|
466
|
+
result as unknown as Record<string, unknown>,
|
|
467
|
+
correlationId,
|
|
468
|
+
);
|
|
362
469
|
completedReasoningJobs.set(job.job_id, Date.now());
|
|
363
470
|
if (completedReasoningJobs.size > COMPLETED_JOB_MAX_SIZE) {
|
|
364
471
|
evictStaleCompletedJobs();
|
|
@@ -401,6 +508,18 @@ export function createRelayService(api: OpenClawPluginApi) {
|
|
|
401
508
|
health.setConnected();
|
|
402
509
|
api.logger.info("Connected to StageWhisper relay stream");
|
|
403
510
|
|
|
511
|
+
if (health.get().status !== "healthy") {
|
|
512
|
+
api.logger.info("Re-probing /v1/responses after reconnect...");
|
|
513
|
+
const probe = await probeOpenResponses(api);
|
|
514
|
+
if (probe.ok) {
|
|
515
|
+
health.recordSuccess();
|
|
516
|
+
if (probe.model) health.setModel(probe.model);
|
|
517
|
+
api.logger.info(`Local AI verified on reconnect — model: ${probe.model ?? "unknown"}`);
|
|
518
|
+
} else {
|
|
519
|
+
api.logger.warn(`Reconnect probe failed: ${probe.error}`);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
|
|
404
523
|
const reader = res.body.getReader();
|
|
405
524
|
const decoder = new TextDecoder();
|
|
406
525
|
let buffer = "";
|
|
@@ -501,7 +620,7 @@ export function createRelayService(api: OpenClawPluginApi) {
|
|
|
501
620
|
if (!isResponsesEndpointEnabled(api)) {
|
|
502
621
|
api.logger.warn(
|
|
503
622
|
"gateway.http.endpoints.responses.enabled is not true — reasoning jobs will fail with 404. " +
|
|
504
|
-
|
|
623
|
+
"Enable it in config and restart the gateway, or re-pair with: openclaw stagewhisper pair --code <CODE> --enable-responses",
|
|
505
624
|
);
|
|
506
625
|
}
|
|
507
626
|
|