forge-openclaw-plugin 0.2.116 → 0.2.117

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.
@@ -24,6 +24,7 @@ export class BackgroundJobManager extends AbstractManager {
24
24
  },
25
25
  functionName: "enqueue"
26
26
  });
27
+ this.scheduleDrain();
27
28
  return;
28
29
  }
29
30
  this.queue.push(input);
@@ -25,6 +25,7 @@ const CODEX_WIKI_COMPILE_RESERVED_RESPONSE_TOKENS = 60_000;
25
25
  const APPROX_CHARS_PER_TOKEN = 4;
26
26
  const REQUEST_TIMEOUT_MS = 90_000;
27
27
  const CODEX_FOREGROUND_COMPILE_TIMEOUT_MS = 10 * 60_000;
28
+ const CODEX_STREAM_READ_TIMEOUT_MS = 10 * 60_000;
28
29
  const BACKGROUND_POLL_INTERVAL_MS = 2_000;
29
30
  const DEFAULT_CODEX_BASE_URL = "https://chatgpt.com/backend-api";
30
31
  const CODEX_JWT_CLAIM_PATH = "https://api.openai.com/auth";
@@ -264,9 +265,52 @@ function parseCodexEventStreamPayload(streamText) {
264
265
  }
265
266
  async function readProviderPayload(response, profile) {
266
267
  return isCodexProfile(profile)
267
- ? parseCodexEventStreamPayload(await response.text())
268
+ ? parseCodexEventStreamPayload(await readResponseTextWithTimeout(response, CODEX_STREAM_READ_TIMEOUT_MS))
268
269
  : readJsonPayload(response);
269
270
  }
271
+ async function readResponseTextWithTimeout(response, timeoutMs) {
272
+ if (!response.body) {
273
+ return response.text();
274
+ }
275
+ const reader = response.body.getReader();
276
+ const decoder = new TextDecoder();
277
+ const chunks = [];
278
+ const deadline = Date.now() + timeoutMs;
279
+ try {
280
+ while (true) {
281
+ const remainingMs = Math.max(1, deadline - Date.now());
282
+ const result = await readStreamChunkWithTimeout(reader, remainingMs, timeoutMs);
283
+ if (result.done) {
284
+ break;
285
+ }
286
+ chunks.push(decoder.decode(result.value, { stream: true }));
287
+ }
288
+ chunks.push(decoder.decode());
289
+ return chunks.join("");
290
+ }
291
+ catch (error) {
292
+ await reader.cancel().catch(() => undefined);
293
+ throw error;
294
+ }
295
+ finally {
296
+ reader.releaseLock();
297
+ }
298
+ }
299
+ function readStreamChunkWithTimeout(reader, remainingMs, totalTimeoutMs) {
300
+ let timeout = null;
301
+ return Promise.race([
302
+ reader.read(),
303
+ new Promise((_, reject) => {
304
+ timeout = setTimeout(() => {
305
+ reject(new Error(`Codex stream read timed out after ${Math.round(totalTimeoutMs / 1000)}s.`));
306
+ }, remainingMs);
307
+ })
308
+ ]).finally(() => {
309
+ if (timeout) {
310
+ clearTimeout(timeout);
311
+ }
312
+ });
313
+ }
270
314
  function readReasoningEffort(profile) {
271
315
  return typeof profile.metadata.reasoningEffort === "string"
272
316
  ? profile.metadata.reasoningEffort
@@ -2,7 +2,7 @@
2
2
  "id": "forge-openclaw-plugin",
3
3
  "name": "Forge",
4
4
  "description": "Curated OpenClaw adapter for the Forge collaboration API, UI entrypoint, and localhost auto-start runtime.",
5
- "version": "0.2.116",
5
+ "version": "0.2.117",
6
6
  "activation": {
7
7
  "onStartup": true,
8
8
  "onCapabilities": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "forge-openclaw-plugin",
3
- "version": "0.2.116",
3
+ "version": "0.2.117",
4
4
  "description": "Curated OpenClaw adapter for the Forge collaboration API, UI entrypoint, and localhost auto-start runtime.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",