@stagewhisper/stagewhisper 0.53.0 → 0.55.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/index.js CHANGED
@@ -128,6 +128,17 @@ var init_client = __esm({
128
128
  throw new Error(`Reasoning result post failed (${res.status}): ${text}`);
129
129
  }
130
130
  }
131
+ async getReasoningJob(jobId) {
132
+ const res = await fetch(`${this.baseUrl}/api/v1/openclaw/reasoning-jobs/${jobId}`, {
133
+ method: "GET",
134
+ headers: this.headers()
135
+ });
136
+ if (!res.ok) {
137
+ const text = await res.text();
138
+ throw new Error(`Reasoning job fetch failed (${res.status}): ${text}`);
139
+ }
140
+ return res.json();
141
+ }
131
142
  streamUrl() {
132
143
  return `${this.baseUrl}/api/v1/openclaw/integrations/${this.integrationId}/stream`;
133
144
  }
@@ -4236,6 +4247,40 @@ function createRelayService(api) {
4236
4247
  }
4237
4248
  return null;
4238
4249
  }
4250
+ function waitTimeoutMsForJob(job, fallbackMs) {
4251
+ const parsedDeadline = new Date(job.deadline_at).getTime();
4252
+ if (!Number.isFinite(parsedDeadline)) return fallbackMs;
4253
+ return Math.max(1e3, parsedDeadline - Date.now());
4254
+ }
4255
+ function needsReasoningJobHydration(job) {
4256
+ if (job["_truncated"] === true) return true;
4257
+ if (typeof job["deadline_at"] !== "string") return true;
4258
+ if (typeof job["idempotency_key"] !== "string") return true;
4259
+ const responseSchema = job["response_schema"];
4260
+ if (typeof responseSchema !== "object" || responseSchema === null) return true;
4261
+ const payload = job["payload"];
4262
+ if (typeof payload !== "object" || payload === null) return true;
4263
+ return payload["_truncated"] === true;
4264
+ }
4265
+ async function hydrateReasoningJobEnvelope(rawJob, client) {
4266
+ const payload = rawJob["payload"];
4267
+ const payloadRecord = typeof payload === "object" && payload !== null ? payload : null;
4268
+ const jobId = typeof rawJob["job_id"] === "string" ? rawJob["job_id"] : typeof payloadRecord?.["job_id"] === "string" ? payloadRecord["job_id"] : typeof payloadRecord?.["id"] === "string" ? payloadRecord["id"] : null;
4269
+ if (!jobId) {
4270
+ api.logger.error("Received reasoning job without job_id");
4271
+ return null;
4272
+ }
4273
+ if (!needsReasoningJobHydration(rawJob)) {
4274
+ return rawJob;
4275
+ }
4276
+ try {
4277
+ api.logger.info(`Hydrating truncated reasoning job ${jobId}`);
4278
+ return await client.getReasoningJob(jobId);
4279
+ } catch (err) {
4280
+ api.logger.error(`Failed to hydrate reasoning job ${jobId}: ${err}`);
4281
+ return null;
4282
+ }
4283
+ }
4239
4284
  async function extractReplyForTask(sessionKey, taskId, maxAttempts = 3) {
4240
4285
  for (let attempt = 0; attempt < maxAttempts; attempt++) {
4241
4286
  if (attempt > 0) {
@@ -4451,7 +4496,7 @@ function createRelayService(api) {
4451
4496
  });
4452
4497
  const waitResult = await api.runtime.subagent.waitForRun({
4453
4498
  runId: result.runId,
4454
- timeoutMs: 35e3
4499
+ timeoutMs: waitTimeoutMsForJob(job, 6e4)
4455
4500
  });
4456
4501
  if (waitResult.status === "ok") {
4457
4502
  const reply = await extractReplyWithRetry(sessionKey);
@@ -4645,7 +4690,7 @@ function createRelayService(api) {
4645
4690
  } else {
4646
4691
  health.recordFailure(result.error_message ?? `reasoning ${result.status}`);
4647
4692
  }
4648
- let encryptedResult;
4693
+ let completionResult;
4649
4694
  try {
4650
4695
  const resultJson = JSON.stringify(result.output ?? {});
4651
4696
  const resultBytes = new TextEncoder().encode(resultJson);
@@ -4659,28 +4704,40 @@ function createRelayService(api) {
4659
4704
  "reasoning_output",
4660
4705
  resultBytes
4661
4706
  );
4662
- encryptedResult = {
4663
- byo_encrypted: true,
4664
- envelope: resultEnvelope,
4665
- job_id: job.job_id,
4707
+ completionResult = {
4666
4708
  status: result.status,
4709
+ provider_run_id: result.provider_run_id,
4710
+ model_ref: result.model_ref,
4667
4711
  usage: result.usage,
4668
- model_ref: result.model_ref
4712
+ output: {
4713
+ byo_encrypted: true,
4714
+ envelope: resultEnvelope,
4715
+ status: result.status
4716
+ },
4717
+ error_code: result.error_code,
4718
+ error_message: result.error_message
4669
4719
  };
4670
4720
  } catch (err) {
4671
4721
  api.logger.error(`BYO job ${job.job_id} result encryption failed: ${err}`);
4672
- encryptedResult = {
4673
- job_id: job.job_id,
4722
+ completionResult = {
4674
4723
  status: "failed",
4724
+ provider_run_id: result.provider_run_id,
4725
+ model_ref: result.model_ref,
4726
+ usage: result.usage,
4727
+ output: {
4728
+ byo_encrypted: true,
4729
+ status: "failed",
4730
+ error_code: "encryption_error",
4731
+ error_message: "Failed to encrypt result"
4732
+ },
4675
4733
  error_code: "encryption_error",
4676
- error_message: "Failed to encrypt result",
4677
- byo_encrypted: true
4734
+ error_message: "Failed to encrypt result"
4678
4735
  };
4679
4736
  }
4680
4737
  try {
4681
4738
  await client.postReasoningResult(
4682
4739
  job.job_id,
4683
- encryptedResult,
4740
+ completionResult,
4684
4741
  correlationId
4685
4742
  );
4686
4743
  completedReasoningJobs.set(job.job_id, Date.now());
@@ -4690,6 +4747,14 @@ function createRelayService(api) {
4690
4747
  }
4691
4748
  }
4692
4749
  async function handleReasoningJob(job, client) {
4750
+ const hydrated = await hydrateReasoningJobEnvelope(
4751
+ job,
4752
+ client
4753
+ );
4754
+ if (!hydrated) {
4755
+ return;
4756
+ }
4757
+ job = hydrated;
4693
4758
  const correlationId = job.correlation_id;
4694
4759
  api.logger.info(
4695
4760
  `Received reasoning job: ${job.job_id} (purpose: ${job.purpose}, correlation: ${correlationId ?? "none"})`
@@ -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.53.0",
5
+ "version": "0.55.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.53.0",
3
+ "version": "0.55.0",
4
4
  "type": "module",
5
5
  "description": "OpenClaw channel plugin that connects StageWhisper live calls to your AI assistant",
6
6
  "license": "MIT",