@kognai/orchestrator-core 0.2.9 → 0.2.10

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.
@@ -49,7 +49,11 @@ class CodingAgent {
49
49
  constructor(name, systemPrompt) { this.name = name; this.systemPrompt = systemPrompt; }
50
50
  async execute(task, previousReview) {
51
51
  (0, orchestrate_engine_1.log)(orchestrate_engine_1.c.cyan, `\n[${this.name}] Executing: ${task.id} (${task.priority})`);
52
- const deliverables = [...(task.deliverables.code || []), ...(task.deliverables.tests || []), ...(task.deliverables.docs || [])];
52
+ // TICKET-353: TEST-FIRST ordering. Generate paired tests BEFORE their code so
53
+ // the test is authored from the SPEC (contract-first), frozen, then the code
54
+ // is written to pass it — instead of one model writing code+test together and
55
+ // letting both agree on the same wrong understanding (#2 separate author).
56
+ const deliverables = [...(task.deliverables.tests || []), ...(task.deliverables.code || []), ...(task.deliverables.docs || [])];
53
57
  // Complexity-aware model routing:
54
58
  // Claude Sonnet → complex tasks (many files, complex keywords, large existing files)
55
59
  // MiniMax M2.5 → simple tasks (small edits, config, stubs) + truncation retry as safety net
@@ -233,15 +237,31 @@ class CodingAgent {
233
237
  const existingContent = (0, fs_1.existsSync)(filepath)
234
238
  ? `\n\n## EXISTING FILE — SURGICAL EDIT ONLY\nDo NOT rewrite the entire file. Output the COMPLETE updated file with your changes merged in.\nIf you add a function, append it. If you edit a line, change only that line.\nFile has ${existingLines} lines — preserve ALL existing code.\n\n### Current Content\n\`\`\`typescript\n${(0, fs_1.readFileSync)(filepath, 'utf-8').substring(0, 3000)}\n\`\`\`\n`
235
239
  : `\n\n## Note: This is a NEW file — create it from scratch.\n`;
240
+ // TICKET-353 (#1 examples + #2 separate author): for a test file, you ARE
241
+ // the test author and this test DEFINES correctness. The implementation is
242
+ // written separately to PASS this test and cannot change it.
236
243
  const testConstraint = isTestFile
237
- ? `\n\n## CRITICAL: TEST FILE SIZE LIMIT
238
- This is a test file. You MUST keep it SHORT to avoid truncation:
239
- - Maximum 5-6 test cases (describe + it blocks)
240
- - Maximum 80 lines total
241
- - NO verbose setup use inline mocks
242
- - NO redundant tests one test per behavior
243
- - Cover: happy path, error case, edge case, defaults — that's it
244
- - If you write more than 80 lines, the file WILL be truncated and REJECTED\n`
244
+ ? `\n\n## YOU ARE THE TEST AUTHOR this test DEFINES correctness
245
+ The implementation file this pairs with will be written SEPARATELY to PASS this test and CANNOT modify it. So this test is the CONTRACT.
246
+ - Derive 3–5 CONCRETE golden input→output examples from the spec/description above and encode them as assertions with EXACT expected values (do the arithmetic yourself; don't assert on whatever the code returns).
247
+ - Use Node's built-in runner: \`import { test } from 'node:test'\` and \`import assert from 'node:assert/strict'\`.
248
+ - Import the real symbols from the implementation file (correct relative path) and exercise ACTUAL behavior: happy path, an error/edge case, and any invariant ("never exceeds capacity").
249
+ - It WILL be executed; assertions must reflect the SPEC's truth, not a guess. Keep it ≤80 lines, no verbose setup.\n`
250
+ : '';
251
+ // TICKET-353 (#2): author tests with a stronger model than the coder
252
+ // default; code files use the assessed/escalated coder model.
253
+ const TEST_AUTHOR_MODEL = process.env.KOGNAI_TEST_AUTHOR_MODEL || 'anthropic/claude-sonnet-4.6';
254
+ const fileProvider = isTestFile ? 'clawrouter' : provider;
255
+ const fileModel = isTestFile ? TEST_AUTHOR_MODEL : model;
256
+ if (isTestFile)
257
+ (0, orchestrate_engine_1.log)(orchestrate_engine_1.c.magenta, ` ✎ [TEST-AUTHOR] ${filepath} via ${fileModel} (contract-first, examples)`);
258
+ // For a CODE file, inject its already-authored paired test (tests-first
259
+ // ordering placed it in createdFiles) as the frozen contract to satisfy.
260
+ const pairedTest = !isTestFile
261
+ ? createdFiles.find(f => f.path === filepath.replace(/\.([tj]sx?)$/, '.test.$1'))
262
+ : undefined;
263
+ const contractBlock = pairedTest
264
+ ? `\n\n## CONTRACT — your code MUST make this test pass (already written; DO NOT modify it; it defines correctness):\n\`\`\`typescript\n${pairedTest.content.substring(0, 3000)}\n\`\`\`\n`
245
265
  : '';
246
266
  // EXACT CONTENT mode: task description contains code block(s) with the exact file content.
247
267
  // Extract them deterministically and bypass LLM to prevent model hallucination.
@@ -270,7 +290,7 @@ ${task.context}
270
290
  ${fileList}
271
291
 
272
292
  ## Generate ONLY: ${filepath}
273
- ${existingContent}${priorCtx}${testConstraint}
293
+ ${existingContent}${priorCtx}${testConstraint}${contractBlock}
274
294
  Write ONLY the content for "${filepath}". Rules:
275
295
  - S64-001: Output the raw file content using FILE: format as described in the system prompt
276
296
  - Do NOT wrap output in markdown code fences (\`\`\`) — for .md files especially, output RAW markdown text, NOT inside a \`\`\`markdown or \`\`\`typescript block
@@ -281,7 +301,7 @@ Write ONLY the content for "${filepath}". Rules:
281
301
  - No explanatory text — output file content only`;
282
302
  try {
283
303
  const startTime = Date.now();
284
- const response = await (0, orchestrate_engine_1.callLLM)(provider, model, this.systemPrompt, userPrompt, 480000, this.name, task.id); // 8 min — qwen3:14b needs time for large files
304
+ const response = await (0, orchestrate_engine_1.callLLM)(fileProvider, fileModel, this.systemPrompt, userPrompt, 480000, this.name, task.id); // 8 min — qwen3:14b needs time for large files
285
305
  const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
286
306
  let content = response.choices?.[0]?.message?.content || '';
287
307
  // Strip MiniMax <think>...</think> tags that leak into responses
@@ -358,7 +378,7 @@ ${fileContent.substring(fileContent.length - 1500)}
358
378
  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.`;
359
379
  let grew = false;
360
380
  try {
361
- const contResponse = await (0, orchestrate_engine_1.callLLM)(provider, model, this.systemPrompt, continuationPrompt, 120000, this.name, `${task.id}_continuation_${chunk}`);
381
+ const contResponse = await (0, orchestrate_engine_1.callLLM)(fileProvider, fileModel, this.systemPrompt, continuationPrompt, 120000, this.name, `${task.id}_continuation_${chunk}`);
362
382
  let contContent = contResponse.choices?.[0]?.message?.content || '';
363
383
  contContent = contContent.replace(/<think>[\s\S]*?<\/think>/g, '').trim();
364
384
  const contBlocks = this.extractCodeBlocks(contContent);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kognai/orchestrator-core",
3
- "version": "0.2.9",
3
+ "version": "0.2.10",
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",