@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.
package/dist/index.js CHANGED
@@ -1,15 +1,15 @@
1
1
  import { AgentDomainCategorySchema, isOrbitalDefinition, getTraitName, isPageReferenceString, isPageReferenceObject, isEntityReference } from '@almadar/core/types';
2
- import { z } from 'zod';
2
+ import { getFullOrbitalPrompt, getRequirementsTraitPrompt, getKeyBehaviorsReference, getSExprQuickRef, getCommonErrorsSection, getArchitectureSection, getMinimalTypeReference } from '@almadar/skills';
3
3
  import { tool } from '@langchain/core/tools';
4
+ import { z } from 'zod';
5
+ import { LLMClient, isStructuredOutputAvailable, getStructuredOutputClient, createRequirementsClient, ANTHROPIC_MODELS, createAnthropicClient, OPENROUTER_MODELS, createOpenRouterClient, KIMI_MODELS, createKimiClient, OPENAI_MODELS, createOpenAIClient, DEEPSEEK_MODELS, createDeepSeekClient } from '@almadar/llm';
4
6
  import { exec, spawn } from 'child_process';
5
7
  import * as path from 'path';
6
8
  import { promisify } from 'util';
7
9
  import * as fs4 from 'fs/promises';
8
- import { isStructuredOutputAvailable, getStructuredOutputClient, LLMClient, createRequirementsClient, ANTHROPIC_MODELS, createAnthropicClient, OPENAI_MODELS, createOpenAIClient, DEEPSEEK_MODELS, createDeepSeekClient } from '@almadar/llm';
9
10
  import * as domain_language_star from '@almadar/core/domain-language';
10
11
  import * as fs3 from 'fs';
11
12
  import crypto, { randomUUID } from 'crypto';
12
- import { getFullOrbitalPrompt, getRequirementsTraitPrompt, getKeyBehaviorsReference, getSExprQuickRef, getCommonErrorsSection, getArchitectureSection, getMinimalTypeReference } from '@almadar/skills';
13
13
  import { GitHubIntegration } from '@almadar/integrations';
14
14
  import '@langchain/core/messages';
15
15
  import { FilesystemBackend, createDeepAgent } from 'deepagents';
@@ -393,6 +393,855 @@ var init_cache = __esm({
393
393
  init_prompt_assembler();
394
394
  }
395
395
  });
396
+
397
+ // src/orbitals/shared/constants.ts
398
+ var PROVIDER_CONCURRENCY_LIMITS, PROVIDER_BATCH_SIZES, BATCH_MAX_TOKENS;
399
+ var init_constants = __esm({
400
+ "src/orbitals/shared/constants.ts"() {
401
+ PROVIDER_CONCURRENCY_LIMITS = {
402
+ anthropic: 3,
403
+ openai: 5,
404
+ deepseek: 3,
405
+ kimi: 3,
406
+ openrouter: 5
407
+ };
408
+ PROVIDER_BATCH_SIZES = {
409
+ anthropic: 3,
410
+ // Anthropic works well with 3 orbitals per call
411
+ openai: 5,
412
+ // OpenAI can handle more
413
+ deepseek: 3,
414
+ // Conservative for DeepSeek
415
+ kimi: 3,
416
+ // Conservative for Kimi
417
+ openrouter: 5
418
+ // OpenRouter proxies multiple providers
419
+ };
420
+ BATCH_MAX_TOKENS = 12e3;
421
+ }
422
+ });
423
+ function getEntityName2(entity) {
424
+ if (isEntityReference(entity)) {
425
+ return entity.replace(".entity", "");
426
+ }
427
+ return entity.name;
428
+ }
429
+ function getInlineEntity3(entity) {
430
+ if (isEntityReference(entity)) {
431
+ return null;
432
+ }
433
+ return entity;
434
+ }
435
+ function getFieldNames(entity) {
436
+ const inlineEntity = getInlineEntity3(entity);
437
+ if (!inlineEntity?.fields?.length) {
438
+ return "N/A";
439
+ }
440
+ return inlineEntity.fields.map((f) => f.name).join(", ");
441
+ }
442
+ function createLog(level, message, data) {
443
+ return {
444
+ timestamp: Date.now(),
445
+ level,
446
+ message,
447
+ data
448
+ };
449
+ }
450
+ function buildContextSection2(orbital) {
451
+ const parts = [];
452
+ if (orbital.domainContext) {
453
+ const ctx = orbital.domainContext;
454
+ parts.push(`DomainContext: category=${ctx.category || "business"}`);
455
+ if (ctx.vocabulary) {
456
+ parts.push(`Vocabulary: ${JSON.stringify(ctx.vocabulary)}`);
457
+ }
458
+ if (ctx.requestFragment) {
459
+ parts.push(`RequestFragment: "${ctx.requestFragment}"`);
460
+ }
461
+ }
462
+ if (orbital.design) {
463
+ const d = orbital.design;
464
+ if (d.style) parts.push(`Style: ${d.style}`);
465
+ if (d.uxHints) {
466
+ const hints = d.uxHints;
467
+ if (hints.flowPattern) parts.push(`FlowPattern: ${hints.flowPattern}`);
468
+ if (hints.listPattern) parts.push(`ListPattern: ${hints.listPattern}`);
469
+ if (hints.formPattern) parts.push(`FormPattern: ${hints.formPattern}`);
470
+ }
471
+ }
472
+ return parts.length > 0 ? `Context: ${parts.join(", ")}
473
+ ` : "";
474
+ }
475
+ function buildConnectivitySection(orbital) {
476
+ const parts = [];
477
+ if (orbital.emits?.length) {
478
+ parts.push(`Emits: ${orbital.emits.join(", ")}`);
479
+ }
480
+ if (orbital.listens?.length) {
481
+ parts.push(`Listens: ${orbital.listens.map((l) => `${l.event}\u2192${l.triggers}`).join(", ")}`);
482
+ }
483
+ return parts.join("\n");
484
+ }
485
+ function chunkArray(array, size) {
486
+ const chunks = [];
487
+ for (let i = 0; i < array.length; i += size) {
488
+ chunks.push(array.slice(i, i + size));
489
+ }
490
+ return chunks;
491
+ }
492
+ function getErrorMessage(error) {
493
+ if (error instanceof Error) {
494
+ return error.message;
495
+ }
496
+ return String(error);
497
+ }
498
+ var init_utils = __esm({
499
+ "src/orbitals/shared/utils.ts"() {
500
+ }
501
+ });
502
+
503
+ // src/orbitals/shared/index.ts
504
+ var init_shared = __esm({
505
+ "src/orbitals/shared/index.ts"() {
506
+ init_constants();
507
+ init_utils();
508
+ }
509
+ });
510
+ function extractSharedContext(orbitals) {
511
+ const vocabulary = {};
512
+ const styles = /* @__PURE__ */ new Set();
513
+ const patterns = /* @__PURE__ */ new Set();
514
+ const relationships = [];
515
+ for (const orbital of orbitals) {
516
+ if (orbital.domainContext?.vocabulary) {
517
+ Object.assign(vocabulary, orbital.domainContext.vocabulary);
518
+ }
519
+ if (orbital.design?.style) {
520
+ styles.add(orbital.design.style);
521
+ }
522
+ }
523
+ new Map(orbitals.map((o) => [o.name, o]));
524
+ for (const orbital of orbitals) {
525
+ if (orbital.emits) {
526
+ for (const event of orbital.emits) {
527
+ for (const other of orbitals) {
528
+ if (other === orbital) continue;
529
+ if (other.listens) {
530
+ const listener = other.listens.find((l) => l.event === event.event);
531
+ if (listener) {
532
+ relationships.push({
533
+ emitter: orbital.name,
534
+ event: event.event,
535
+ listener: other.name,
536
+ handler: listener.triggers
537
+ });
538
+ }
539
+ }
540
+ }
541
+ }
542
+ }
543
+ }
544
+ return {
545
+ domainVocabulary: Object.keys(vocabulary).length > 0 ? vocabulary : void 0,
546
+ designStyle: styles.size === 1 ? Array.from(styles)[0] : void 0,
547
+ commonPatterns: patterns.size > 0 ? Array.from(patterns) : void 0,
548
+ eventRelationships: relationships.length > 0 ? relationships : void 0
549
+ };
550
+ }
551
+ function assembleBatchPrompt(orbitals, options = {}) {
552
+ const {
553
+ baseSystemPrompt = getFullOrbitalPrompt(),
554
+ includeConnectivity = true
555
+ } = options;
556
+ if (orbitals.length === 0) {
557
+ throw new Error("Cannot assemble batch prompt for empty orbitals array");
558
+ }
559
+ const sharedContext = extractSharedContext(orbitals);
560
+ const batchHeader = buildBatchHeader(orbitals, sharedContext);
561
+ const orbitalSections = orbitals.map(
562
+ (orbital, index) => buildOrbitalSection(orbital, index + 1, orbitals.length, includeConnectivity)
563
+ );
564
+ const outputSection = buildOutputSection(orbitals);
565
+ const prompt = `${baseSystemPrompt}
566
+
567
+ ${"=".repeat(60)}
568
+ BATCH GENERATION: ${orbitals.length} ORBITALS
569
+ ${"=".repeat(60)}
570
+
571
+ ${batchHeader}
572
+
573
+ ${orbitalSections.join("\n\n")}
574
+
575
+ ${outputSection}`;
576
+ const fingerprint = generateBatchFingerprint(orbitals);
577
+ return {
578
+ prompt,
579
+ fingerprint,
580
+ usedCachedTemplate: false,
581
+ // Batch doesn't use templates yet
582
+ orbitalCount: orbitals.length,
583
+ orbitalNames: orbitals.map((o) => o.name)
584
+ };
585
+ }
586
+ function buildBatchHeader(orbitals, sharedContext) {
587
+ const lines = [
588
+ `## Batch Overview`,
589
+ `- Total Orbitals: ${orbitals.length}`,
590
+ `- Orbitals: ${orbitals.map((o) => o.name).join(", ")}`
591
+ ];
592
+ if (sharedContext.designStyle) {
593
+ lines.push(`- Design Style: ${sharedContext.designStyle}`);
594
+ }
595
+ if (sharedContext.commonPatterns?.length) {
596
+ lines.push(`- Common Patterns: ${sharedContext.commonPatterns.join(", ")}`);
597
+ }
598
+ if (sharedContext.domainVocabulary && Object.keys(sharedContext.domainVocabulary).length > 0) {
599
+ lines.push(`
600
+ ## Shared Domain Vocabulary`);
601
+ for (const [term, definition] of Object.entries(sharedContext.domainVocabulary)) {
602
+ lines.push(`- ${term}: ${definition}`);
603
+ }
604
+ }
605
+ if (sharedContext.eventRelationships?.length) {
606
+ lines.push(`
607
+ ## Cross-Orbital Event Relationships`);
608
+ for (const rel of sharedContext.eventRelationships) {
609
+ lines.push(`- ${rel.emitter} emits "${rel.event}" \u2192 ${rel.listener} handles with "${rel.handler}"`);
610
+ }
611
+ }
612
+ return lines.join("\n");
613
+ }
614
+ function buildOrbitalSection(orbital, index, total, includeConnectivity) {
615
+ const entityName = getEntityName2(orbital.entity);
616
+ const fieldNames = getFieldNames(orbital.entity);
617
+ const contextSection = buildContextSection2(orbital);
618
+ const connectivitySection = includeConnectivity ? buildConnectivitySection(orbital) : "";
619
+ return `---
620
+ ## ORBITAL ${index}/${total}: ${orbital.name}
621
+
622
+ **Entity**: ${entityName}
623
+ **Persistence**: ${orbital.entity.persistence || "persistent"}
624
+ **Fields**: ${fieldNames}
625
+ **Traits**: ${orbital.traits.map((t) => typeof t === "string" ? t : "ref" in t ? t.ref : t.name).join(", ")}
626
+ ${contextSection}${connectivitySection ? `**Connectivity**:
627
+ ${connectivitySection}
628
+ ` : ""}
629
+ Generate a complete FullOrbitalUnit for ${orbital.name} with:
630
+ - Full field definitions with types and validation
631
+ - Trait state machines with transitions and effects
632
+ - Business rule validation using "guard" S-expression on SAVE transitions
633
+ - Pages with trait references
634
+ - domainContext with category, vocabulary, and requestFragment
635
+ - design with style and uxHints (flowPattern, listPattern, formPattern)
636
+ ${orbital.emits?.length ? "- PRESERVE emits: " + orbital.emits.map((e) => e.event).join(", ") : ""}
637
+ ${orbital.listens?.length ? "- PRESERVE listens: " + orbital.listens.map((l) => l.event).join(", ") : ""}`;
638
+ }
639
+ function buildOutputSection(orbitals) {
640
+ return `---
641
+ ## OUTPUT FORMAT
642
+
643
+ Return a JSON object with this exact structure:
644
+
645
+ \`\`\`json
646
+ {
647
+ "orbitals": [
648
+ ${orbitals.map((o, i) => ` {
649
+ "name": "${o.name}",
650
+ // ... complete FullOrbitalUnit for ${o.name}
651
+ }${i < orbitals.length - 1 ? "," : ""}`).join("\n")}
652
+ ]
653
+ }
654
+ \`\`\`
655
+
656
+ **CRITICAL RULES:**
657
+ 1. Return a SINGLE JSON object with an "orbitals" array
658
+ 2. Each element in the array is a complete FullOrbitalUnit
659
+ 3. Maintain the order: ${orbitals.map((o) => o.name).join(", ")}
660
+ 4. PRESERVE all emits/listens as specified in each orbital section
661
+ 5. Use shared domain vocabulary consistently across all orbitals
662
+ 6. Ensure cross-orbital event wiring is maintained
663
+ `;
664
+ }
665
+ function generateBatchFingerprint(orbitals) {
666
+ const fingerprints = orbitals.map((o) => computeOrbitalFingerprint(o));
667
+ const combined = fingerprints.sort().join("|");
668
+ let hash = 0;
669
+ for (let i = 0; i < combined.length; i++) {
670
+ const char = combined.charCodeAt(i);
671
+ hash = (hash << 5) - hash + char;
672
+ hash = hash & hash;
673
+ }
674
+ return `batch:${orbitals.length}:${Math.abs(hash).toString(16).slice(0, 8)}`;
675
+ }
676
+ function splitIntoBatches(orbitals, options = {}) {
677
+ const {
678
+ maxBatchSize = 3,
679
+ preserveRelationships = true
680
+ } = options;
681
+ if (!preserveRelationships) {
682
+ return chunkArray(orbitals, maxBatchSize);
683
+ }
684
+ const clusters = groupByRelationships(orbitals);
685
+ const batches = [];
686
+ for (const cluster of clusters) {
687
+ if (cluster.length <= maxBatchSize) {
688
+ batches.push(cluster);
689
+ } else {
690
+ batches.push(...chunkArray(cluster, maxBatchSize));
691
+ }
692
+ }
693
+ return batches;
694
+ }
695
+ function groupByRelationships(orbitals) {
696
+ const visited = /* @__PURE__ */ new Set();
697
+ const clusters = [];
698
+ const adjacency = /* @__PURE__ */ new Map();
699
+ for (const orbital of orbitals) {
700
+ if (!adjacency.has(orbital.name)) {
701
+ adjacency.set(orbital.name, /* @__PURE__ */ new Set());
702
+ }
703
+ if (orbital.emits) {
704
+ for (const event of orbital.emits) {
705
+ for (const other of orbitals) {
706
+ if (other === orbital) continue;
707
+ if (other.listens?.some((l) => l.event === event.event)) {
708
+ adjacency.get(orbital.name)?.add(other.name);
709
+ if (!adjacency.has(other.name)) {
710
+ adjacency.set(other.name, /* @__PURE__ */ new Set());
711
+ }
712
+ adjacency.get(other.name)?.add(orbital.name);
713
+ }
714
+ }
715
+ }
716
+ }
717
+ }
718
+ function dfs(orbital, cluster) {
719
+ visited.add(orbital.name);
720
+ cluster.push(orbital);
721
+ const neighbors = adjacency.get(orbital.name) || /* @__PURE__ */ new Set();
722
+ for (const neighborName of neighbors) {
723
+ if (!visited.has(neighborName)) {
724
+ const neighbor = orbitals.find((o) => o.name === neighborName);
725
+ if (neighbor) {
726
+ dfs(neighbor, cluster);
727
+ }
728
+ }
729
+ }
730
+ }
731
+ for (const orbital of orbitals) {
732
+ if (!visited.has(orbital.name)) {
733
+ const cluster = [];
734
+ dfs(orbital, cluster);
735
+ clusters.push(cluster);
736
+ }
737
+ }
738
+ return clusters;
739
+ }
740
+ function estimateBatchTokens(orbitals) {
741
+ const baseTokens = 2e3;
742
+ const perOrbitalTokens = 800;
743
+ return baseTokens + orbitals.length * perOrbitalTokens;
744
+ }
745
+ function willBatchFit(orbitals, maxTokens = 12e3) {
746
+ const estimated = estimateBatchTokens(orbitals);
747
+ return estimated < maxTokens * 0.5;
748
+ }
749
+ var init_prompt_assembler2 = __esm({
750
+ "src/orbitals/batch/prompt-assembler.ts"() {
751
+ init_cache();
752
+ init_shared();
753
+ }
754
+ });
755
+
756
+ // src/orbitals/batch/concurrency.ts
757
+ function createConcurrencyController(maxConcurrency) {
758
+ let activeCount = 0;
759
+ const queue = [];
760
+ return {
761
+ async acquire() {
762
+ if (activeCount < maxConcurrency) {
763
+ activeCount++;
764
+ return Promise.resolve();
765
+ }
766
+ return new Promise((resolve2) => {
767
+ queue.push(() => {
768
+ activeCount++;
769
+ resolve2();
770
+ });
771
+ });
772
+ },
773
+ release() {
774
+ activeCount = Math.max(0, activeCount - 1);
775
+ const next = queue.shift();
776
+ if (next) {
777
+ next();
778
+ }
779
+ },
780
+ get activeCount() {
781
+ return activeCount;
782
+ },
783
+ get waitingCount() {
784
+ return queue.length;
785
+ }
786
+ };
787
+ }
788
+ async function runWithConcurrency(tasks, options) {
789
+ const { concurrency, onProgress } = options;
790
+ const controller = createConcurrencyController(concurrency);
791
+ const results = [];
792
+ let completed = 0;
793
+ await Promise.all(
794
+ tasks.map(async (task, index) => {
795
+ await controller.acquire();
796
+ try {
797
+ results[index] = await task();
798
+ completed++;
799
+ onProgress?.(completed, tasks.length);
800
+ } finally {
801
+ controller.release();
802
+ }
803
+ })
804
+ );
805
+ return results;
806
+ }
807
+ async function asyncMapWithConcurrency2(items, mapper, concurrency) {
808
+ return runWithConcurrency(
809
+ items.map((item, index) => () => mapper(item, index)),
810
+ { concurrency }
811
+ );
812
+ }
813
+ var init_concurrency = __esm({
814
+ "src/orbitals/batch/concurrency.ts"() {
815
+ }
816
+ });
817
+
818
+ // src/orbitals/batch/batch-generator.ts
819
+ async function generateOrbitalsBatch(client, orbitals, options = {}) {
820
+ const startTime = Date.now();
821
+ const aggregateLogs = [];
822
+ const provider = client.getProvider();
823
+ const mode = options.mode || "single-call";
824
+ const maxConcurrency = options.concurrency ?? PROVIDER_CONCURRENCY_LIMITS[provider];
825
+ const maxBatchSize = options.batchSize ?? PROVIDER_BATCH_SIZES[provider];
826
+ console.log(`[BatchGenerator] Starting batch generation: ${orbitals.length} orbitals, mode=${mode}, concurrency=${maxConcurrency}`);
827
+ aggregateLogs.push(createLog("info", `Starting batch generation`, {
828
+ totalOrbitals: orbitals.length,
829
+ mode,
830
+ provider,
831
+ maxConcurrency,
832
+ maxBatchSize
833
+ }));
834
+ const batches = splitIntoBatches(orbitals, {
835
+ maxBatchSize,
836
+ preserveRelationships: options.preserveRelationships ?? true
837
+ });
838
+ console.log(`[BatchGenerator] Split into ${batches.length} batches: [${batches.map((b) => b.length).join(", ")}]`);
839
+ aggregateLogs.push(createLog("info", `Split into ${batches.length} batches`, {
840
+ batchSizes: batches.map((b) => b.length)
841
+ }));
842
+ options.onBatchProgress?.({
843
+ type: "batch_start",
844
+ batchIndex: 0,
845
+ totalBatches: batches.length,
846
+ completedOrbitals: 0,
847
+ totalOrbitals: orbitals.length
848
+ });
849
+ let batchResults;
850
+ if (mode === "parallel-individual") {
851
+ batchResults = await generateParallelIndividual(client, orbitals, {
852
+ ...options,
853
+ concurrency: maxConcurrency,
854
+ onBatchProgress: options.onBatchProgress
855
+ });
856
+ } else if (mode === "single-call") {
857
+ batchResults = await generateSingleCallBatches(client, batches, {
858
+ ...options,
859
+ concurrency: maxConcurrency,
860
+ onBatchProgress: options.onBatchProgress
861
+ });
862
+ } else {
863
+ batchResults = await generateAdaptive(client, orbitals, batches, {
864
+ ...options,
865
+ concurrency: maxConcurrency,
866
+ maxBatchSize,
867
+ onBatchProgress: options.onBatchProgress
868
+ });
869
+ }
870
+ const totalDurationMs = Date.now() - startTime;
871
+ const allResults = batchResults.flatMap((b) => b.results);
872
+ const successful = allResults.filter((r) => r.success).length;
873
+ const failed = allResults.length - successful;
874
+ const totalTokens = batchResults.reduce(
875
+ (sum, b) => sum + (b.usage?.totalTokens ?? 0),
876
+ 0
877
+ );
878
+ console.log(`[BatchGenerator] Complete: ${successful}/${allResults.length} successful, ${totalTokens} tokens, ${totalDurationMs}ms`);
879
+ aggregateLogs.push(createLog("info", `Batch generation completed`, {
880
+ totalDurationMs,
881
+ successful,
882
+ failed,
883
+ totalTokens,
884
+ totalBatches: batches.length
885
+ }));
886
+ options.onBatchProgress?.({
887
+ type: "batch_complete",
888
+ batchIndex: batches.length - 1,
889
+ totalBatches: batches.length,
890
+ completedOrbitals: successful,
891
+ totalOrbitals: orbitals.length
892
+ });
893
+ return {
894
+ results: allResults.map((r) => ({
895
+ orbital: r.orbital,
896
+ fingerprint: "",
897
+ // TODO: compute from orbital
898
+ usedTemplate: false,
899
+ usage: void 0,
900
+ validation: r.success ? { valid: true, errorCount: 0, warningCount: 0 } : { valid: false, errorCount: 1, warningCount: 0 },
901
+ logs: []
902
+ })),
903
+ totalDurationMs,
904
+ aggregateLogs,
905
+ summary: {
906
+ total: allResults.length,
907
+ successful,
908
+ failed,
909
+ totalTokens
910
+ },
911
+ batchResults,
912
+ totalBatches: batches.length
913
+ };
914
+ }
915
+ async function generateSingleCallBatches(client, batches, options) {
916
+ let completedOrbitals = 0;
917
+ const totalOrbitals = batches.reduce((sum, b) => sum + b.length, 0);
918
+ return asyncMapWithConcurrency2(
919
+ batches,
920
+ async (batch, batchIndex) => {
921
+ return generateSingleBatch(client, batch, batchIndex, {
922
+ ...options,
923
+ onProgress: (completedInBatch) => {
924
+ const newCompleted = completedOrbitals + completedInBatch;
925
+ options.onBatchProgress?.({
926
+ type: "orbital_complete",
927
+ batchIndex,
928
+ totalBatches: batches.length,
929
+ completedOrbitals: newCompleted,
930
+ totalOrbitals
931
+ });
932
+ completedOrbitals = newCompleted;
933
+ }
934
+ });
935
+ },
936
+ options.concurrency
937
+ );
938
+ }
939
+ async function generateParallelIndividual(client, orbitals, options) {
940
+ const batches = orbitals.map((o) => [o]);
941
+ return generateSingleCallBatches(client, batches, {
942
+ ...options,
943
+ concurrency: options.concurrency
944
+ });
945
+ }
946
+ async function generateAdaptive(client, orbitals, batches, options) {
947
+ const allFit = batches.every((batch) => willBatchFit(batch, BATCH_MAX_TOKENS));
948
+ if (allFit) {
949
+ console.log(`[BatchGenerator] Adaptive: Using single-call batches (${batches.length} batches)`);
950
+ return generateSingleCallBatches(client, batches, options);
951
+ }
952
+ console.log(`[BatchGenerator] Adaptive: Using parallel-individual (batches too large)`);
953
+ return generateParallelIndividual(client, orbitals, options);
954
+ }
955
+ async function generateSingleBatch(client, orbitals, batchIndex, options) {
956
+ const batchStartTime = Date.now();
957
+ const logs = [];
958
+ console.log(`[BatchGenerator] Starting batch ${batchIndex + 1}: ${orbitals.map((o) => o.name).join(", ")}`);
959
+ logs.push(createLog("info", `Starting batch ${batchIndex + 1}`, {
960
+ orbitalCount: orbitals.length,
961
+ orbitals: orbitals.map((o) => o.name)
962
+ }));
963
+ try {
964
+ const batchPrompt = assembleBatchPrompt(orbitals);
965
+ console.log(`[BatchGenerator] Batch ${batchIndex + 1} prompt assembled: ${batchPrompt.prompt.length} chars`);
966
+ logs.push(createLog("info", `Batch prompt assembled`, {
967
+ promptLength: batchPrompt.prompt.length,
968
+ estimatedTokens: Math.ceil(batchPrompt.prompt.length / 4)
969
+ }));
970
+ const llmResult = await client.callWithMetadata({
971
+ systemPrompt: batchPrompt.prompt,
972
+ userPrompt: "Generate all orbitals in the batch. Return valid JSON matching the output format specified.",
973
+ maxTokens: BATCH_MAX_TOKENS,
974
+ skipSchemaValidation: true
975
+ });
976
+ logs.push(createLog("info", `LLM call completed`, {
977
+ promptTokens: llmResult.usage?.promptTokens,
978
+ completionTokens: llmResult.usage?.completionTokens
979
+ }));
980
+ const parsed = parseBatchResult(llmResult.data, orbitals);
981
+ console.log(`[BatchGenerator] Batch ${batchIndex + 1} parsed: ${parsed.filter((p) => p.success).length}/${parsed.length} successful`);
982
+ for (let i = 0; i < parsed.length; i++) {
983
+ options.onProgress?.(i + 1);
984
+ }
985
+ const durationMs = Date.now() - batchStartTime;
986
+ logs.push(createLog("info", `Batch ${batchIndex + 1} completed`, {
987
+ durationMs,
988
+ successful: parsed.filter((r) => r.success).length
989
+ }));
990
+ return {
991
+ orbitals,
992
+ results: parsed,
993
+ usage: llmResult.usage ?? void 0,
994
+ durationMs,
995
+ logs
996
+ };
997
+ } catch (error) {
998
+ const errorMessage = getErrorMessage(error);
999
+ console.error(`[BatchGenerator] Batch ${batchIndex + 1} FAILED: ${errorMessage}`);
1000
+ logs.push(createLog("error", `Batch ${batchIndex + 1} failed`, {
1001
+ error: errorMessage
1002
+ }));
1003
+ return {
1004
+ orbitals,
1005
+ results: orbitals.map((o) => ({
1006
+ orbital: o,
1007
+ success: false,
1008
+ error: errorMessage
1009
+ })),
1010
+ durationMs: Date.now() - batchStartTime,
1011
+ logs
1012
+ };
1013
+ }
1014
+ }
1015
+ function parseBatchResult(data, expectedOrbitals) {
1016
+ if (!data || typeof data !== "object") {
1017
+ return expectedOrbitals.map((o) => ({
1018
+ orbital: o,
1019
+ success: false,
1020
+ error: "Invalid response: expected object"
1021
+ }));
1022
+ }
1023
+ const obj = data;
1024
+ if (!obj.orbitals || !Array.isArray(obj.orbitals)) {
1025
+ return expectedOrbitals.map((o) => ({
1026
+ orbital: o,
1027
+ success: false,
1028
+ error: "Invalid response: missing orbitals array"
1029
+ }));
1030
+ }
1031
+ const results = obj.orbitals;
1032
+ return expectedOrbitals.map((expected, index) => {
1033
+ const result = results[index];
1034
+ if (!result) {
1035
+ return {
1036
+ orbital: expected,
1037
+ success: false,
1038
+ error: `Missing result for orbital ${index + 1}`
1039
+ };
1040
+ }
1041
+ if (!result.name) {
1042
+ return {
1043
+ orbital: expected,
1044
+ success: false,
1045
+ error: "Generated orbital missing name"
1046
+ };
1047
+ }
1048
+ return {
1049
+ orbital: result,
1050
+ success: true
1051
+ };
1052
+ });
1053
+ }
1054
+ var init_batch_generator = __esm({
1055
+ "src/orbitals/batch/batch-generator.ts"() {
1056
+ init_shared();
1057
+ init_prompt_assembler2();
1058
+ init_concurrency();
1059
+ }
1060
+ });
1061
+
1062
+ // src/orbitals/batch/index.ts
1063
+ var init_batch = __esm({
1064
+ "src/orbitals/batch/index.ts"() {
1065
+ init_batch_generator();
1066
+ init_prompt_assembler2();
1067
+ init_concurrency();
1068
+ }
1069
+ });
1070
+
1071
+ // src/tools/orbital-batch-subagent.ts
1072
+ var orbital_batch_subagent_exports = {};
1073
+ __export(orbital_batch_subagent_exports, {
1074
+ createOrbitalBatchSubagentTool: () => createOrbitalBatchSubagentTool
1075
+ });
1076
+ function createOrbitalBatchSubagentTool(options = {}) {
1077
+ let eventCallback = options.onSubagentEvent;
1078
+ let completeCallback = options.onBatchComplete;
1079
+ const requirements = options.requirements;
1080
+ const workDir = options.workDir;
1081
+ const setEventCallback = (callback) => {
1082
+ eventCallback = callback;
1083
+ };
1084
+ const setBatchCompleteCallback = (callback) => {
1085
+ completeCallback = callback;
1086
+ };
1087
+ const emitEvent = (orbitalName, orbitalIndex, totalOrbitals, type, data) => {
1088
+ if (eventCallback) {
1089
+ eventCallback(orbitalName, orbitalIndex, totalOrbitals, {
1090
+ type,
1091
+ data,
1092
+ timestamp: Date.now()
1093
+ });
1094
+ }
1095
+ };
1096
+ const batchTool = tool(
1097
+ async ({ orbitals, options: batchOptions }) => {
1098
+ if (!orbitals || orbitals.length === 0) {
1099
+ return JSON.stringify({
1100
+ success: false,
1101
+ error: "No orbitals provided for batch generation.",
1102
+ orbitals: []
1103
+ });
1104
+ }
1105
+ console.log(`[OrbitalBatchSubagent] Starting batch generation for ${orbitals.length} orbitals`);
1106
+ try {
1107
+ emitEvent("batch", 0, 1, "message", {
1108
+ content: `Starting batch generation for ${orbitals.length} orbitals`,
1109
+ role: "assistant",
1110
+ isComplete: false
1111
+ });
1112
+ emitEvent("batch", 0, 1, "todo_update", {
1113
+ todos: orbitals.map((o, i) => ({
1114
+ id: `orbital-${i}`,
1115
+ task: `Generate ${o.name}`,
1116
+ status: "pending"
1117
+ }))
1118
+ });
1119
+ const client = new LLMClient({
1120
+ provider: options.provider || "anthropic",
1121
+ model: options.model || "claude-sonnet-4-20250514"
1122
+ });
1123
+ const generationOptions = {
1124
+ mode: batchOptions?.mode || "adaptive",
1125
+ batchSize: batchOptions?.batchSize,
1126
+ concurrency: batchOptions?.maxConcurrency ?? PROVIDER_CONCURRENCY_LIMITS[client.getProvider()],
1127
+ preserveRelationships: batchOptions?.preserveRelationships ?? true,
1128
+ requirements,
1129
+ onBatchProgress: (event) => {
1130
+ if (event.type === "orbital_complete" && event.orbitalName) {
1131
+ emitEvent(event.orbitalName || "batch", event.batchIndex, event.totalBatches, "todo_update", {
1132
+ todos: orbitals.map((o, i) => ({
1133
+ id: `orbital-${i}`,
1134
+ task: `Generate ${o.name}`,
1135
+ status: o.name === event.orbitalName ? "completed" : event.completedOrbitals > i ? "completed" : "pending"
1136
+ }))
1137
+ });
1138
+ }
1139
+ emitEvent(event.orbitalName || "batch", event.batchIndex, event.totalBatches, "generation_log", {
1140
+ level: "info",
1141
+ message: `Progress: ${event.completedOrbitals}/${event.totalOrbitals} orbitals complete`,
1142
+ data: {
1143
+ batchIndex: event.batchIndex,
1144
+ completedOrbitals: event.completedOrbitals,
1145
+ totalOrbitals: event.totalOrbitals
1146
+ }
1147
+ });
1148
+ }
1149
+ };
1150
+ emitEvent("batch", 0, 1, "tool_call", {
1151
+ tool: "generateOrbitalsBatch",
1152
+ args: {
1153
+ orbitalCount: orbitals.length,
1154
+ mode: generationOptions.mode,
1155
+ concurrency: generationOptions.concurrency
1156
+ }
1157
+ });
1158
+ const result = await generateOrbitalsBatch(client, orbitals, generationOptions);
1159
+ emitEvent("batch", result.totalBatches - 1, result.totalBatches, "todo_update", {
1160
+ todos: orbitals.map((o, i) => ({
1161
+ id: `orbital-${i}`,
1162
+ task: `Generate ${o.name}`,
1163
+ status: result.batchResults.some(
1164
+ (b) => b.results.some((r) => r.orbital.name === o.name && r.success)
1165
+ ) ? "completed" : "failed"
1166
+ }))
1167
+ });
1168
+ const generatedOrbitals = result.results.filter((r) => r.orbital).map((r) => r.orbital);
1169
+ const successCount = generatedOrbitals.length;
1170
+ const failedCount = orbitals.length - successCount;
1171
+ emitEvent("batch", result.totalBatches - 1, result.totalBatches, "message", {
1172
+ content: `Batch generation complete: ${successCount}/${orbitals.length} orbitals generated successfully`,
1173
+ role: "assistant",
1174
+ isComplete: true
1175
+ });
1176
+ if (workDir && completeCallback && generatedOrbitals.length > 0) {
1177
+ try {
1178
+ await completeCallback(generatedOrbitals, 0, 1);
1179
+ emitEvent("batch", result.totalBatches - 1, result.totalBatches, "generation_log", {
1180
+ level: "info",
1181
+ message: `Persisted ${generatedOrbitals.length} orbitals`
1182
+ });
1183
+ } catch (persistError) {
1184
+ console.error(`[OrbitalBatchSubagent] Failed to persist orbitals:`, persistError);
1185
+ emitEvent("batch", result.totalBatches - 1, result.totalBatches, "generation_log", {
1186
+ level: "warn",
1187
+ message: "Failed to persist some orbitals",
1188
+ data: { error: String(persistError) }
1189
+ });
1190
+ }
1191
+ }
1192
+ return JSON.stringify({
1193
+ success: successCount === orbitals.length,
1194
+ generated: successCount,
1195
+ failed: failedCount,
1196
+ total: orbitals.length,
1197
+ orbitals: generatedOrbitals,
1198
+ duration: result.totalDurationMs,
1199
+ totalTokens: result.summary.totalTokens,
1200
+ batches: result.totalBatches
1201
+ });
1202
+ } catch (error) {
1203
+ const errorMessage = error instanceof Error ? error.message : String(error);
1204
+ console.error(`[OrbitalBatchSubagent] Batch generation failed:`, errorMessage);
1205
+ emitEvent("batch", 0, 1, "error", {
1206
+ error: errorMessage,
1207
+ code: "BATCH_GENERATION_ERROR"
1208
+ });
1209
+ return JSON.stringify({
1210
+ success: false,
1211
+ error: errorMessage,
1212
+ orbitals: []
1213
+ });
1214
+ }
1215
+ },
1216
+ {
1217
+ name: "generate_orbitals_batch",
1218
+ 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.",
1219
+ schema: OrbitalBatchInputSchema
1220
+ }
1221
+ );
1222
+ return {
1223
+ tool: batchTool,
1224
+ setEventCallback,
1225
+ setBatchCompleteCallback
1226
+ };
1227
+ }
1228
+ var OrbitalBatchInputSchema;
1229
+ var init_orbital_batch_subagent = __esm({
1230
+ "src/tools/orbital-batch-subagent.ts"() {
1231
+ init_shared();
1232
+ init_batch();
1233
+ OrbitalBatchInputSchema = z.object({
1234
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1235
+ orbitals: z.array(z.any()).describe("Array of OrbitalUnits to generate"),
1236
+ options: z.object({
1237
+ mode: z.enum(["single-call", "parallel-individual", "adaptive"]).optional().default("adaptive"),
1238
+ batchSize: z.number().optional(),
1239
+ maxConcurrency: z.number().optional(),
1240
+ preserveRelationships: z.boolean().optional().default(true)
1241
+ }).optional().describe("Batch generation options")
1242
+ });
1243
+ }
1244
+ });
396
1245
  var ExtractedRequirementsSchema = z.object({
397
1246
  /** Entity names to create */
398
1247
  entities: z.array(z.string()).optional().default([]),
@@ -422,7 +1271,7 @@ var GenerateRequestSchema = z.object({
422
1271
  /** Optional: Workspace directory (defaults to temp dir) */
423
1272
  workspace: z.string().optional(),
424
1273
  /** Optional: LLM provider */
425
- provider: z.enum(["anthropic", "openai", "deepseek"]).optional(),
1274
+ provider: z.enum(["anthropic", "openai", "deepseek", "kimi", "openrouter"]).optional(),
426
1275
  /** Optional: Model name */
427
1276
  model: z.string().optional(),
428
1277
  /** Optional: Disable human-in-the-loop interrupts (for eval/testing) */
@@ -1825,8 +2674,8 @@ function createGenerateOrbitalDomainTool(options = {}) {
1825
2674
  orbitalName: spec.name
1826
2675
  });
1827
2676
  const client = new LLMClient({
1828
- provider: "anthropic",
1829
- model: "claude-sonnet-4-20250514",
2677
+ provider: options.provider ?? "anthropic",
2678
+ model: options.model ?? "claude-sonnet-4-20250514",
1830
2679
  temperature: 0
1831
2680
  });
1832
2681
  const userPrompt = buildDynamicUserPrompt(spec);
@@ -2032,20 +2881,8 @@ function createDomainOrbitalTools(options = {}) {
2032
2881
 
2033
2882
  // src/orbitals/generation/orbital-generator.ts
2034
2883
  init_cache();
2035
- function getEntityName2(entity) {
2036
- if (isEntityReference(entity)) {
2037
- return entity.replace(".entity", "");
2038
- }
2039
- return entity.name;
2040
- }
2041
- function createLog(level, message, data) {
2042
- return {
2043
- timestamp: Date.now(),
2044
- level,
2045
- message,
2046
- data
2047
- };
2048
- }
2884
+ init_shared();
2885
+ init_shared();
2049
2886
  async function generateFullOrbital(client, orbital, options = {}) {
2050
2887
  const {
2051
2888
  maxTokens = 8192,
@@ -2318,8 +3155,8 @@ function createOrbitalSubagentTool(options = {}) {
2318
3155
  ]
2319
3156
  });
2320
3157
  const client = new LLMClient({
2321
- provider: "anthropic",
2322
- model: "claude-sonnet-4-20250514"
3158
+ provider: options.provider ?? "anthropic",
3159
+ model: options.model ?? "claude-sonnet-4-20250514"
2323
3160
  });
2324
3161
  emitEvent(orbitalUnit.name, orbitalIndex, totalOrbitals, "tool_call", {
2325
3162
  tool: "llm_generate",
@@ -2451,6 +3288,9 @@ function createSubagentEventWrapper(writeEvent) {
2451
3288
  writeEvent(sseEvent);
2452
3289
  };
2453
3290
  }
3291
+
3292
+ // src/tools/index.ts
3293
+ init_orbital_batch_subagent();
2454
3294
  function getTraitGenerationPrompt() {
2455
3295
  return `You are a Trait Generator for KFlow orbital schemas.
2456
3296
 
@@ -4678,6 +5518,21 @@ function createLLMClient(provider, model, verbose) {
4678
5518
  model: model || OPENAI_MODELS.GPT4O,
4679
5519
  temperature
4680
5520
  });
5521
+ case "kimi":
5522
+ if (verbose)
5523
+ console.log(`[SkillAgent] Using Kimi: ${model || KIMI_MODELS.K2_5}`);
5524
+ return createKimiClient({
5525
+ model: model || KIMI_MODELS.K2_5,
5526
+ temperature: 0.6
5527
+ // Kimi with thinking disabled requires 0.6
5528
+ });
5529
+ case "openrouter":
5530
+ if (verbose)
5531
+ console.log(`[SkillAgent] Using OpenRouter: ${model || OPENROUTER_MODELS.QWEN_2_5_72B}`);
5532
+ return createOpenRouterClient({
5533
+ model: model || OPENROUTER_MODELS.QWEN_2_5_72B,
5534
+ temperature: 0.3
5535
+ });
4681
5536
  case "anthropic":
4682
5537
  default:
4683
5538
  if (verbose)
@@ -4702,6 +5557,8 @@ async function createSkillAgent(options) {
4702
5557
  threadId: providedThreadId,
4703
5558
  provider = "anthropic",
4704
5559
  model,
5560
+ subagentProvider = "anthropic",
5561
+ subagentModel = "claude-sonnet-4-20250514",
4705
5562
  verbose = false,
4706
5563
  skillLoader,
4707
5564
  skillRefLoader
@@ -4798,18 +5655,24 @@ ${skillContents}`;
4798
5655
  const finishTaskTool = createFinishTaskTool(workDir);
4799
5656
  const validateSchemaTool = createValidateSchemaTool(workDir);
4800
5657
  const ORBITAL_SKILLS = ["kflow-orbitals", "kflow-orbital-games", "kflow-orbital-fixing"];
5658
+ const ORBITAL_BATCH_SKILLS = ["kflow-orbitals-batch"];
4801
5659
  const LEAN_SKILLS = ["kflow-lean-orbitals", "kflow-lean-fixing"];
4802
5660
  const isOrbitalSkill = primarySkill.name === "kflow-orbitals";
5661
+ const isOrbitalBatchSkill = ORBITAL_BATCH_SKILLS.includes(primarySkill.name);
4803
5662
  const isLeanSkill = LEAN_SKILLS.includes(primarySkill.name);
4804
5663
  const needsChunkingTools = ORBITAL_SKILLS.includes(primarySkill.name);
4805
5664
  let orbitalTool;
4806
5665
  let setOrbitalEventCallback;
4807
5666
  let setOrbitalCompleteCallback;
5667
+ let orbitalBatchTool;
5668
+ let setBatchEventCallback;
4808
5669
  let domainOrbitalTools;
4809
5670
  const chunkingTools = needsChunkingTools ? createSchemaChunkingTools(workDir) : null;
4810
5671
  if (isOrbitalSkill) {
4811
5672
  const orbitalResult = createOrbitalSubagentTool({
4812
- requirements: options.requirements
5673
+ requirements: options.requirements,
5674
+ provider: subagentProvider,
5675
+ model: subagentModel
4813
5676
  });
4814
5677
  orbitalTool = orbitalResult.tool;
4815
5678
  setOrbitalEventCallback = orbitalResult.setEventCallback;
@@ -4821,10 +5684,31 @@ ${skillContents}`;
4821
5684
  console.log(`[SkillAgent] Orbital tools enabled for kflow-orbitals skill`);
4822
5685
  }
4823
5686
  }
5687
+ if (isOrbitalBatchSkill) {
5688
+ const { createOrbitalBatchSubagentTool: createOrbitalBatchSubagentTool2 } = await Promise.resolve().then(() => (init_orbital_batch_subagent(), orbital_batch_subagent_exports));
5689
+ const batchResult = createOrbitalBatchSubagentTool2({
5690
+ requirements: options.requirements,
5691
+ provider: subagentProvider,
5692
+ model: subagentModel,
5693
+ workDir
5694
+ });
5695
+ orbitalBatchTool = batchResult.tool;
5696
+ setBatchEventCallback = batchResult.setEventCallback;
5697
+ if (options.onSubagentEvent) {
5698
+ setBatchEventCallback(options.onSubagentEvent);
5699
+ }
5700
+ if (verbose) {
5701
+ console.log(`[SkillAgent] Batch orbital tools enabled for kflow-orbitals-batch skill`);
5702
+ }
5703
+ }
4824
5704
  if (isLeanSkill) {
4825
- domainOrbitalTools = createDomainOrbitalTools({ workDir });
5705
+ domainOrbitalTools = createDomainOrbitalTools({
5706
+ workDir,
5707
+ provider: subagentProvider,
5708
+ model: subagentModel
5709
+ });
4826
5710
  if (verbose) {
4827
- console.log(`[SkillAgent] Domain orbital tools enabled for ${primarySkill.name} skill`);
5711
+ console.log(`[SkillAgent] Domain orbital tools enabled for ${primarySkill.name} skill (provider: ${subagentProvider})`);
4828
5712
  }
4829
5713
  }
4830
5714
  const githubTools = options.githubConfig ? createGitHubToolsArray({
@@ -4839,8 +5723,9 @@ ${skillContents}`;
4839
5723
  const tools = [
4840
5724
  executeTool,
4841
5725
  finishTaskTool,
4842
- ...isOrbitalSkill ? [] : [validateSchemaTool],
5726
+ ...isOrbitalSkill || isOrbitalBatchSkill ? [] : [validateSchemaTool],
4843
5727
  ...orbitalTool ? [orbitalTool] : [],
5728
+ ...orbitalBatchTool ? [orbitalBatchTool] : [],
4844
5729
  ...domainOrbitalTools ? [
4845
5730
  domainOrbitalTools.generateOrbitalDomain,
4846
5731
  domainOrbitalTools.constructCombinedDomain