@kognai/orchestrator-core 0.2.6 → 0.2.7

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.
@@ -320,35 +320,52 @@ Write ONLY the content for "${filepath}". Rules:
320
320
  fileContent = await this.fixJsonWithOllama(fileContent, filepath);
321
321
  }
322
322
  }
323
- // TRUNCATION PRE-CHECK: Detect if MiniMax cut off output mid-function
324
- // If code ends inside an open block (unclosed braces) or with an incomplete statement,
325
- // retry once with a "continue" prompt before sending to supervisor review.
326
- const truncationDetected = this.detectTruncation(fileContent);
327
- if (truncationDetected && (provider === 'clawrouter' || provider === 'ollama')) {
328
- (0, orchestrate_engine_1.log)(orchestrate_engine_1.c.yellow, ` ! TRUNCATION detected in ${filepath} retrying with continuation prompt...`);
329
- const continuationPrompt = `The previous response for "${filepath}" was TRUNCATED — it ended mid-function or with an incomplete block. Here is what was generated so far:
323
+ // TICKET-349: multi-pass chunked generation. The OpenClaw gateway clamps
324
+ // output to ~4096 tokens regardless of the requested max_tokens, so a file
325
+ // larger than one chunk gets cut mid-statement [TRUNCATION] reject, no
326
+ // matter how capable the model is (deepseek AND sonnet truncate at the
327
+ // same length). Decompose the GENERATION: keep issuing continuation passes
328
+ // and appending until the file is complete (no truncation) or we hit the
329
+ // chunk cap. Works for ALL providers (previously clawrouter/ollama-only).
330
+ // Bounded by KOGNAI_MAX_CONTINUATION_CHUNKS (default 5 → ~5×4k≈20k output)
331
+ // and a no-progress guard so it can never loop forever.
332
+ const MAX_CONTINUATION_CHUNKS = parseInt(process.env.KOGNAI_MAX_CONTINUATION_CHUNKS ?? '5', 10);
333
+ let chunk = 0;
334
+ while (this.detectTruncation(fileContent) && chunk < MAX_CONTINUATION_CHUNKS) {
335
+ chunk++;
336
+ (0, orchestrate_engine_1.log)(orchestrate_engine_1.c.yellow, ` ! TRUNCATION in ${filepath} — continuation pass ${chunk}/${MAX_CONTINUATION_CHUNKS} (gateway ~4k output cap)...`);
337
+ const continuationPrompt = `The previous response for "${filepath}" was TRUNCATED — it ended mid-function or with an incomplete block. Here is the tail of what exists so far:
330
338
 
331
339
  \`\`\`typescript
332
340
  ${fileContent.substring(fileContent.length - 1500)}
333
341
  \`\`\`
334
342
 
335
- Continue from where it left off and output ONLY the remaining code (no duplicated content). Output a COMPLETE, valid TypeScript/JavaScript file ending with the final closing brace.`;
343
+ Continue EXACTLY from where it left off and output ONLY the remaining code (no duplicated content, no preamble, no markdown fences). End the file with its final closing brace.`;
344
+ let grew = false;
336
345
  try {
337
- const contResponse = await (0, orchestrate_engine_1.callLLM)(provider, model, this.systemPrompt, continuationPrompt, 120000, this.name, `${task.id}_continuation`);
346
+ const contResponse = await (0, orchestrate_engine_1.callLLM)(provider, model, this.systemPrompt, continuationPrompt, 120000, this.name, `${task.id}_continuation_${chunk}`);
338
347
  let contContent = contResponse.choices?.[0]?.message?.content || '';
339
348
  contContent = contContent.replace(/<think>[\s\S]*?<\/think>/g, '').trim();
340
349
  const contBlocks = this.extractCodeBlocks(contContent);
341
350
  const continuation = contBlocks.length > 0 ? contBlocks[0] : this.stripResidualFences(contContent);
342
351
  if (continuation.length > 50) {
343
- // Merge: use the original up to the last complete line, then append continuation
344
- fileContent = fileContent + '\n' + continuation;
345
- fileContent = this.stripResidualFences(fileContent);
346
- (0, orchestrate_engine_1.log)(orchestrate_engine_1.c.green, ` ✓ Continuation merged for ${filepath} (+${continuation.length} chars)`);
352
+ fileContent = this.stripResidualFences(fileContent + '\n' + continuation);
353
+ grew = true;
354
+ (0, orchestrate_engine_1.log)(orchestrate_engine_1.c.green, ` ✓ Pass ${chunk} merged for ${filepath} (+${continuation.length} chars, total ${fileContent.length})`);
347
355
  }
348
356
  }
349
357
  catch (contErr) {
350
- (0, orchestrate_engine_1.log)(orchestrate_engine_1.c.yellow, ` ! Continuation failed: ${contErr.message}`);
358
+ (0, orchestrate_engine_1.log)(orchestrate_engine_1.c.yellow, ` ! Continuation pass ${chunk} failed: ${contErr.message}`);
351
359
  }
360
+ // No-progress guard: if a pass added nothing usable, stop — further
361
+ // passes won't help and would just burn budget.
362
+ if (!grew) {
363
+ (0, orchestrate_engine_1.log)(orchestrate_engine_1.c.yellow, ` ! Continuation made no progress — stopping at pass ${chunk}`);
364
+ break;
365
+ }
366
+ }
367
+ if (chunk > 0 && !this.detectTruncation(fileContent)) {
368
+ (0, orchestrate_engine_1.log)(orchestrate_engine_1.c.green, ` ✓ ${filepath} assembled complete over ${chunk + 1} pass(es)`);
352
369
  }
353
370
  createdFiles.push({ path: filepath, content: fileContent });
354
371
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kognai/orchestrator-core",
3
- "version": "0.2.6",
3
+ "version": "0.2.7",
4
4
  "description": "Kognai sovereign orchestrator — core engine (template-agnostic). Shared by all products (Kognai/coding, Voxight/market-intel, Invoica/fin-compliance); each supplies only its template. Replaces per-repo forks of orchestrate-agents-v2 / sprint-runner / lib.",
5
5
  "license": "MIT",
6
6
  "author": "SkinGem",