@almadar/agent 1.3.0 → 1.3.1

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.
@@ -1,11 +1,12 @@
1
1
  import { AgentDomainCategorySchema, isOrbitalDefinition, isEntityReference, getTraitName } from '@almadar/core/types';
2
+ import { getFullOrbitalPrompt, getRequirementsTraitPrompt, getKeyBehaviorsReference, getSExprQuickRef, getCommonErrorsSection, getArchitectureSection } from '@almadar/skills';
3
+ import { tool } from '@langchain/core/tools';
4
+ import { z } from 'zod';
5
+ import { LLMClient, ANTHROPIC_MODELS, createAnthropicClient, OPENROUTER_MODELS, createOpenRouterClient, KIMI_MODELS, createKimiClient, OPENAI_MODELS, createOpenAIClient, DEEPSEEK_MODELS, createDeepSeekClient } from '@almadar/llm';
2
6
  import { FilesystemBackend, createDeepAgent } from 'deepagents';
3
7
  import { MemorySaver } from '@langchain/langgraph';
4
8
  export { Command } from '@langchain/langgraph';
5
9
  import { v4 } from 'uuid';
6
- import { ANTHROPIC_MODELS, createAnthropicClient, OPENAI_MODELS, createOpenAIClient, DEEPSEEK_MODELS, createDeepSeekClient, LLMClient } from '@almadar/llm';
7
- import { tool } from '@langchain/core/tools';
8
- import { z } from 'zod';
9
10
  import { exec, spawn } from 'child_process';
10
11
  import * as path from 'path';
11
12
  import { promisify } from 'util';
@@ -13,7 +14,6 @@ import * as fs4 from 'fs/promises';
13
14
  import * as domain_language_star from '@almadar/core/domain-language';
14
15
  import * as fs3 from 'fs';
15
16
  import crypto, { randomUUID } from 'crypto';
16
- import { getFullOrbitalPrompt, getRequirementsTraitPrompt, getKeyBehaviorsReference, getSExprQuickRef, getCommonErrorsSection, getArchitectureSection } from '@almadar/skills';
17
17
  import { GitHubIntegration } from '@almadar/integrations';
18
18
  import { BaseCheckpointSaver } from '@langchain/langgraph-checkpoint';
19
19
 
@@ -308,6 +308,855 @@ var init_cache = __esm({
308
308
  init_prompt_assembler();
309
309
  }
310
310
  });
311
+
312
+ // src/orbitals/shared/constants.ts
313
+ var PROVIDER_CONCURRENCY_LIMITS, PROVIDER_BATCH_SIZES, BATCH_MAX_TOKENS;
314
+ var init_constants = __esm({
315
+ "src/orbitals/shared/constants.ts"() {
316
+ PROVIDER_CONCURRENCY_LIMITS = {
317
+ anthropic: 3,
318
+ openai: 5,
319
+ deepseek: 3,
320
+ kimi: 3,
321
+ openrouter: 5
322
+ };
323
+ PROVIDER_BATCH_SIZES = {
324
+ anthropic: 3,
325
+ // Anthropic works well with 3 orbitals per call
326
+ openai: 5,
327
+ // OpenAI can handle more
328
+ deepseek: 3,
329
+ // Conservative for DeepSeek
330
+ kimi: 3,
331
+ // Conservative for Kimi
332
+ openrouter: 5
333
+ // OpenRouter proxies multiple providers
334
+ };
335
+ BATCH_MAX_TOKENS = 12e3;
336
+ }
337
+ });
338
+ function getEntityName2(entity) {
339
+ if (isEntityReference(entity)) {
340
+ return entity.replace(".entity", "");
341
+ }
342
+ return entity.name;
343
+ }
344
+ function getInlineEntity3(entity) {
345
+ if (isEntityReference(entity)) {
346
+ return null;
347
+ }
348
+ return entity;
349
+ }
350
+ function getFieldNames(entity) {
351
+ const inlineEntity = getInlineEntity3(entity);
352
+ if (!inlineEntity?.fields?.length) {
353
+ return "N/A";
354
+ }
355
+ return inlineEntity.fields.map((f) => f.name).join(", ");
356
+ }
357
+ function createLog(level, message, data) {
358
+ return {
359
+ timestamp: Date.now(),
360
+ level,
361
+ message,
362
+ data
363
+ };
364
+ }
365
+ function buildContextSection2(orbital) {
366
+ const parts = [];
367
+ if (orbital.domainContext) {
368
+ const ctx = orbital.domainContext;
369
+ parts.push(`DomainContext: category=${ctx.category || "business"}`);
370
+ if (ctx.vocabulary) {
371
+ parts.push(`Vocabulary: ${JSON.stringify(ctx.vocabulary)}`);
372
+ }
373
+ if (ctx.requestFragment) {
374
+ parts.push(`RequestFragment: "${ctx.requestFragment}"`);
375
+ }
376
+ }
377
+ if (orbital.design) {
378
+ const d = orbital.design;
379
+ if (d.style) parts.push(`Style: ${d.style}`);
380
+ if (d.uxHints) {
381
+ const hints = d.uxHints;
382
+ if (hints.flowPattern) parts.push(`FlowPattern: ${hints.flowPattern}`);
383
+ if (hints.listPattern) parts.push(`ListPattern: ${hints.listPattern}`);
384
+ if (hints.formPattern) parts.push(`FormPattern: ${hints.formPattern}`);
385
+ }
386
+ }
387
+ return parts.length > 0 ? `Context: ${parts.join(", ")}
388
+ ` : "";
389
+ }
390
+ function buildConnectivitySection(orbital) {
391
+ const parts = [];
392
+ if (orbital.emits?.length) {
393
+ parts.push(`Emits: ${orbital.emits.join(", ")}`);
394
+ }
395
+ if (orbital.listens?.length) {
396
+ parts.push(`Listens: ${orbital.listens.map((l) => `${l.event}\u2192${l.triggers}`).join(", ")}`);
397
+ }
398
+ return parts.join("\n");
399
+ }
400
+ function chunkArray(array, size) {
401
+ const chunks = [];
402
+ for (let i = 0; i < array.length; i += size) {
403
+ chunks.push(array.slice(i, i + size));
404
+ }
405
+ return chunks;
406
+ }
407
+ function getErrorMessage(error) {
408
+ if (error instanceof Error) {
409
+ return error.message;
410
+ }
411
+ return String(error);
412
+ }
413
+ var init_utils = __esm({
414
+ "src/orbitals/shared/utils.ts"() {
415
+ }
416
+ });
417
+
418
+ // src/orbitals/shared/index.ts
419
+ var init_shared = __esm({
420
+ "src/orbitals/shared/index.ts"() {
421
+ init_constants();
422
+ init_utils();
423
+ }
424
+ });
425
+ function extractSharedContext(orbitals) {
426
+ const vocabulary = {};
427
+ const styles = /* @__PURE__ */ new Set();
428
+ const patterns = /* @__PURE__ */ new Set();
429
+ const relationships = [];
430
+ for (const orbital of orbitals) {
431
+ if (orbital.domainContext?.vocabulary) {
432
+ Object.assign(vocabulary, orbital.domainContext.vocabulary);
433
+ }
434
+ if (orbital.design?.style) {
435
+ styles.add(orbital.design.style);
436
+ }
437
+ }
438
+ new Map(orbitals.map((o) => [o.name, o]));
439
+ for (const orbital of orbitals) {
440
+ if (orbital.emits) {
441
+ for (const event of orbital.emits) {
442
+ for (const other of orbitals) {
443
+ if (other === orbital) continue;
444
+ if (other.listens) {
445
+ const listener = other.listens.find((l) => l.event === event.event);
446
+ if (listener) {
447
+ relationships.push({
448
+ emitter: orbital.name,
449
+ event: event.event,
450
+ listener: other.name,
451
+ handler: listener.triggers
452
+ });
453
+ }
454
+ }
455
+ }
456
+ }
457
+ }
458
+ }
459
+ return {
460
+ domainVocabulary: Object.keys(vocabulary).length > 0 ? vocabulary : void 0,
461
+ designStyle: styles.size === 1 ? Array.from(styles)[0] : void 0,
462
+ commonPatterns: patterns.size > 0 ? Array.from(patterns) : void 0,
463
+ eventRelationships: relationships.length > 0 ? relationships : void 0
464
+ };
465
+ }
466
+ function assembleBatchPrompt(orbitals, options = {}) {
467
+ const {
468
+ baseSystemPrompt = getFullOrbitalPrompt(),
469
+ includeConnectivity = true
470
+ } = options;
471
+ if (orbitals.length === 0) {
472
+ throw new Error("Cannot assemble batch prompt for empty orbitals array");
473
+ }
474
+ const sharedContext = extractSharedContext(orbitals);
475
+ const batchHeader = buildBatchHeader(orbitals, sharedContext);
476
+ const orbitalSections = orbitals.map(
477
+ (orbital, index) => buildOrbitalSection(orbital, index + 1, orbitals.length, includeConnectivity)
478
+ );
479
+ const outputSection = buildOutputSection(orbitals);
480
+ const prompt = `${baseSystemPrompt}
481
+
482
+ ${"=".repeat(60)}
483
+ BATCH GENERATION: ${orbitals.length} ORBITALS
484
+ ${"=".repeat(60)}
485
+
486
+ ${batchHeader}
487
+
488
+ ${orbitalSections.join("\n\n")}
489
+
490
+ ${outputSection}`;
491
+ const fingerprint = generateBatchFingerprint(orbitals);
492
+ return {
493
+ prompt,
494
+ fingerprint,
495
+ usedCachedTemplate: false,
496
+ // Batch doesn't use templates yet
497
+ orbitalCount: orbitals.length,
498
+ orbitalNames: orbitals.map((o) => o.name)
499
+ };
500
+ }
501
+ function buildBatchHeader(orbitals, sharedContext) {
502
+ const lines = [
503
+ `## Batch Overview`,
504
+ `- Total Orbitals: ${orbitals.length}`,
505
+ `- Orbitals: ${orbitals.map((o) => o.name).join(", ")}`
506
+ ];
507
+ if (sharedContext.designStyle) {
508
+ lines.push(`- Design Style: ${sharedContext.designStyle}`);
509
+ }
510
+ if (sharedContext.commonPatterns?.length) {
511
+ lines.push(`- Common Patterns: ${sharedContext.commonPatterns.join(", ")}`);
512
+ }
513
+ if (sharedContext.domainVocabulary && Object.keys(sharedContext.domainVocabulary).length > 0) {
514
+ lines.push(`
515
+ ## Shared Domain Vocabulary`);
516
+ for (const [term, definition] of Object.entries(sharedContext.domainVocabulary)) {
517
+ lines.push(`- ${term}: ${definition}`);
518
+ }
519
+ }
520
+ if (sharedContext.eventRelationships?.length) {
521
+ lines.push(`
522
+ ## Cross-Orbital Event Relationships`);
523
+ for (const rel of sharedContext.eventRelationships) {
524
+ lines.push(`- ${rel.emitter} emits "${rel.event}" \u2192 ${rel.listener} handles with "${rel.handler}"`);
525
+ }
526
+ }
527
+ return lines.join("\n");
528
+ }
529
+ function buildOrbitalSection(orbital, index, total, includeConnectivity) {
530
+ const entityName = getEntityName2(orbital.entity);
531
+ const fieldNames = getFieldNames(orbital.entity);
532
+ const contextSection = buildContextSection2(orbital);
533
+ const connectivitySection = includeConnectivity ? buildConnectivitySection(orbital) : "";
534
+ return `---
535
+ ## ORBITAL ${index}/${total}: ${orbital.name}
536
+
537
+ **Entity**: ${entityName}
538
+ **Persistence**: ${orbital.entity.persistence || "persistent"}
539
+ **Fields**: ${fieldNames}
540
+ **Traits**: ${orbital.traits.map((t) => typeof t === "string" ? t : "ref" in t ? t.ref : t.name).join(", ")}
541
+ ${contextSection}${connectivitySection ? `**Connectivity**:
542
+ ${connectivitySection}
543
+ ` : ""}
544
+ Generate a complete FullOrbitalUnit for ${orbital.name} with:
545
+ - Full field definitions with types and validation
546
+ - Trait state machines with transitions and effects
547
+ - Business rule validation using "guard" S-expression on SAVE transitions
548
+ - Pages with trait references
549
+ - domainContext with category, vocabulary, and requestFragment
550
+ - design with style and uxHints (flowPattern, listPattern, formPattern)
551
+ ${orbital.emits?.length ? "- PRESERVE emits: " + orbital.emits.map((e) => e.event).join(", ") : ""}
552
+ ${orbital.listens?.length ? "- PRESERVE listens: " + orbital.listens.map((l) => l.event).join(", ") : ""}`;
553
+ }
554
+ function buildOutputSection(orbitals) {
555
+ return `---
556
+ ## OUTPUT FORMAT
557
+
558
+ Return a JSON object with this exact structure:
559
+
560
+ \`\`\`json
561
+ {
562
+ "orbitals": [
563
+ ${orbitals.map((o, i) => ` {
564
+ "name": "${o.name}",
565
+ // ... complete FullOrbitalUnit for ${o.name}
566
+ }${i < orbitals.length - 1 ? "," : ""}`).join("\n")}
567
+ ]
568
+ }
569
+ \`\`\`
570
+
571
+ **CRITICAL RULES:**
572
+ 1. Return a SINGLE JSON object with an "orbitals" array
573
+ 2. Each element in the array is a complete FullOrbitalUnit
574
+ 3. Maintain the order: ${orbitals.map((o) => o.name).join(", ")}
575
+ 4. PRESERVE all emits/listens as specified in each orbital section
576
+ 5. Use shared domain vocabulary consistently across all orbitals
577
+ 6. Ensure cross-orbital event wiring is maintained
578
+ `;
579
+ }
580
+ function generateBatchFingerprint(orbitals) {
581
+ const fingerprints = orbitals.map((o) => computeOrbitalFingerprint(o));
582
+ const combined = fingerprints.sort().join("|");
583
+ let hash = 0;
584
+ for (let i = 0; i < combined.length; i++) {
585
+ const char = combined.charCodeAt(i);
586
+ hash = (hash << 5) - hash + char;
587
+ hash = hash & hash;
588
+ }
589
+ return `batch:${orbitals.length}:${Math.abs(hash).toString(16).slice(0, 8)}`;
590
+ }
591
+ function splitIntoBatches(orbitals, options = {}) {
592
+ const {
593
+ maxBatchSize = 3,
594
+ preserveRelationships = true
595
+ } = options;
596
+ if (!preserveRelationships) {
597
+ return chunkArray(orbitals, maxBatchSize);
598
+ }
599
+ const clusters = groupByRelationships(orbitals);
600
+ const batches = [];
601
+ for (const cluster of clusters) {
602
+ if (cluster.length <= maxBatchSize) {
603
+ batches.push(cluster);
604
+ } else {
605
+ batches.push(...chunkArray(cluster, maxBatchSize));
606
+ }
607
+ }
608
+ return batches;
609
+ }
610
+ function groupByRelationships(orbitals) {
611
+ const visited = /* @__PURE__ */ new Set();
612
+ const clusters = [];
613
+ const adjacency = /* @__PURE__ */ new Map();
614
+ for (const orbital of orbitals) {
615
+ if (!adjacency.has(orbital.name)) {
616
+ adjacency.set(orbital.name, /* @__PURE__ */ new Set());
617
+ }
618
+ if (orbital.emits) {
619
+ for (const event of orbital.emits) {
620
+ for (const other of orbitals) {
621
+ if (other === orbital) continue;
622
+ if (other.listens?.some((l) => l.event === event.event)) {
623
+ adjacency.get(orbital.name)?.add(other.name);
624
+ if (!adjacency.has(other.name)) {
625
+ adjacency.set(other.name, /* @__PURE__ */ new Set());
626
+ }
627
+ adjacency.get(other.name)?.add(orbital.name);
628
+ }
629
+ }
630
+ }
631
+ }
632
+ }
633
+ function dfs(orbital, cluster) {
634
+ visited.add(orbital.name);
635
+ cluster.push(orbital);
636
+ const neighbors = adjacency.get(orbital.name) || /* @__PURE__ */ new Set();
637
+ for (const neighborName of neighbors) {
638
+ if (!visited.has(neighborName)) {
639
+ const neighbor = orbitals.find((o) => o.name === neighborName);
640
+ if (neighbor) {
641
+ dfs(neighbor, cluster);
642
+ }
643
+ }
644
+ }
645
+ }
646
+ for (const orbital of orbitals) {
647
+ if (!visited.has(orbital.name)) {
648
+ const cluster = [];
649
+ dfs(orbital, cluster);
650
+ clusters.push(cluster);
651
+ }
652
+ }
653
+ return clusters;
654
+ }
655
+ function estimateBatchTokens(orbitals) {
656
+ const baseTokens = 2e3;
657
+ const perOrbitalTokens = 800;
658
+ return baseTokens + orbitals.length * perOrbitalTokens;
659
+ }
660
+ function willBatchFit(orbitals, maxTokens = 12e3) {
661
+ const estimated = estimateBatchTokens(orbitals);
662
+ return estimated < maxTokens * 0.5;
663
+ }
664
+ var init_prompt_assembler2 = __esm({
665
+ "src/orbitals/batch/prompt-assembler.ts"() {
666
+ init_cache();
667
+ init_shared();
668
+ }
669
+ });
670
+
671
+ // src/orbitals/batch/concurrency.ts
672
+ function createConcurrencyController(maxConcurrency) {
673
+ let activeCount = 0;
674
+ const queue = [];
675
+ return {
676
+ async acquire() {
677
+ if (activeCount < maxConcurrency) {
678
+ activeCount++;
679
+ return Promise.resolve();
680
+ }
681
+ return new Promise((resolve2) => {
682
+ queue.push(() => {
683
+ activeCount++;
684
+ resolve2();
685
+ });
686
+ });
687
+ },
688
+ release() {
689
+ activeCount = Math.max(0, activeCount - 1);
690
+ const next = queue.shift();
691
+ if (next) {
692
+ next();
693
+ }
694
+ },
695
+ get activeCount() {
696
+ return activeCount;
697
+ },
698
+ get waitingCount() {
699
+ return queue.length;
700
+ }
701
+ };
702
+ }
703
+ async function runWithConcurrency(tasks, options) {
704
+ const { concurrency, onProgress } = options;
705
+ const controller = createConcurrencyController(concurrency);
706
+ const results = [];
707
+ let completed = 0;
708
+ await Promise.all(
709
+ tasks.map(async (task, index) => {
710
+ await controller.acquire();
711
+ try {
712
+ results[index] = await task();
713
+ completed++;
714
+ onProgress?.(completed, tasks.length);
715
+ } finally {
716
+ controller.release();
717
+ }
718
+ })
719
+ );
720
+ return results;
721
+ }
722
+ async function asyncMapWithConcurrency2(items, mapper, concurrency) {
723
+ return runWithConcurrency(
724
+ items.map((item, index) => () => mapper(item, index)),
725
+ { concurrency }
726
+ );
727
+ }
728
+ var init_concurrency = __esm({
729
+ "src/orbitals/batch/concurrency.ts"() {
730
+ }
731
+ });
732
+
733
+ // src/orbitals/batch/batch-generator.ts
734
+ async function generateOrbitalsBatch(client, orbitals, options = {}) {
735
+ const startTime = Date.now();
736
+ const aggregateLogs = [];
737
+ const provider = client.getProvider();
738
+ const mode = options.mode || "single-call";
739
+ const maxConcurrency = options.concurrency ?? PROVIDER_CONCURRENCY_LIMITS[provider];
740
+ const maxBatchSize = options.batchSize ?? PROVIDER_BATCH_SIZES[provider];
741
+ console.log(`[BatchGenerator] Starting batch generation: ${orbitals.length} orbitals, mode=${mode}, concurrency=${maxConcurrency}`);
742
+ aggregateLogs.push(createLog("info", `Starting batch generation`, {
743
+ totalOrbitals: orbitals.length,
744
+ mode,
745
+ provider,
746
+ maxConcurrency,
747
+ maxBatchSize
748
+ }));
749
+ const batches = splitIntoBatches(orbitals, {
750
+ maxBatchSize,
751
+ preserveRelationships: options.preserveRelationships ?? true
752
+ });
753
+ console.log(`[BatchGenerator] Split into ${batches.length} batches: [${batches.map((b) => b.length).join(", ")}]`);
754
+ aggregateLogs.push(createLog("info", `Split into ${batches.length} batches`, {
755
+ batchSizes: batches.map((b) => b.length)
756
+ }));
757
+ options.onBatchProgress?.({
758
+ type: "batch_start",
759
+ batchIndex: 0,
760
+ totalBatches: batches.length,
761
+ completedOrbitals: 0,
762
+ totalOrbitals: orbitals.length
763
+ });
764
+ let batchResults;
765
+ if (mode === "parallel-individual") {
766
+ batchResults = await generateParallelIndividual(client, orbitals, {
767
+ ...options,
768
+ concurrency: maxConcurrency,
769
+ onBatchProgress: options.onBatchProgress
770
+ });
771
+ } else if (mode === "single-call") {
772
+ batchResults = await generateSingleCallBatches(client, batches, {
773
+ ...options,
774
+ concurrency: maxConcurrency,
775
+ onBatchProgress: options.onBatchProgress
776
+ });
777
+ } else {
778
+ batchResults = await generateAdaptive(client, orbitals, batches, {
779
+ ...options,
780
+ concurrency: maxConcurrency,
781
+ maxBatchSize,
782
+ onBatchProgress: options.onBatchProgress
783
+ });
784
+ }
785
+ const totalDurationMs = Date.now() - startTime;
786
+ const allResults = batchResults.flatMap((b) => b.results);
787
+ const successful = allResults.filter((r) => r.success).length;
788
+ const failed = allResults.length - successful;
789
+ const totalTokens = batchResults.reduce(
790
+ (sum, b) => sum + (b.usage?.totalTokens ?? 0),
791
+ 0
792
+ );
793
+ console.log(`[BatchGenerator] Complete: ${successful}/${allResults.length} successful, ${totalTokens} tokens, ${totalDurationMs}ms`);
794
+ aggregateLogs.push(createLog("info", `Batch generation completed`, {
795
+ totalDurationMs,
796
+ successful,
797
+ failed,
798
+ totalTokens,
799
+ totalBatches: batches.length
800
+ }));
801
+ options.onBatchProgress?.({
802
+ type: "batch_complete",
803
+ batchIndex: batches.length - 1,
804
+ totalBatches: batches.length,
805
+ completedOrbitals: successful,
806
+ totalOrbitals: orbitals.length
807
+ });
808
+ return {
809
+ results: allResults.map((r) => ({
810
+ orbital: r.orbital,
811
+ fingerprint: "",
812
+ // TODO: compute from orbital
813
+ usedTemplate: false,
814
+ usage: void 0,
815
+ validation: r.success ? { valid: true, errorCount: 0, warningCount: 0 } : { valid: false, errorCount: 1, warningCount: 0 },
816
+ logs: []
817
+ })),
818
+ totalDurationMs,
819
+ aggregateLogs,
820
+ summary: {
821
+ total: allResults.length,
822
+ successful,
823
+ failed,
824
+ totalTokens
825
+ },
826
+ batchResults,
827
+ totalBatches: batches.length
828
+ };
829
+ }
830
+ async function generateSingleCallBatches(client, batches, options) {
831
+ let completedOrbitals = 0;
832
+ const totalOrbitals = batches.reduce((sum, b) => sum + b.length, 0);
833
+ return asyncMapWithConcurrency2(
834
+ batches,
835
+ async (batch, batchIndex) => {
836
+ return generateSingleBatch(client, batch, batchIndex, {
837
+ ...options,
838
+ onProgress: (completedInBatch) => {
839
+ const newCompleted = completedOrbitals + completedInBatch;
840
+ options.onBatchProgress?.({
841
+ type: "orbital_complete",
842
+ batchIndex,
843
+ totalBatches: batches.length,
844
+ completedOrbitals: newCompleted,
845
+ totalOrbitals
846
+ });
847
+ completedOrbitals = newCompleted;
848
+ }
849
+ });
850
+ },
851
+ options.concurrency
852
+ );
853
+ }
854
+ async function generateParallelIndividual(client, orbitals, options) {
855
+ const batches = orbitals.map((o) => [o]);
856
+ return generateSingleCallBatches(client, batches, {
857
+ ...options,
858
+ concurrency: options.concurrency
859
+ });
860
+ }
861
+ async function generateAdaptive(client, orbitals, batches, options) {
862
+ const allFit = batches.every((batch) => willBatchFit(batch, BATCH_MAX_TOKENS));
863
+ if (allFit) {
864
+ console.log(`[BatchGenerator] Adaptive: Using single-call batches (${batches.length} batches)`);
865
+ return generateSingleCallBatches(client, batches, options);
866
+ }
867
+ console.log(`[BatchGenerator] Adaptive: Using parallel-individual (batches too large)`);
868
+ return generateParallelIndividual(client, orbitals, options);
869
+ }
870
+ async function generateSingleBatch(client, orbitals, batchIndex, options) {
871
+ const batchStartTime = Date.now();
872
+ const logs = [];
873
+ console.log(`[BatchGenerator] Starting batch ${batchIndex + 1}: ${orbitals.map((o) => o.name).join(", ")}`);
874
+ logs.push(createLog("info", `Starting batch ${batchIndex + 1}`, {
875
+ orbitalCount: orbitals.length,
876
+ orbitals: orbitals.map((o) => o.name)
877
+ }));
878
+ try {
879
+ const batchPrompt = assembleBatchPrompt(orbitals);
880
+ console.log(`[BatchGenerator] Batch ${batchIndex + 1} prompt assembled: ${batchPrompt.prompt.length} chars`);
881
+ logs.push(createLog("info", `Batch prompt assembled`, {
882
+ promptLength: batchPrompt.prompt.length,
883
+ estimatedTokens: Math.ceil(batchPrompt.prompt.length / 4)
884
+ }));
885
+ const llmResult = await client.callWithMetadata({
886
+ systemPrompt: batchPrompt.prompt,
887
+ userPrompt: "Generate all orbitals in the batch. Return valid JSON matching the output format specified.",
888
+ maxTokens: BATCH_MAX_TOKENS,
889
+ skipSchemaValidation: true
890
+ });
891
+ logs.push(createLog("info", `LLM call completed`, {
892
+ promptTokens: llmResult.usage?.promptTokens,
893
+ completionTokens: llmResult.usage?.completionTokens
894
+ }));
895
+ const parsed = parseBatchResult(llmResult.data, orbitals);
896
+ console.log(`[BatchGenerator] Batch ${batchIndex + 1} parsed: ${parsed.filter((p) => p.success).length}/${parsed.length} successful`);
897
+ for (let i = 0; i < parsed.length; i++) {
898
+ options.onProgress?.(i + 1);
899
+ }
900
+ const durationMs = Date.now() - batchStartTime;
901
+ logs.push(createLog("info", `Batch ${batchIndex + 1} completed`, {
902
+ durationMs,
903
+ successful: parsed.filter((r) => r.success).length
904
+ }));
905
+ return {
906
+ orbitals,
907
+ results: parsed,
908
+ usage: llmResult.usage ?? void 0,
909
+ durationMs,
910
+ logs
911
+ };
912
+ } catch (error) {
913
+ const errorMessage = getErrorMessage(error);
914
+ console.error(`[BatchGenerator] Batch ${batchIndex + 1} FAILED: ${errorMessage}`);
915
+ logs.push(createLog("error", `Batch ${batchIndex + 1} failed`, {
916
+ error: errorMessage
917
+ }));
918
+ return {
919
+ orbitals,
920
+ results: orbitals.map((o) => ({
921
+ orbital: o,
922
+ success: false,
923
+ error: errorMessage
924
+ })),
925
+ durationMs: Date.now() - batchStartTime,
926
+ logs
927
+ };
928
+ }
929
+ }
930
+ function parseBatchResult(data, expectedOrbitals) {
931
+ if (!data || typeof data !== "object") {
932
+ return expectedOrbitals.map((o) => ({
933
+ orbital: o,
934
+ success: false,
935
+ error: "Invalid response: expected object"
936
+ }));
937
+ }
938
+ const obj = data;
939
+ if (!obj.orbitals || !Array.isArray(obj.orbitals)) {
940
+ return expectedOrbitals.map((o) => ({
941
+ orbital: o,
942
+ success: false,
943
+ error: "Invalid response: missing orbitals array"
944
+ }));
945
+ }
946
+ const results = obj.orbitals;
947
+ return expectedOrbitals.map((expected, index) => {
948
+ const result = results[index];
949
+ if (!result) {
950
+ return {
951
+ orbital: expected,
952
+ success: false,
953
+ error: `Missing result for orbital ${index + 1}`
954
+ };
955
+ }
956
+ if (!result.name) {
957
+ return {
958
+ orbital: expected,
959
+ success: false,
960
+ error: "Generated orbital missing name"
961
+ };
962
+ }
963
+ return {
964
+ orbital: result,
965
+ success: true
966
+ };
967
+ });
968
+ }
969
+ var init_batch_generator = __esm({
970
+ "src/orbitals/batch/batch-generator.ts"() {
971
+ init_shared();
972
+ init_prompt_assembler2();
973
+ init_concurrency();
974
+ }
975
+ });
976
+
977
+ // src/orbitals/batch/index.ts
978
+ var init_batch = __esm({
979
+ "src/orbitals/batch/index.ts"() {
980
+ init_batch_generator();
981
+ init_prompt_assembler2();
982
+ init_concurrency();
983
+ }
984
+ });
985
+
986
+ // src/tools/orbital-batch-subagent.ts
987
+ var orbital_batch_subagent_exports = {};
988
+ __export(orbital_batch_subagent_exports, {
989
+ createOrbitalBatchSubagentTool: () => createOrbitalBatchSubagentTool
990
+ });
991
+ function createOrbitalBatchSubagentTool(options = {}) {
992
+ let eventCallback = options.onSubagentEvent;
993
+ let completeCallback = options.onBatchComplete;
994
+ const requirements = options.requirements;
995
+ const workDir = options.workDir;
996
+ const setEventCallback = (callback) => {
997
+ eventCallback = callback;
998
+ };
999
+ const setBatchCompleteCallback = (callback) => {
1000
+ completeCallback = callback;
1001
+ };
1002
+ const emitEvent = (orbitalName, orbitalIndex, totalOrbitals, type, data) => {
1003
+ if (eventCallback) {
1004
+ eventCallback(orbitalName, orbitalIndex, totalOrbitals, {
1005
+ type,
1006
+ data,
1007
+ timestamp: Date.now()
1008
+ });
1009
+ }
1010
+ };
1011
+ const batchTool = tool(
1012
+ async ({ orbitals, options: batchOptions }) => {
1013
+ if (!orbitals || orbitals.length === 0) {
1014
+ return JSON.stringify({
1015
+ success: false,
1016
+ error: "No orbitals provided for batch generation.",
1017
+ orbitals: []
1018
+ });
1019
+ }
1020
+ console.log(`[OrbitalBatchSubagent] Starting batch generation for ${orbitals.length} orbitals`);
1021
+ try {
1022
+ emitEvent("batch", 0, 1, "message", {
1023
+ content: `Starting batch generation for ${orbitals.length} orbitals`,
1024
+ role: "assistant",
1025
+ isComplete: false
1026
+ });
1027
+ emitEvent("batch", 0, 1, "todo_update", {
1028
+ todos: orbitals.map((o, i) => ({
1029
+ id: `orbital-${i}`,
1030
+ task: `Generate ${o.name}`,
1031
+ status: "pending"
1032
+ }))
1033
+ });
1034
+ const client = new LLMClient({
1035
+ provider: options.provider || "anthropic",
1036
+ model: options.model || "claude-sonnet-4-20250514"
1037
+ });
1038
+ const generationOptions = {
1039
+ mode: batchOptions?.mode || "adaptive",
1040
+ batchSize: batchOptions?.batchSize,
1041
+ concurrency: batchOptions?.maxConcurrency ?? PROVIDER_CONCURRENCY_LIMITS[client.getProvider()],
1042
+ preserveRelationships: batchOptions?.preserveRelationships ?? true,
1043
+ requirements,
1044
+ onBatchProgress: (event) => {
1045
+ if (event.type === "orbital_complete" && event.orbitalName) {
1046
+ emitEvent(event.orbitalName || "batch", event.batchIndex, event.totalBatches, "todo_update", {
1047
+ todos: orbitals.map((o, i) => ({
1048
+ id: `orbital-${i}`,
1049
+ task: `Generate ${o.name}`,
1050
+ status: o.name === event.orbitalName ? "completed" : event.completedOrbitals > i ? "completed" : "pending"
1051
+ }))
1052
+ });
1053
+ }
1054
+ emitEvent(event.orbitalName || "batch", event.batchIndex, event.totalBatches, "generation_log", {
1055
+ level: "info",
1056
+ message: `Progress: ${event.completedOrbitals}/${event.totalOrbitals} orbitals complete`,
1057
+ data: {
1058
+ batchIndex: event.batchIndex,
1059
+ completedOrbitals: event.completedOrbitals,
1060
+ totalOrbitals: event.totalOrbitals
1061
+ }
1062
+ });
1063
+ }
1064
+ };
1065
+ emitEvent("batch", 0, 1, "tool_call", {
1066
+ tool: "generateOrbitalsBatch",
1067
+ args: {
1068
+ orbitalCount: orbitals.length,
1069
+ mode: generationOptions.mode,
1070
+ concurrency: generationOptions.concurrency
1071
+ }
1072
+ });
1073
+ const result = await generateOrbitalsBatch(client, orbitals, generationOptions);
1074
+ emitEvent("batch", result.totalBatches - 1, result.totalBatches, "todo_update", {
1075
+ todos: orbitals.map((o, i) => ({
1076
+ id: `orbital-${i}`,
1077
+ task: `Generate ${o.name}`,
1078
+ status: result.batchResults.some(
1079
+ (b) => b.results.some((r) => r.orbital.name === o.name && r.success)
1080
+ ) ? "completed" : "failed"
1081
+ }))
1082
+ });
1083
+ const generatedOrbitals = result.results.filter((r) => r.orbital).map((r) => r.orbital);
1084
+ const successCount = generatedOrbitals.length;
1085
+ const failedCount = orbitals.length - successCount;
1086
+ emitEvent("batch", result.totalBatches - 1, result.totalBatches, "message", {
1087
+ content: `Batch generation complete: ${successCount}/${orbitals.length} orbitals generated successfully`,
1088
+ role: "assistant",
1089
+ isComplete: true
1090
+ });
1091
+ if (workDir && completeCallback && generatedOrbitals.length > 0) {
1092
+ try {
1093
+ await completeCallback(generatedOrbitals, 0, 1);
1094
+ emitEvent("batch", result.totalBatches - 1, result.totalBatches, "generation_log", {
1095
+ level: "info",
1096
+ message: `Persisted ${generatedOrbitals.length} orbitals`
1097
+ });
1098
+ } catch (persistError) {
1099
+ console.error(`[OrbitalBatchSubagent] Failed to persist orbitals:`, persistError);
1100
+ emitEvent("batch", result.totalBatches - 1, result.totalBatches, "generation_log", {
1101
+ level: "warn",
1102
+ message: "Failed to persist some orbitals",
1103
+ data: { error: String(persistError) }
1104
+ });
1105
+ }
1106
+ }
1107
+ return JSON.stringify({
1108
+ success: successCount === orbitals.length,
1109
+ generated: successCount,
1110
+ failed: failedCount,
1111
+ total: orbitals.length,
1112
+ orbitals: generatedOrbitals,
1113
+ duration: result.totalDurationMs,
1114
+ totalTokens: result.summary.totalTokens,
1115
+ batches: result.totalBatches
1116
+ });
1117
+ } catch (error) {
1118
+ const errorMessage = error instanceof Error ? error.message : String(error);
1119
+ console.error(`[OrbitalBatchSubagent] Batch generation failed:`, errorMessage);
1120
+ emitEvent("batch", 0, 1, "error", {
1121
+ error: errorMessage,
1122
+ code: "BATCH_GENERATION_ERROR"
1123
+ });
1124
+ return JSON.stringify({
1125
+ success: false,
1126
+ error: errorMessage,
1127
+ orbitals: []
1128
+ });
1129
+ }
1130
+ },
1131
+ {
1132
+ name: "generate_orbitals_batch",
1133
+ 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.",
1134
+ schema: OrbitalBatchInputSchema
1135
+ }
1136
+ );
1137
+ return {
1138
+ tool: batchTool,
1139
+ setEventCallback,
1140
+ setBatchCompleteCallback
1141
+ };
1142
+ }
1143
+ var OrbitalBatchInputSchema;
1144
+ var init_orbital_batch_subagent = __esm({
1145
+ "src/tools/orbital-batch-subagent.ts"() {
1146
+ init_shared();
1147
+ init_batch();
1148
+ OrbitalBatchInputSchema = z.object({
1149
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1150
+ orbitals: z.array(z.any()).describe("Array of OrbitalUnits to generate"),
1151
+ options: z.object({
1152
+ mode: z.enum(["single-call", "parallel-individual", "adaptive"]).optional().default("adaptive"),
1153
+ batchSize: z.number().optional(),
1154
+ maxConcurrency: z.number().optional(),
1155
+ preserveRelationships: z.boolean().optional().default(true)
1156
+ }).optional().describe("Batch generation options")
1157
+ });
1158
+ }
1159
+ });
311
1160
  var DANGEROUS_COMMANDS = [
312
1161
  "rm",
313
1162
  "rmdir",
@@ -1535,8 +2384,8 @@ function createGenerateOrbitalDomainTool(options = {}) {
1535
2384
  orbitalName: spec.name
1536
2385
  });
1537
2386
  const client = new LLMClient({
1538
- provider: "anthropic",
1539
- model: "claude-sonnet-4-20250514",
2387
+ provider: options.provider ?? "anthropic",
2388
+ model: options.model ?? "claude-sonnet-4-20250514",
1540
2389
  temperature: 0
1541
2390
  });
1542
2391
  const userPrompt = buildDynamicUserPrompt(spec);
@@ -1742,20 +2591,8 @@ function createDomainOrbitalTools(options = {}) {
1742
2591
 
1743
2592
  // src/orbitals/generation/orbital-generator.ts
1744
2593
  init_cache();
1745
- function getEntityName2(entity) {
1746
- if (isEntityReference(entity)) {
1747
- return entity.replace(".entity", "");
1748
- }
1749
- return entity.name;
1750
- }
1751
- function createLog(level, message, data) {
1752
- return {
1753
- timestamp: Date.now(),
1754
- level,
1755
- message,
1756
- data
1757
- };
1758
- }
2594
+ init_shared();
2595
+ init_shared();
1759
2596
  async function generateFullOrbital(client, orbital, options = {}) {
1760
2597
  const {
1761
2598
  maxTokens = 8192,
@@ -2016,8 +2853,8 @@ function createOrbitalSubagentTool(options = {}) {
2016
2853
  ]
2017
2854
  });
2018
2855
  const client = new LLMClient({
2019
- provider: "anthropic",
2020
- model: "claude-sonnet-4-20250514"
2856
+ provider: options.provider ?? "anthropic",
2857
+ model: options.model ?? "claude-sonnet-4-20250514"
2021
2858
  });
2022
2859
  emitEvent(orbitalUnit.name, orbitalIndex, totalOrbitals, "tool_call", {
2023
2860
  tool: "llm_generate",
@@ -2134,6 +2971,9 @@ USAGE:
2134
2971
  setOrbitalCompleteCallback
2135
2972
  };
2136
2973
  }
2974
+
2975
+ // src/tools/index.ts
2976
+ init_orbital_batch_subagent();
2137
2977
  var TraitSpecSchema = z.object({
2138
2978
  name: z.string().describe("Name of the trait"),
2139
2979
  description: z.string().describe("Description of what this trait does"),
@@ -3506,6 +4346,21 @@ function createLLMClient(provider, model, verbose) {
3506
4346
  model: model || OPENAI_MODELS.GPT4O,
3507
4347
  temperature
3508
4348
  });
4349
+ case "kimi":
4350
+ if (verbose)
4351
+ console.log(`[SkillAgent] Using Kimi: ${model || KIMI_MODELS.K2_5}`);
4352
+ return createKimiClient({
4353
+ model: model || KIMI_MODELS.K2_5,
4354
+ temperature: 0.6
4355
+ // Kimi with thinking disabled requires 0.6
4356
+ });
4357
+ case "openrouter":
4358
+ if (verbose)
4359
+ console.log(`[SkillAgent] Using OpenRouter: ${model || OPENROUTER_MODELS.QWEN_2_5_72B}`);
4360
+ return createOpenRouterClient({
4361
+ model: model || OPENROUTER_MODELS.QWEN_2_5_72B,
4362
+ temperature: 0.3
4363
+ });
3509
4364
  case "anthropic":
3510
4365
  default:
3511
4366
  if (verbose)
@@ -3530,6 +4385,8 @@ async function createSkillAgent(options) {
3530
4385
  threadId: providedThreadId,
3531
4386
  provider = "anthropic",
3532
4387
  model,
4388
+ subagentProvider = "anthropic",
4389
+ subagentModel = "claude-sonnet-4-20250514",
3533
4390
  verbose = false,
3534
4391
  skillLoader,
3535
4392
  skillRefLoader
@@ -3626,18 +4483,24 @@ ${skillContents}`;
3626
4483
  const finishTaskTool = createFinishTaskTool(workDir);
3627
4484
  const validateSchemaTool = createValidateSchemaTool(workDir);
3628
4485
  const ORBITAL_SKILLS = ["kflow-orbitals", "kflow-orbital-games", "kflow-orbital-fixing"];
4486
+ const ORBITAL_BATCH_SKILLS = ["kflow-orbitals-batch"];
3629
4487
  const LEAN_SKILLS = ["kflow-lean-orbitals", "kflow-lean-fixing"];
3630
4488
  const isOrbitalSkill = primarySkill.name === "kflow-orbitals";
4489
+ const isOrbitalBatchSkill = ORBITAL_BATCH_SKILLS.includes(primarySkill.name);
3631
4490
  const isLeanSkill = LEAN_SKILLS.includes(primarySkill.name);
3632
4491
  const needsChunkingTools = ORBITAL_SKILLS.includes(primarySkill.name);
3633
4492
  let orbitalTool;
3634
4493
  let setOrbitalEventCallback;
3635
4494
  let setOrbitalCompleteCallback;
4495
+ let orbitalBatchTool;
4496
+ let setBatchEventCallback;
3636
4497
  let domainOrbitalTools;
3637
4498
  const chunkingTools = needsChunkingTools ? createSchemaChunkingTools(workDir) : null;
3638
4499
  if (isOrbitalSkill) {
3639
4500
  const orbitalResult = createOrbitalSubagentTool({
3640
- requirements: options.requirements
4501
+ requirements: options.requirements,
4502
+ provider: subagentProvider,
4503
+ model: subagentModel
3641
4504
  });
3642
4505
  orbitalTool = orbitalResult.tool;
3643
4506
  setOrbitalEventCallback = orbitalResult.setEventCallback;
@@ -3649,10 +4512,31 @@ ${skillContents}`;
3649
4512
  console.log(`[SkillAgent] Orbital tools enabled for kflow-orbitals skill`);
3650
4513
  }
3651
4514
  }
4515
+ if (isOrbitalBatchSkill) {
4516
+ const { createOrbitalBatchSubagentTool: createOrbitalBatchSubagentTool2 } = await Promise.resolve().then(() => (init_orbital_batch_subagent(), orbital_batch_subagent_exports));
4517
+ const batchResult = createOrbitalBatchSubagentTool2({
4518
+ requirements: options.requirements,
4519
+ provider: subagentProvider,
4520
+ model: subagentModel,
4521
+ workDir
4522
+ });
4523
+ orbitalBatchTool = batchResult.tool;
4524
+ setBatchEventCallback = batchResult.setEventCallback;
4525
+ if (options.onSubagentEvent) {
4526
+ setBatchEventCallback(options.onSubagentEvent);
4527
+ }
4528
+ if (verbose) {
4529
+ console.log(`[SkillAgent] Batch orbital tools enabled for kflow-orbitals-batch skill`);
4530
+ }
4531
+ }
3652
4532
  if (isLeanSkill) {
3653
- domainOrbitalTools = createDomainOrbitalTools({ workDir });
4533
+ domainOrbitalTools = createDomainOrbitalTools({
4534
+ workDir,
4535
+ provider: subagentProvider,
4536
+ model: subagentModel
4537
+ });
3654
4538
  if (verbose) {
3655
- console.log(`[SkillAgent] Domain orbital tools enabled for ${primarySkill.name} skill`);
4539
+ console.log(`[SkillAgent] Domain orbital tools enabled for ${primarySkill.name} skill (provider: ${subagentProvider})`);
3656
4540
  }
3657
4541
  }
3658
4542
  const githubTools = options.githubConfig ? createGitHubToolsArray({
@@ -3667,8 +4551,9 @@ ${skillContents}`;
3667
4551
  const tools = [
3668
4552
  executeTool,
3669
4553
  finishTaskTool,
3670
- ...isOrbitalSkill ? [] : [validateSchemaTool],
4554
+ ...isOrbitalSkill || isOrbitalBatchSkill ? [] : [validateSchemaTool],
3671
4555
  ...orbitalTool ? [orbitalTool] : [],
4556
+ ...orbitalBatchTool ? [orbitalBatchTool] : [],
3672
4557
  ...domainOrbitalTools ? [
3673
4558
  domainOrbitalTools.generateOrbitalDomain,
3674
4559
  domainOrbitalTools.constructCombinedDomain