@tiens.nguyen/gonext-local-worker 1.0.19 → 1.0.23

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.
@@ -159,9 +159,14 @@ async function runChatJob(job) {
159
159
  let buf = "";
160
160
  let flushTimer = null;
161
161
  let fullText = "";
162
+ /** Chains debounced chunk POSTs so we never PATCH `completed` while a chunk POST is still in flight. */
163
+ let flushTail = Promise.resolve();
164
+
165
+ /** Batch streamed text: fewer HTTPS round-trips to the API than a 12ms debounce per flush. */
166
+ const CHUNK_DEBOUNCE_MS = 80;
167
+ const CHUNK_MAX_BUF = 6144;
162
168
 
163
169
  const flushChunks = async () => {
164
- flushTimer = null;
165
170
  const t = buf;
166
171
  buf = "";
167
172
  if (!t) return;
@@ -172,15 +177,25 @@ async function runChatJob(job) {
172
177
  if (!res.ok && res.status !== 204) {
173
178
  const snippet = (await res.text().catch(() => "")).trim().slice(0, 400);
174
179
  const url = `${apiBase}${CHUNK_PATH}`;
175
- console.error(
176
- `[gonext-worker] job-chunk POST failed status=${res.status} url=${url} jobId=${jobId}` +
177
- (snippet ? ` response=${snippet}` : "")
178
- );
179
- if (res.status === 404) {
180
+ const benign409 =
181
+ res.status === 409 && snippet.includes('"jobStatus":"completed"');
182
+ if (!benign409) {
180
183
  console.error(
181
- "[gonext-worker] hint: 404 usually means (a) API not redeployed with POST /api/worker/job-chunk, or (b) response JSON {\"error\":\"Job not found\"} = Dynamo lookup failed (wrong worker key user vs job owner)."
184
+ `[gonext-worker] job-chunk POST failed status=${res.status} url=${url} jobId=${jobId}` +
185
+ (snippet ? ` response=${snippet}` : "")
182
186
  );
183
187
  }
188
+ if (res.status === 404) {
189
+ if (snippet.includes("Cannot POST")) {
190
+ console.error(
191
+ "[gonext-worker] DEPLOY: Lambda/API still runs old Express without POST /api/worker/job-chunk. From repo: cd api && npm ci && sam build && sam deploy — or publish the latest bundled handler so execute-api serves current routes."
192
+ );
193
+ } else {
194
+ console.error(
195
+ '[gonext-worker] hint: JSON {"error":"Job not found"} = Dynamo lookup failed (wrong worker user vs job owner). Otherwise redeploy API.'
196
+ );
197
+ }
198
+ }
184
199
  }
185
200
  };
186
201
 
@@ -188,8 +203,23 @@ async function runChatJob(job) {
188
203
  if (!s) return;
189
204
  fullText += s;
190
205
  buf += s;
206
+ if (buf.length >= CHUNK_MAX_BUF) {
207
+ if (flushTimer) {
208
+ clearTimeout(flushTimer);
209
+ flushTimer = null;
210
+ }
211
+ flushTail = flushTail.then(() => flushChunks()).catch((err) => {
212
+ console.error("[gonext-worker] chunk flush error:", err);
213
+ });
214
+ return;
215
+ }
191
216
  if (!flushTimer) {
192
- flushTimer = setTimeout(() => void flushChunks(), 12);
217
+ flushTimer = setTimeout(() => {
218
+ flushTimer = null;
219
+ flushTail = flushTail.then(() => flushChunks()).catch((err) => {
220
+ console.error("[gonext-worker] chunk flush error:", err);
221
+ });
222
+ }, CHUNK_DEBOUNCE_MS);
193
223
  }
194
224
  };
195
225
 
@@ -232,6 +262,7 @@ async function runChatJob(job) {
232
262
  clearTimeout(flushTimer);
233
263
  flushTimer = null;
234
264
  }
265
+ await flushTail;
235
266
  await flushChunks();
236
267
 
237
268
  const totalTimeSeconds = (Date.now() - start) / 1000;
@@ -250,6 +281,7 @@ async function runChatJob(job) {
250
281
  clearTimeout(flushTimer);
251
282
  flushTimer = null;
252
283
  }
284
+ await flushTail;
253
285
  await flushChunks().catch(() => {});
254
286
  const message = e instanceof Error ? e.message : String(e);
255
287
  await workerFetch(`/api/worker/jobs/${jobId}`, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tiens.nguyen/gonext-local-worker",
3
- "version": "1.0.19",
3
+ "version": "1.0.23",
4
4
  "description": "Polls GoNext cloud API for async local LLM jobs and runs them against Ollama/OpenAI-compatible servers on this Mac",
5
5
  "type": "module",
6
6
  "license": "MIT",