@almadar/agent 1.3.0 → 1.3.2

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.
@@ -1599,8 +1599,8 @@ function createGenerateOrbitalDomainTool(options = {}) {
1599
1599
  orbitalName: spec.name
1600
1600
  });
1601
1601
  const client = new LLMClient({
1602
- provider: "anthropic",
1603
- model: "claude-sonnet-4-20250514",
1602
+ provider: options.provider ?? "anthropic",
1603
+ model: options.model ?? "claude-sonnet-4-20250514",
1604
1604
  temperature: 0
1605
1605
  });
1606
1606
  const userPrompt = buildDynamicUserPrompt(spec);
@@ -1806,12 +1806,47 @@ function createDomainOrbitalTools(options = {}) {
1806
1806
 
1807
1807
  // src/orbitals/generation/orbital-generator.ts
1808
1808
  init_cache();
1809
+
1810
+ // src/orbitals/shared/constants.ts
1811
+ var PROVIDER_CONCURRENCY_LIMITS = {
1812
+ anthropic: 3,
1813
+ openai: 5,
1814
+ deepseek: 3,
1815
+ kimi: 3,
1816
+ openrouter: 5
1817
+ };
1818
+ var PROVIDER_BATCH_SIZES = {
1819
+ anthropic: 3,
1820
+ // Anthropic works well with 3 orbitals per call
1821
+ openai: 5,
1822
+ // OpenAI can handle more
1823
+ deepseek: 3,
1824
+ // Conservative for DeepSeek
1825
+ kimi: 3,
1826
+ // Conservative for Kimi
1827
+ openrouter: 5
1828
+ // OpenRouter proxies multiple providers
1829
+ };
1830
+ var BATCH_MAX_TOKENS = 12e3;
1809
1831
  function getEntityName2(entity) {
1810
1832
  if (isEntityReference(entity)) {
1811
1833
  return entity.replace(".entity", "");
1812
1834
  }
1813
1835
  return entity.name;
1814
1836
  }
1837
+ function getInlineEntity3(entity) {
1838
+ if (isEntityReference(entity)) {
1839
+ return null;
1840
+ }
1841
+ return entity;
1842
+ }
1843
+ function getFieldNames(entity) {
1844
+ const inlineEntity = getInlineEntity3(entity);
1845
+ if (!inlineEntity?.fields?.length) {
1846
+ return "N/A";
1847
+ }
1848
+ return inlineEntity.fields.map((f) => f.name).join(", ");
1849
+ }
1815
1850
  function createLog(level, message, data) {
1816
1851
  return {
1817
1852
  timestamp: Date.now(),
@@ -1820,6 +1855,56 @@ function createLog(level, message, data) {
1820
1855
  data
1821
1856
  };
1822
1857
  }
1858
+ function buildContextSection2(orbital) {
1859
+ const parts = [];
1860
+ if (orbital.domainContext) {
1861
+ const ctx = orbital.domainContext;
1862
+ parts.push(`DomainContext: category=${ctx.category || "business"}`);
1863
+ if (ctx.vocabulary) {
1864
+ parts.push(`Vocabulary: ${JSON.stringify(ctx.vocabulary)}`);
1865
+ }
1866
+ if (ctx.requestFragment) {
1867
+ parts.push(`RequestFragment: "${ctx.requestFragment}"`);
1868
+ }
1869
+ }
1870
+ if (orbital.design) {
1871
+ const d = orbital.design;
1872
+ if (d.style) parts.push(`Style: ${d.style}`);
1873
+ if (d.uxHints) {
1874
+ const hints = d.uxHints;
1875
+ if (hints.flowPattern) parts.push(`FlowPattern: ${hints.flowPattern}`);
1876
+ if (hints.listPattern) parts.push(`ListPattern: ${hints.listPattern}`);
1877
+ if (hints.formPattern) parts.push(`FormPattern: ${hints.formPattern}`);
1878
+ }
1879
+ }
1880
+ return parts.length > 0 ? `Context: ${parts.join(", ")}
1881
+ ` : "";
1882
+ }
1883
+ function buildConnectivitySection(orbital) {
1884
+ const parts = [];
1885
+ if (orbital.emits?.length) {
1886
+ parts.push(`Emits: ${orbital.emits.join(", ")}`);
1887
+ }
1888
+ if (orbital.listens?.length) {
1889
+ parts.push(`Listens: ${orbital.listens.map((l) => `${l.event}\u2192${l.triggers}`).join(", ")}`);
1890
+ }
1891
+ return parts.join("\n");
1892
+ }
1893
+ function chunkArray(array, size) {
1894
+ const chunks = [];
1895
+ for (let i = 0; i < array.length; i += size) {
1896
+ chunks.push(array.slice(i, i + size));
1897
+ }
1898
+ return chunks;
1899
+ }
1900
+ function getErrorMessage(error) {
1901
+ if (error instanceof Error) {
1902
+ return error.message;
1903
+ }
1904
+ return String(error);
1905
+ }
1906
+
1907
+ // src/orbitals/generation/orbital-generator.ts
1823
1908
  async function generateFullOrbital(client, orbital, options = {}) {
1824
1909
  const {
1825
1910
  maxTokens = 8192,
@@ -2080,8 +2165,8 @@ function createOrbitalSubagentTool(options = {}) {
2080
2165
  ]
2081
2166
  });
2082
2167
  const client = new LLMClient({
2083
- provider: "anthropic",
2084
- model: "claude-sonnet-4-20250514"
2168
+ provider: options.provider ?? "anthropic",
2169
+ model: options.model ?? "claude-sonnet-4-20250514"
2085
2170
  });
2086
2171
  emitEvent(orbitalUnit.name, orbitalIndex, totalOrbitals, "tool_call", {
2087
2172
  tool: "llm_generate",
@@ -2213,6 +2298,707 @@ function createSubagentEventWrapper(writeEvent) {
2213
2298
  writeEvent(sseEvent);
2214
2299
  };
2215
2300
  }
2301
+
2302
+ // src/orbitals/batch/prompt-assembler.ts
2303
+ init_cache();
2304
+ function extractSharedContext(orbitals) {
2305
+ const vocabulary = {};
2306
+ const styles = /* @__PURE__ */ new Set();
2307
+ const patterns = /* @__PURE__ */ new Set();
2308
+ const relationships = [];
2309
+ for (const orbital of orbitals) {
2310
+ if (orbital.domainContext?.vocabulary) {
2311
+ Object.assign(vocabulary, orbital.domainContext.vocabulary);
2312
+ }
2313
+ if (orbital.design?.style) {
2314
+ styles.add(orbital.design.style);
2315
+ }
2316
+ }
2317
+ new Map(orbitals.map((o) => [o.name, o]));
2318
+ for (const orbital of orbitals) {
2319
+ if (orbital.emits) {
2320
+ for (const event of orbital.emits) {
2321
+ for (const other of orbitals) {
2322
+ if (other === orbital) continue;
2323
+ if (other.listens) {
2324
+ const listener = other.listens.find((l) => l.event === event.event);
2325
+ if (listener) {
2326
+ relationships.push({
2327
+ emitter: orbital.name,
2328
+ event: event.event,
2329
+ listener: other.name,
2330
+ handler: listener.triggers
2331
+ });
2332
+ }
2333
+ }
2334
+ }
2335
+ }
2336
+ }
2337
+ }
2338
+ return {
2339
+ domainVocabulary: Object.keys(vocabulary).length > 0 ? vocabulary : void 0,
2340
+ designStyle: styles.size === 1 ? Array.from(styles)[0] : void 0,
2341
+ commonPatterns: patterns.size > 0 ? Array.from(patterns) : void 0,
2342
+ eventRelationships: relationships.length > 0 ? relationships : void 0
2343
+ };
2344
+ }
2345
+ function assembleBatchPrompt(orbitals, options = {}) {
2346
+ const {
2347
+ baseSystemPrompt = getFullOrbitalPrompt(),
2348
+ includeConnectivity = true
2349
+ } = options;
2350
+ if (orbitals.length === 0) {
2351
+ throw new Error("Cannot assemble batch prompt for empty orbitals array");
2352
+ }
2353
+ const sharedContext = extractSharedContext(orbitals);
2354
+ const batchHeader = buildBatchHeader(orbitals, sharedContext);
2355
+ const orbitalSections = orbitals.map(
2356
+ (orbital, index) => buildOrbitalSection(orbital, index + 1, orbitals.length, includeConnectivity)
2357
+ );
2358
+ const outputSection = buildOutputSection(orbitals);
2359
+ const prompt = `${baseSystemPrompt}
2360
+
2361
+ ${"=".repeat(60)}
2362
+ BATCH GENERATION: ${orbitals.length} ORBITALS
2363
+ ${"=".repeat(60)}
2364
+
2365
+ ${batchHeader}
2366
+
2367
+ ${orbitalSections.join("\n\n")}
2368
+
2369
+ ${outputSection}`;
2370
+ const fingerprint = generateBatchFingerprint(orbitals);
2371
+ return {
2372
+ prompt,
2373
+ fingerprint,
2374
+ usedCachedTemplate: false,
2375
+ // Batch doesn't use templates yet
2376
+ orbitalCount: orbitals.length,
2377
+ orbitalNames: orbitals.map((o) => o.name)
2378
+ };
2379
+ }
2380
+ function buildBatchHeader(orbitals, sharedContext) {
2381
+ const lines = [
2382
+ `## Batch Overview`,
2383
+ `- Total Orbitals: ${orbitals.length}`,
2384
+ `- Orbitals: ${orbitals.map((o) => o.name).join(", ")}`
2385
+ ];
2386
+ if (sharedContext.designStyle) {
2387
+ lines.push(`- Design Style: ${sharedContext.designStyle}`);
2388
+ }
2389
+ if (sharedContext.commonPatterns?.length) {
2390
+ lines.push(`- Common Patterns: ${sharedContext.commonPatterns.join(", ")}`);
2391
+ }
2392
+ if (sharedContext.domainVocabulary && Object.keys(sharedContext.domainVocabulary).length > 0) {
2393
+ lines.push(`
2394
+ ## Shared Domain Vocabulary`);
2395
+ for (const [term, definition] of Object.entries(sharedContext.domainVocabulary)) {
2396
+ lines.push(`- ${term}: ${definition}`);
2397
+ }
2398
+ }
2399
+ if (sharedContext.eventRelationships?.length) {
2400
+ lines.push(`
2401
+ ## Cross-Orbital Event Relationships`);
2402
+ for (const rel of sharedContext.eventRelationships) {
2403
+ lines.push(`- ${rel.emitter} emits "${rel.event}" \u2192 ${rel.listener} handles with "${rel.handler}"`);
2404
+ }
2405
+ }
2406
+ return lines.join("\n");
2407
+ }
2408
+ function buildOrbitalSection(orbital, index, total, includeConnectivity) {
2409
+ const entityName = getEntityName2(orbital.entity);
2410
+ const fieldNames = getFieldNames(orbital.entity);
2411
+ const contextSection = buildContextSection2(orbital);
2412
+ const connectivitySection = includeConnectivity ? buildConnectivitySection(orbital) : "";
2413
+ return `---
2414
+ ## ORBITAL ${index}/${total}: ${orbital.name}
2415
+
2416
+ **Entity**: ${entityName}
2417
+ **Persistence**: ${orbital.entity.persistence || "persistent"}
2418
+ **Fields**: ${fieldNames}
2419
+ **Traits**: ${orbital.traits.map((t) => typeof t === "string" ? t : "ref" in t ? t.ref : t.name).join(", ")}
2420
+ ${contextSection}${connectivitySection ? `**Connectivity**:
2421
+ ${connectivitySection}
2422
+ ` : ""}
2423
+ Generate a complete FullOrbitalUnit for ${orbital.name} with:
2424
+ - Full field definitions with types and validation
2425
+ - Trait state machines with transitions and effects
2426
+ - Business rule validation using "guard" S-expression on SAVE transitions
2427
+ - Pages with trait references
2428
+ - domainContext with category, vocabulary, and requestFragment
2429
+ - design with style and uxHints (flowPattern, listPattern, formPattern)
2430
+ ${orbital.emits?.length ? "- PRESERVE emits: " + orbital.emits.map((e) => e.event).join(", ") : ""}
2431
+ ${orbital.listens?.length ? "- PRESERVE listens: " + orbital.listens.map((l) => l.event).join(", ") : ""}`;
2432
+ }
2433
+ function buildOutputSection(orbitals) {
2434
+ return `---
2435
+ ## OUTPUT FORMAT
2436
+
2437
+ Return a JSON object with this exact structure:
2438
+
2439
+ \`\`\`json
2440
+ {
2441
+ "orbitals": [
2442
+ ${orbitals.map((o, i) => ` {
2443
+ "name": "${o.name}",
2444
+ // ... complete FullOrbitalUnit for ${o.name}
2445
+ }${i < orbitals.length - 1 ? "," : ""}`).join("\n")}
2446
+ ]
2447
+ }
2448
+ \`\`\`
2449
+
2450
+ **CRITICAL RULES:**
2451
+ 1. Return a SINGLE JSON object with an "orbitals" array
2452
+ 2. Each element in the array is a complete FullOrbitalUnit
2453
+ 3. Maintain the order: ${orbitals.map((o) => o.name).join(", ")}
2454
+ 4. PRESERVE all emits/listens as specified in each orbital section
2455
+ 5. Use shared domain vocabulary consistently across all orbitals
2456
+ 6. Ensure cross-orbital event wiring is maintained
2457
+ `;
2458
+ }
2459
+ function generateBatchFingerprint(orbitals) {
2460
+ const fingerprints = orbitals.map((o) => computeOrbitalFingerprint(o));
2461
+ const combined = fingerprints.sort().join("|");
2462
+ let hash = 0;
2463
+ for (let i = 0; i < combined.length; i++) {
2464
+ const char = combined.charCodeAt(i);
2465
+ hash = (hash << 5) - hash + char;
2466
+ hash = hash & hash;
2467
+ }
2468
+ return `batch:${orbitals.length}:${Math.abs(hash).toString(16).slice(0, 8)}`;
2469
+ }
2470
+ function splitIntoBatches(orbitals, options = {}) {
2471
+ const {
2472
+ maxBatchSize = 3,
2473
+ preserveRelationships = true
2474
+ } = options;
2475
+ if (!preserveRelationships) {
2476
+ return chunkArray(orbitals, maxBatchSize);
2477
+ }
2478
+ const clusters = groupByRelationships(orbitals);
2479
+ const batches = [];
2480
+ for (const cluster of clusters) {
2481
+ if (cluster.length <= maxBatchSize) {
2482
+ batches.push(cluster);
2483
+ } else {
2484
+ batches.push(...chunkArray(cluster, maxBatchSize));
2485
+ }
2486
+ }
2487
+ return batches;
2488
+ }
2489
+ function groupByRelationships(orbitals) {
2490
+ const visited = /* @__PURE__ */ new Set();
2491
+ const clusters = [];
2492
+ const adjacency = /* @__PURE__ */ new Map();
2493
+ for (const orbital of orbitals) {
2494
+ if (!adjacency.has(orbital.name)) {
2495
+ adjacency.set(orbital.name, /* @__PURE__ */ new Set());
2496
+ }
2497
+ if (orbital.emits) {
2498
+ for (const event of orbital.emits) {
2499
+ for (const other of orbitals) {
2500
+ if (other === orbital) continue;
2501
+ if (other.listens?.some((l) => l.event === event.event)) {
2502
+ adjacency.get(orbital.name)?.add(other.name);
2503
+ if (!adjacency.has(other.name)) {
2504
+ adjacency.set(other.name, /* @__PURE__ */ new Set());
2505
+ }
2506
+ adjacency.get(other.name)?.add(orbital.name);
2507
+ }
2508
+ }
2509
+ }
2510
+ }
2511
+ }
2512
+ function dfs(orbital, cluster) {
2513
+ visited.add(orbital.name);
2514
+ cluster.push(orbital);
2515
+ const neighbors = adjacency.get(orbital.name) || /* @__PURE__ */ new Set();
2516
+ for (const neighborName of neighbors) {
2517
+ if (!visited.has(neighborName)) {
2518
+ const neighbor = orbitals.find((o) => o.name === neighborName);
2519
+ if (neighbor) {
2520
+ dfs(neighbor, cluster);
2521
+ }
2522
+ }
2523
+ }
2524
+ }
2525
+ for (const orbital of orbitals) {
2526
+ if (!visited.has(orbital.name)) {
2527
+ const cluster = [];
2528
+ dfs(orbital, cluster);
2529
+ clusters.push(cluster);
2530
+ }
2531
+ }
2532
+ return clusters;
2533
+ }
2534
+ function estimateBatchTokens(orbitals) {
2535
+ const baseTokens = 2e3;
2536
+ const perOrbitalTokens = 800;
2537
+ return baseTokens + orbitals.length * perOrbitalTokens;
2538
+ }
2539
+ function willBatchFit(orbitals, maxTokens = 12e3) {
2540
+ const estimated = estimateBatchTokens(orbitals);
2541
+ return estimated < maxTokens * 0.5;
2542
+ }
2543
+
2544
+ // src/orbitals/batch/concurrency.ts
2545
+ function createConcurrencyController(maxConcurrency) {
2546
+ let activeCount = 0;
2547
+ const queue = [];
2548
+ return {
2549
+ async acquire() {
2550
+ if (activeCount < maxConcurrency) {
2551
+ activeCount++;
2552
+ return Promise.resolve();
2553
+ }
2554
+ return new Promise((resolve2) => {
2555
+ queue.push(() => {
2556
+ activeCount++;
2557
+ resolve2();
2558
+ });
2559
+ });
2560
+ },
2561
+ release() {
2562
+ activeCount = Math.max(0, activeCount - 1);
2563
+ const next = queue.shift();
2564
+ if (next) {
2565
+ next();
2566
+ }
2567
+ },
2568
+ get activeCount() {
2569
+ return activeCount;
2570
+ },
2571
+ get waitingCount() {
2572
+ return queue.length;
2573
+ }
2574
+ };
2575
+ }
2576
+ async function runWithConcurrency(tasks, options) {
2577
+ const { concurrency, onProgress } = options;
2578
+ const controller = createConcurrencyController(concurrency);
2579
+ const results = [];
2580
+ let completed = 0;
2581
+ await Promise.all(
2582
+ tasks.map(async (task, index) => {
2583
+ await controller.acquire();
2584
+ try {
2585
+ results[index] = await task();
2586
+ completed++;
2587
+ onProgress?.(completed, tasks.length);
2588
+ } finally {
2589
+ controller.release();
2590
+ }
2591
+ })
2592
+ );
2593
+ return results;
2594
+ }
2595
+ async function asyncMapWithConcurrency2(items, mapper, concurrency) {
2596
+ return runWithConcurrency(
2597
+ items.map((item, index) => () => mapper(item, index)),
2598
+ { concurrency }
2599
+ );
2600
+ }
2601
+
2602
+ // src/orbitals/batch/batch-generator.ts
2603
+ async function generateOrbitalsBatch(client, orbitals, options = {}) {
2604
+ const startTime = Date.now();
2605
+ const aggregateLogs = [];
2606
+ const provider = client.getProvider();
2607
+ const mode = options.mode || "single-call";
2608
+ const maxConcurrency = options.concurrency ?? PROVIDER_CONCURRENCY_LIMITS[provider];
2609
+ const maxBatchSize = options.batchSize ?? PROVIDER_BATCH_SIZES[provider];
2610
+ console.log(`[BatchGenerator] Starting batch generation: ${orbitals.length} orbitals, mode=${mode}, concurrency=${maxConcurrency}`);
2611
+ aggregateLogs.push(createLog("info", `Starting batch generation`, {
2612
+ totalOrbitals: orbitals.length,
2613
+ mode,
2614
+ provider,
2615
+ maxConcurrency,
2616
+ maxBatchSize
2617
+ }));
2618
+ const batches = splitIntoBatches(orbitals, {
2619
+ maxBatchSize,
2620
+ preserveRelationships: options.preserveRelationships ?? true
2621
+ });
2622
+ console.log(`[BatchGenerator] Split into ${batches.length} batches: [${batches.map((b) => b.length).join(", ")}]`);
2623
+ aggregateLogs.push(createLog("info", `Split into ${batches.length} batches`, {
2624
+ batchSizes: batches.map((b) => b.length)
2625
+ }));
2626
+ options.onBatchProgress?.({
2627
+ type: "batch_start",
2628
+ batchIndex: 0,
2629
+ totalBatches: batches.length,
2630
+ completedOrbitals: 0,
2631
+ totalOrbitals: orbitals.length
2632
+ });
2633
+ let batchResults;
2634
+ if (mode === "parallel-individual") {
2635
+ batchResults = await generateParallelIndividual(client, orbitals, {
2636
+ ...options,
2637
+ concurrency: maxConcurrency,
2638
+ onBatchProgress: options.onBatchProgress
2639
+ });
2640
+ } else if (mode === "single-call") {
2641
+ batchResults = await generateSingleCallBatches(client, batches, {
2642
+ ...options,
2643
+ concurrency: maxConcurrency,
2644
+ onBatchProgress: options.onBatchProgress
2645
+ });
2646
+ } else {
2647
+ batchResults = await generateAdaptive(client, orbitals, batches, {
2648
+ ...options,
2649
+ concurrency: maxConcurrency,
2650
+ maxBatchSize,
2651
+ onBatchProgress: options.onBatchProgress
2652
+ });
2653
+ }
2654
+ const totalDurationMs = Date.now() - startTime;
2655
+ const allResults = batchResults.flatMap((b) => b.results);
2656
+ const successful = allResults.filter((r) => r.success).length;
2657
+ const failed = allResults.length - successful;
2658
+ const totalTokens = batchResults.reduce(
2659
+ (sum, b) => sum + (b.usage?.totalTokens ?? 0),
2660
+ 0
2661
+ );
2662
+ console.log(`[BatchGenerator] Complete: ${successful}/${allResults.length} successful, ${totalTokens} tokens, ${totalDurationMs}ms`);
2663
+ aggregateLogs.push(createLog("info", `Batch generation completed`, {
2664
+ totalDurationMs,
2665
+ successful,
2666
+ failed,
2667
+ totalTokens,
2668
+ totalBatches: batches.length
2669
+ }));
2670
+ options.onBatchProgress?.({
2671
+ type: "batch_complete",
2672
+ batchIndex: batches.length - 1,
2673
+ totalBatches: batches.length,
2674
+ completedOrbitals: successful,
2675
+ totalOrbitals: orbitals.length
2676
+ });
2677
+ return {
2678
+ results: allResults.map((r) => ({
2679
+ orbital: r.orbital,
2680
+ fingerprint: "",
2681
+ // TODO: compute from orbital
2682
+ usedTemplate: false,
2683
+ usage: void 0,
2684
+ validation: r.success ? { valid: true, errorCount: 0, warningCount: 0 } : { valid: false, errorCount: 1, warningCount: 0 },
2685
+ logs: []
2686
+ })),
2687
+ totalDurationMs,
2688
+ aggregateLogs,
2689
+ summary: {
2690
+ total: allResults.length,
2691
+ successful,
2692
+ failed,
2693
+ totalTokens
2694
+ },
2695
+ batchResults,
2696
+ totalBatches: batches.length
2697
+ };
2698
+ }
2699
+ async function generateSingleCallBatches(client, batches, options) {
2700
+ let completedOrbitals = 0;
2701
+ const totalOrbitals = batches.reduce((sum, b) => sum + b.length, 0);
2702
+ return asyncMapWithConcurrency2(
2703
+ batches,
2704
+ async (batch, batchIndex) => {
2705
+ return generateSingleBatch(client, batch, batchIndex, {
2706
+ ...options,
2707
+ onProgress: (completedInBatch) => {
2708
+ const newCompleted = completedOrbitals + completedInBatch;
2709
+ options.onBatchProgress?.({
2710
+ type: "orbital_complete",
2711
+ batchIndex,
2712
+ totalBatches: batches.length,
2713
+ completedOrbitals: newCompleted,
2714
+ totalOrbitals
2715
+ });
2716
+ completedOrbitals = newCompleted;
2717
+ }
2718
+ });
2719
+ },
2720
+ options.concurrency
2721
+ );
2722
+ }
2723
+ async function generateParallelIndividual(client, orbitals, options) {
2724
+ const batches = orbitals.map((o) => [o]);
2725
+ return generateSingleCallBatches(client, batches, {
2726
+ ...options,
2727
+ concurrency: options.concurrency
2728
+ });
2729
+ }
2730
+ async function generateAdaptive(client, orbitals, batches, options) {
2731
+ const allFit = batches.every((batch) => willBatchFit(batch, BATCH_MAX_TOKENS));
2732
+ if (allFit) {
2733
+ console.log(`[BatchGenerator] Adaptive: Using single-call batches (${batches.length} batches)`);
2734
+ return generateSingleCallBatches(client, batches, options);
2735
+ }
2736
+ console.log(`[BatchGenerator] Adaptive: Using parallel-individual (batches too large)`);
2737
+ return generateParallelIndividual(client, orbitals, options);
2738
+ }
2739
+ async function generateSingleBatch(client, orbitals, batchIndex, options) {
2740
+ const batchStartTime = Date.now();
2741
+ const logs = [];
2742
+ console.log(`[BatchGenerator] Starting batch ${batchIndex + 1}: ${orbitals.map((o) => o.name).join(", ")}`);
2743
+ logs.push(createLog("info", `Starting batch ${batchIndex + 1}`, {
2744
+ orbitalCount: orbitals.length,
2745
+ orbitals: orbitals.map((o) => o.name)
2746
+ }));
2747
+ try {
2748
+ const batchPrompt = assembleBatchPrompt(orbitals);
2749
+ console.log(`[BatchGenerator] Batch ${batchIndex + 1} prompt assembled: ${batchPrompt.prompt.length} chars`);
2750
+ logs.push(createLog("info", `Batch prompt assembled`, {
2751
+ promptLength: batchPrompt.prompt.length,
2752
+ estimatedTokens: Math.ceil(batchPrompt.prompt.length / 4)
2753
+ }));
2754
+ const llmResult = await client.callWithMetadata({
2755
+ systemPrompt: batchPrompt.prompt,
2756
+ userPrompt: "Generate all orbitals in the batch. Return valid JSON matching the output format specified.",
2757
+ maxTokens: BATCH_MAX_TOKENS,
2758
+ skipSchemaValidation: true
2759
+ });
2760
+ logs.push(createLog("info", `LLM call completed`, {
2761
+ promptTokens: llmResult.usage?.promptTokens,
2762
+ completionTokens: llmResult.usage?.completionTokens
2763
+ }));
2764
+ const parsed = parseBatchResult(llmResult.data, orbitals);
2765
+ console.log(`[BatchGenerator] Batch ${batchIndex + 1} parsed: ${parsed.filter((p) => p.success).length}/${parsed.length} successful`);
2766
+ for (let i = 0; i < parsed.length; i++) {
2767
+ options.onProgress?.(i + 1);
2768
+ }
2769
+ const durationMs = Date.now() - batchStartTime;
2770
+ logs.push(createLog("info", `Batch ${batchIndex + 1} completed`, {
2771
+ durationMs,
2772
+ successful: parsed.filter((r) => r.success).length
2773
+ }));
2774
+ return {
2775
+ orbitals,
2776
+ results: parsed,
2777
+ usage: llmResult.usage ?? void 0,
2778
+ durationMs,
2779
+ logs
2780
+ };
2781
+ } catch (error) {
2782
+ const errorMessage = getErrorMessage(error);
2783
+ console.error(`[BatchGenerator] Batch ${batchIndex + 1} FAILED: ${errorMessage}`);
2784
+ logs.push(createLog("error", `Batch ${batchIndex + 1} failed`, {
2785
+ error: errorMessage
2786
+ }));
2787
+ return {
2788
+ orbitals,
2789
+ results: orbitals.map((o) => ({
2790
+ orbital: o,
2791
+ success: false,
2792
+ error: errorMessage
2793
+ })),
2794
+ durationMs: Date.now() - batchStartTime,
2795
+ logs
2796
+ };
2797
+ }
2798
+ }
2799
+ function parseBatchResult(data, expectedOrbitals) {
2800
+ if (!data || typeof data !== "object") {
2801
+ return expectedOrbitals.map((o) => ({
2802
+ orbital: o,
2803
+ success: false,
2804
+ error: "Invalid response: expected object"
2805
+ }));
2806
+ }
2807
+ const obj = data;
2808
+ if (!obj.orbitals || !Array.isArray(obj.orbitals)) {
2809
+ return expectedOrbitals.map((o) => ({
2810
+ orbital: o,
2811
+ success: false,
2812
+ error: "Invalid response: missing orbitals array"
2813
+ }));
2814
+ }
2815
+ const results = obj.orbitals;
2816
+ return expectedOrbitals.map((expected, index) => {
2817
+ const result = results[index];
2818
+ if (!result) {
2819
+ return {
2820
+ orbital: expected,
2821
+ success: false,
2822
+ error: `Missing result for orbital ${index + 1}`
2823
+ };
2824
+ }
2825
+ if (!result.name) {
2826
+ return {
2827
+ orbital: expected,
2828
+ success: false,
2829
+ error: "Generated orbital missing name"
2830
+ };
2831
+ }
2832
+ return {
2833
+ orbital: result,
2834
+ success: true
2835
+ };
2836
+ });
2837
+ }
2838
+
2839
+ // src/tools/orbital-batch-subagent.ts
2840
+ var OrbitalBatchInputSchema = z.object({
2841
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2842
+ orbitals: z.array(z.any()).describe("Array of OrbitalUnits to generate"),
2843
+ options: z.object({
2844
+ mode: z.enum(["single-call", "parallel-individual", "adaptive"]).optional().default("adaptive"),
2845
+ batchSize: z.number().optional(),
2846
+ maxConcurrency: z.number().optional(),
2847
+ preserveRelationships: z.boolean().optional().default(true)
2848
+ }).optional().describe("Batch generation options")
2849
+ });
2850
+ function createOrbitalBatchSubagentTool(options = {}) {
2851
+ let eventCallback = options.onSubagentEvent;
2852
+ let completeCallback = options.onBatchComplete;
2853
+ const requirements = options.requirements;
2854
+ const workDir = options.workDir;
2855
+ const setEventCallback = (callback) => {
2856
+ eventCallback = callback;
2857
+ };
2858
+ const setBatchCompleteCallback = (callback) => {
2859
+ completeCallback = callback;
2860
+ };
2861
+ const emitEvent = (orbitalName, orbitalIndex, totalOrbitals, type, data) => {
2862
+ if (eventCallback) {
2863
+ eventCallback(orbitalName, orbitalIndex, totalOrbitals, {
2864
+ type,
2865
+ data,
2866
+ timestamp: Date.now()
2867
+ });
2868
+ }
2869
+ };
2870
+ const batchTool = tool(
2871
+ async ({ orbitals, options: batchOptions }) => {
2872
+ if (!orbitals || orbitals.length === 0) {
2873
+ return JSON.stringify({
2874
+ success: false,
2875
+ error: "No orbitals provided for batch generation.",
2876
+ orbitals: []
2877
+ });
2878
+ }
2879
+ console.log(`[OrbitalBatchSubagent] Starting batch generation for ${orbitals.length} orbitals`);
2880
+ try {
2881
+ emitEvent("batch", 0, 1, "message", {
2882
+ content: `Starting batch generation for ${orbitals.length} orbitals`,
2883
+ role: "assistant",
2884
+ isComplete: false
2885
+ });
2886
+ emitEvent("batch", 0, 1, "todo_update", {
2887
+ todos: orbitals.map((o, i) => ({
2888
+ id: `orbital-${i}`,
2889
+ task: `Generate ${o.name}`,
2890
+ status: "pending"
2891
+ }))
2892
+ });
2893
+ const client = new LLMClient({
2894
+ provider: options.provider || "anthropic",
2895
+ model: options.model || "claude-sonnet-4-20250514"
2896
+ });
2897
+ const generationOptions = {
2898
+ mode: batchOptions?.mode || "adaptive",
2899
+ batchSize: batchOptions?.batchSize,
2900
+ concurrency: batchOptions?.maxConcurrency ?? PROVIDER_CONCURRENCY_LIMITS[client.getProvider()],
2901
+ preserveRelationships: batchOptions?.preserveRelationships ?? true,
2902
+ requirements,
2903
+ onBatchProgress: (event) => {
2904
+ if (event.type === "orbital_complete" && event.orbitalName) {
2905
+ emitEvent(event.orbitalName || "batch", event.batchIndex, event.totalBatches, "todo_update", {
2906
+ todos: orbitals.map((o, i) => ({
2907
+ id: `orbital-${i}`,
2908
+ task: `Generate ${o.name}`,
2909
+ status: o.name === event.orbitalName ? "completed" : event.completedOrbitals > i ? "completed" : "pending"
2910
+ }))
2911
+ });
2912
+ }
2913
+ emitEvent(event.orbitalName || "batch", event.batchIndex, event.totalBatches, "generation_log", {
2914
+ level: "info",
2915
+ message: `Progress: ${event.completedOrbitals}/${event.totalOrbitals} orbitals complete`,
2916
+ data: {
2917
+ batchIndex: event.batchIndex,
2918
+ completedOrbitals: event.completedOrbitals,
2919
+ totalOrbitals: event.totalOrbitals
2920
+ }
2921
+ });
2922
+ }
2923
+ };
2924
+ emitEvent("batch", 0, 1, "tool_call", {
2925
+ tool: "generateOrbitalsBatch",
2926
+ args: {
2927
+ orbitalCount: orbitals.length,
2928
+ mode: generationOptions.mode,
2929
+ concurrency: generationOptions.concurrency
2930
+ }
2931
+ });
2932
+ const result = await generateOrbitalsBatch(client, orbitals, generationOptions);
2933
+ emitEvent("batch", result.totalBatches - 1, result.totalBatches, "todo_update", {
2934
+ todos: orbitals.map((o, i) => ({
2935
+ id: `orbital-${i}`,
2936
+ task: `Generate ${o.name}`,
2937
+ status: result.batchResults.some(
2938
+ (b) => b.results.some((r) => r.orbital.name === o.name && r.success)
2939
+ ) ? "completed" : "failed"
2940
+ }))
2941
+ });
2942
+ const generatedOrbitals = result.results.filter((r) => r.orbital).map((r) => r.orbital);
2943
+ const successCount = generatedOrbitals.length;
2944
+ const failedCount = orbitals.length - successCount;
2945
+ emitEvent("batch", result.totalBatches - 1, result.totalBatches, "message", {
2946
+ content: `Batch generation complete: ${successCount}/${orbitals.length} orbitals generated successfully`,
2947
+ role: "assistant",
2948
+ isComplete: true
2949
+ });
2950
+ if (workDir && completeCallback && generatedOrbitals.length > 0) {
2951
+ try {
2952
+ await completeCallback(generatedOrbitals, 0, 1);
2953
+ emitEvent("batch", result.totalBatches - 1, result.totalBatches, "generation_log", {
2954
+ level: "info",
2955
+ message: `Persisted ${generatedOrbitals.length} orbitals`
2956
+ });
2957
+ } catch (persistError) {
2958
+ console.error(`[OrbitalBatchSubagent] Failed to persist orbitals:`, persistError);
2959
+ emitEvent("batch", result.totalBatches - 1, result.totalBatches, "generation_log", {
2960
+ level: "warn",
2961
+ message: "Failed to persist some orbitals",
2962
+ data: { error: String(persistError) }
2963
+ });
2964
+ }
2965
+ }
2966
+ return JSON.stringify({
2967
+ success: successCount === orbitals.length,
2968
+ generated: successCount,
2969
+ failed: failedCount,
2970
+ total: orbitals.length,
2971
+ orbitals: generatedOrbitals,
2972
+ duration: result.totalDurationMs,
2973
+ totalTokens: result.summary.totalTokens,
2974
+ batches: result.totalBatches
2975
+ });
2976
+ } catch (error) {
2977
+ const errorMessage = error instanceof Error ? error.message : String(error);
2978
+ console.error(`[OrbitalBatchSubagent] Batch generation failed:`, errorMessage);
2979
+ emitEvent("batch", 0, 1, "error", {
2980
+ error: errorMessage,
2981
+ code: "BATCH_GENERATION_ERROR"
2982
+ });
2983
+ return JSON.stringify({
2984
+ success: false,
2985
+ error: errorMessage,
2986
+ orbitals: []
2987
+ });
2988
+ }
2989
+ },
2990
+ {
2991
+ name: "generate_orbitals_batch",
2992
+ description: "Generate multiple orbitals in optimized batches. MUCH FASTER than calling generate_orbital multiple times. Use this when generating 3+ orbitals. Supports parallel generation with automatic concurrency control.",
2993
+ schema: OrbitalBatchInputSchema
2994
+ }
2995
+ );
2996
+ return {
2997
+ tool: batchTool,
2998
+ setEventCallback,
2999
+ setBatchCompleteCallback
3000
+ };
3001
+ }
2216
3002
  function getTraitGenerationPrompt() {
2217
3003
  return `You are a Trait Generator for KFlow orbital schemas.
2218
3004
 
@@ -3231,6 +4017,6 @@ function createAgentTools(workDir) {
3231
4017
  };
3232
4018
  }
3233
4019
 
3234
- export { createAgentTools, createApplyChunkTool, createCombineSchemasTool, createConstructCombinedDomainTool, createDomainOrbitalTools, createExecuteTool, createExtractChunkTool, createFinishTaskTool, createGenerateOrbitalDomainTool, createGenerateSchemaTool, createGitHubTools, createGitHubToolsArray, createOrbitalSubagentTool, createQuerySchemaStructureTool, createSchemaChunkingTools, createSubagentEventWrapper, createTraitEventWrapper, createTraitSubagentTool, createValidateSchemaTool, validateCommandPaths };
4020
+ export { createAgentTools, createApplyChunkTool, createCombineSchemasTool, createConstructCombinedDomainTool, createDomainOrbitalTools, createExecuteTool, createExtractChunkTool, createFinishTaskTool, createGenerateOrbitalDomainTool, createGenerateSchemaTool, createGitHubTools, createGitHubToolsArray, createOrbitalBatchSubagentTool, createOrbitalSubagentTool, createQuerySchemaStructureTool, createSchemaChunkingTools, createSubagentEventWrapper, createTraitEventWrapper, createTraitSubagentTool, createValidateSchemaTool, validateCommandPaths };
3235
4021
  //# sourceMappingURL=index.js.map
3236
4022
  //# sourceMappingURL=index.js.map