@almadar/agent 1.2.2 → 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/agent/index.d.ts +3 -3
- package/dist/agent/index.js +993 -303
- package/dist/agent/index.js.map +1 -1
- package/dist/{api-types-BW_58thJ.d.ts → api-types-DVdGNr2M.d.ts} +3 -3
- package/dist/event-transformer/index.d.ts +1 -1
- package/dist/event-transformer/index.js +1 -1
- package/dist/event-transformer/index.js.map +1 -1
- package/dist/{index-D-Ahuo6F.d.ts → index-BN4d3ObG.d.ts} +7 -3
- package/dist/index-DFJdTDbo.d.ts +2320 -0
- package/dist/index.d.ts +14 -68
- package/dist/index.js +994 -306
- package/dist/index.js.map +1 -1
- package/dist/{orbital-subagent-cNfTLdXQ.d.ts → orbital-subagent-CCo-ONJY.d.ts} +34 -25
- package/dist/tools/index.d.ts +7 -2380
- package/dist/tools/index.js +874 -286
- package/dist/tools/index.js.map +1 -1
- package/package.json +10 -5
package/dist/index.js
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
import { AgentDomainCategorySchema, isOrbitalDefinition, getTraitName, isPageReferenceString, isPageReferenceObject, isEntityReference } from '@almadar/core/types';
|
|
2
|
-
import {
|
|
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, generateKflowDesignSkill } from '@almadar/skills';
|
|
13
|
-
import { formatRecommendationsForPrompt, buildRecommendationContext, recommendPatterns } from '@almadar/patterns';
|
|
14
13
|
import { GitHubIntegration } from '@almadar/integrations';
|
|
15
14
|
import '@langchain/core/messages';
|
|
16
15
|
import { FilesystemBackend, createDeepAgent } from 'deepagents';
|
|
@@ -394,6 +393,855 @@ var init_cache = __esm({
|
|
|
394
393
|
init_prompt_assembler();
|
|
395
394
|
}
|
|
396
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
|
+
});
|
|
397
1245
|
var ExtractedRequirementsSchema = z.object({
|
|
398
1246
|
/** Entity names to create */
|
|
399
1247
|
entities: z.array(z.string()).optional().default([]),
|
|
@@ -423,7 +1271,7 @@ var GenerateRequestSchema = z.object({
|
|
|
423
1271
|
/** Optional: Workspace directory (defaults to temp dir) */
|
|
424
1272
|
workspace: z.string().optional(),
|
|
425
1273
|
/** Optional: LLM provider */
|
|
426
|
-
provider: z.enum(["anthropic", "openai", "deepseek"]).optional(),
|
|
1274
|
+
provider: z.enum(["anthropic", "openai", "deepseek", "kimi", "openrouter"]).optional(),
|
|
427
1275
|
/** Optional: Model name */
|
|
428
1276
|
model: z.string().optional(),
|
|
429
1277
|
/** Optional: Disable human-in-the-loop interrupts (for eval/testing) */
|
|
@@ -1341,6 +2189,77 @@ npx kflow domain:validate input.orb --verbose
|
|
|
1341
2189
|
|
|
1342
2190
|
// src/tools/finish-task.ts
|
|
1343
2191
|
var execAsync2 = promisify(exec);
|
|
2192
|
+
var PROP_CORRECTIONS = {
|
|
2193
|
+
onSubmit: "submitEvent",
|
|
2194
|
+
onCancel: "cancelEvent",
|
|
2195
|
+
headerActions: "actions",
|
|
2196
|
+
loading: "isLoading",
|
|
2197
|
+
fieldNames: "fields"
|
|
2198
|
+
};
|
|
2199
|
+
function autoCorrectProps(schema) {
|
|
2200
|
+
let corrections = 0;
|
|
2201
|
+
JSON.stringify(schema);
|
|
2202
|
+
function walkAndFix(obj) {
|
|
2203
|
+
if (Array.isArray(obj)) {
|
|
2204
|
+
return obj.map(walkAndFix);
|
|
2205
|
+
}
|
|
2206
|
+
if (obj && typeof obj === "object") {
|
|
2207
|
+
const result = {};
|
|
2208
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
2209
|
+
if (key in PROP_CORRECTIONS) {
|
|
2210
|
+
result[PROP_CORRECTIONS[key]] = walkAndFix(value);
|
|
2211
|
+
corrections++;
|
|
2212
|
+
} else {
|
|
2213
|
+
result[key] = walkAndFix(value);
|
|
2214
|
+
}
|
|
2215
|
+
}
|
|
2216
|
+
return result;
|
|
2217
|
+
}
|
|
2218
|
+
return obj;
|
|
2219
|
+
}
|
|
2220
|
+
const fixed = walkAndFix(schema);
|
|
2221
|
+
Object.assign(schema, fixed);
|
|
2222
|
+
return corrections;
|
|
2223
|
+
}
|
|
2224
|
+
function checkCompositionQuality(schema) {
|
|
2225
|
+
const warnings = [];
|
|
2226
|
+
const orbitals = schema.orbitals;
|
|
2227
|
+
if (!Array.isArray(orbitals)) return warnings;
|
|
2228
|
+
for (const orbital of orbitals) {
|
|
2229
|
+
const orbObj = orbital;
|
|
2230
|
+
const traits = orbObj.traits;
|
|
2231
|
+
if (!Array.isArray(traits)) continue;
|
|
2232
|
+
for (const trait of traits) {
|
|
2233
|
+
const traitObj = trait;
|
|
2234
|
+
const transitions = traitObj.stateMachine?.transitions;
|
|
2235
|
+
if (!Array.isArray(transitions)) continue;
|
|
2236
|
+
for (const transition of transitions) {
|
|
2237
|
+
const trans = transition;
|
|
2238
|
+
if (trans.event !== "INIT") continue;
|
|
2239
|
+
const effects = trans.effects;
|
|
2240
|
+
if (!Array.isArray(effects)) continue;
|
|
2241
|
+
const mainRenderUIs = effects.filter(
|
|
2242
|
+
(e) => Array.isArray(e) && e[0] === "render-ui" && e[1] === "main"
|
|
2243
|
+
);
|
|
2244
|
+
if (mainRenderUIs.length > 1) {
|
|
2245
|
+
warnings.push(
|
|
2246
|
+
`\u26A0\uFE0F ${orbObj.name}/${traitObj.name} INIT has ${mainRenderUIs.length} flat render-ui calls to main. Should be a single composed stack with children.`
|
|
2247
|
+
);
|
|
2248
|
+
}
|
|
2249
|
+
if (mainRenderUIs.length === 1) {
|
|
2250
|
+
const renderPayload = mainRenderUIs[0];
|
|
2251
|
+
const payload = renderPayload[2];
|
|
2252
|
+
if (payload && payload.type !== "stack" && !payload.children) {
|
|
2253
|
+
warnings.push(
|
|
2254
|
+
`\u26A0\uFE0F ${orbObj.name}/${traitObj.name} INIT renders a single flat ${payload.type} to main. Should be a composed stack with header, metrics, and data sections.`
|
|
2255
|
+
);
|
|
2256
|
+
}
|
|
2257
|
+
}
|
|
2258
|
+
}
|
|
2259
|
+
}
|
|
2260
|
+
}
|
|
2261
|
+
return warnings;
|
|
2262
|
+
}
|
|
1344
2263
|
async function collectOrbitalsFromDir(workDir) {
|
|
1345
2264
|
const orbitalsDir = path.join(workDir, ".orbitals");
|
|
1346
2265
|
try {
|
|
@@ -1395,6 +2314,8 @@ function createFinishTaskTool(workDir) {
|
|
|
1395
2314
|
let stats = null;
|
|
1396
2315
|
let validationResult = null;
|
|
1397
2316
|
let source = null;
|
|
2317
|
+
let propCorrections = 0;
|
|
2318
|
+
let compositionWarnings = [];
|
|
1398
2319
|
if (workDir) {
|
|
1399
2320
|
const orbitals = await collectOrbitalsFromDir(workDir);
|
|
1400
2321
|
if (orbitals.length > 0) {
|
|
@@ -1439,6 +2360,10 @@ function createFinishTaskTool(workDir) {
|
|
|
1439
2360
|
} catch {
|
|
1440
2361
|
}
|
|
1441
2362
|
}
|
|
2363
|
+
if (combinedSchema) {
|
|
2364
|
+
propCorrections = autoCorrectProps(combinedSchema);
|
|
2365
|
+
compositionWarnings = checkCompositionQuality(combinedSchema);
|
|
2366
|
+
}
|
|
1442
2367
|
if (combinedSchema) {
|
|
1443
2368
|
const schemaPath = path.join(workDir, "schema.json");
|
|
1444
2369
|
await fs4.writeFile(schemaPath, JSON.stringify(combinedSchema, null, 2));
|
|
@@ -1458,6 +2383,10 @@ function createFinishTaskTool(workDir) {
|
|
|
1458
2383
|
errorCount: validationResult.errors?.length || 0,
|
|
1459
2384
|
warningCount: validationResult.warnings?.length || 0
|
|
1460
2385
|
} : void 0,
|
|
2386
|
+
designQuality: {
|
|
2387
|
+
propCorrections: propCorrections || 0,
|
|
2388
|
+
compositionWarnings: compositionWarnings || []
|
|
2389
|
+
},
|
|
1461
2390
|
schemaPath: combinedSchema ? path.join(workDir, "schema.json") : input.schemaPath,
|
|
1462
2391
|
nextAction: "NONE - Task is complete. Output a brief success message to the user."
|
|
1463
2392
|
};
|
|
@@ -1745,8 +2674,8 @@ function createGenerateOrbitalDomainTool(options = {}) {
|
|
|
1745
2674
|
orbitalName: spec.name
|
|
1746
2675
|
});
|
|
1747
2676
|
const client = new LLMClient({
|
|
1748
|
-
provider: "anthropic",
|
|
1749
|
-
model: "claude-sonnet-4-20250514",
|
|
2677
|
+
provider: options.provider ?? "anthropic",
|
|
2678
|
+
model: options.model ?? "claude-sonnet-4-20250514",
|
|
1750
2679
|
temperature: 0
|
|
1751
2680
|
});
|
|
1752
2681
|
const userPrompt = buildDynamicUserPrompt(spec);
|
|
@@ -1952,20 +2881,8 @@ function createDomainOrbitalTools(options = {}) {
|
|
|
1952
2881
|
|
|
1953
2882
|
// src/orbitals/generation/orbital-generator.ts
|
|
1954
2883
|
init_cache();
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
return entity.replace(".entity", "");
|
|
1958
|
-
}
|
|
1959
|
-
return entity.name;
|
|
1960
|
-
}
|
|
1961
|
-
function createLog(level, message, data) {
|
|
1962
|
-
return {
|
|
1963
|
-
timestamp: Date.now(),
|
|
1964
|
-
level,
|
|
1965
|
-
message,
|
|
1966
|
-
data
|
|
1967
|
-
};
|
|
1968
|
-
}
|
|
2884
|
+
init_shared();
|
|
2885
|
+
init_shared();
|
|
1969
2886
|
async function generateFullOrbital(client, orbital, options = {}) {
|
|
1970
2887
|
const {
|
|
1971
2888
|
maxTokens = 8192,
|
|
@@ -2238,8 +3155,8 @@ function createOrbitalSubagentTool(options = {}) {
|
|
|
2238
3155
|
]
|
|
2239
3156
|
});
|
|
2240
3157
|
const client = new LLMClient({
|
|
2241
|
-
provider: "anthropic",
|
|
2242
|
-
model: "claude-sonnet-4-20250514"
|
|
3158
|
+
provider: options.provider ?? "anthropic",
|
|
3159
|
+
model: options.model ?? "claude-sonnet-4-20250514"
|
|
2243
3160
|
});
|
|
2244
3161
|
emitEvent(orbitalUnit.name, orbitalIndex, totalOrbitals, "tool_call", {
|
|
2245
3162
|
tool: "llm_generate",
|
|
@@ -2371,6 +3288,9 @@ function createSubagentEventWrapper(writeEvent) {
|
|
|
2371
3288
|
writeEvent(sseEvent);
|
|
2372
3289
|
};
|
|
2373
3290
|
}
|
|
3291
|
+
|
|
3292
|
+
// src/tools/index.ts
|
|
3293
|
+
init_orbital_batch_subagent();
|
|
2374
3294
|
function getTraitGenerationPrompt() {
|
|
2375
3295
|
return `You are a Trait Generator for KFlow orbital schemas.
|
|
2376
3296
|
|
|
@@ -3016,273 +3936,6 @@ function createSchemaChunkingTools(workDir) {
|
|
|
3016
3936
|
applyChunk: createApplyChunkTool(workDir)
|
|
3017
3937
|
};
|
|
3018
3938
|
}
|
|
3019
|
-
var designCache = /* @__PURE__ */ new Map();
|
|
3020
|
-
var CACHE_TTL_MS2 = 24 * 60 * 60 * 1e3;
|
|
3021
|
-
var CACHE_VERSION2 = 1;
|
|
3022
|
-
function generateFingerprint2(input) {
|
|
3023
|
-
const normalized = JSON.stringify({
|
|
3024
|
-
version: CACHE_VERSION2,
|
|
3025
|
-
...input
|
|
3026
|
-
});
|
|
3027
|
-
return crypto.createHash("sha256").update(normalized).digest("hex").slice(0, 16);
|
|
3028
|
-
}
|
|
3029
|
-
function getCached2(fingerprint) {
|
|
3030
|
-
const entry = designCache.get(fingerprint);
|
|
3031
|
-
if (!entry) return null;
|
|
3032
|
-
if (Date.now() - entry.timestamp > CACHE_TTL_MS2) {
|
|
3033
|
-
designCache.delete(fingerprint);
|
|
3034
|
-
return null;
|
|
3035
|
-
}
|
|
3036
|
-
return entry;
|
|
3037
|
-
}
|
|
3038
|
-
var STATIC_DESIGN_PROMPT = null;
|
|
3039
|
-
function getDesignSystemPrompt() {
|
|
3040
|
-
if (!STATIC_DESIGN_PROMPT) {
|
|
3041
|
-
const skill = generateKflowDesignSkill();
|
|
3042
|
-
STATIC_DESIGN_PROMPT = skill.content;
|
|
3043
|
-
}
|
|
3044
|
-
return STATIC_DESIGN_PROMPT;
|
|
3045
|
-
}
|
|
3046
|
-
function getPatternRecommendations(input) {
|
|
3047
|
-
const recContext = buildRecommendationContext({
|
|
3048
|
-
state: input.from,
|
|
3049
|
-
event: input.event,
|
|
3050
|
-
slot: input.slot,
|
|
3051
|
-
domainCategory: input.domainCategory,
|
|
3052
|
-
entityFields: input.entityFields
|
|
3053
|
-
});
|
|
3054
|
-
return recommendPatterns(recContext, 8);
|
|
3055
|
-
}
|
|
3056
|
-
function buildDesignUserPrompt(input) {
|
|
3057
|
-
const fieldList = input.entityFields.map((f) => {
|
|
3058
|
-
let desc = ` - ${f.name}: ${f.type}`;
|
|
3059
|
-
if (f.values) desc += ` (values: ${f.values.join(", ")})`;
|
|
3060
|
-
return desc;
|
|
3061
|
-
}).join("\n");
|
|
3062
|
-
const hints = [];
|
|
3063
|
-
if (input.designStyle) hints.push(`Style: ${input.designStyle}`);
|
|
3064
|
-
if (input.flowPattern) hints.push(`Flow: ${input.flowPattern}`);
|
|
3065
|
-
if (input.listPattern) hints.push(`List: ${input.listPattern}`);
|
|
3066
|
-
if (input.formPattern) hints.push(`Form: ${input.formPattern}`);
|
|
3067
|
-
if (input.detailPattern) hints.push(`Detail: ${input.detailPattern}`);
|
|
3068
|
-
const vocab = input.vocabulary ? Object.entries(input.vocabulary).map(([k, v]) => ` ${k} \u2192 "${v}"`).join("\n") : "";
|
|
3069
|
-
return `Design render-ui effects for this transition:
|
|
3070
|
-
|
|
3071
|
-
## Transition
|
|
3072
|
-
- **From**: ${input.from}
|
|
3073
|
-
- **To**: ${input.to}
|
|
3074
|
-
- **Event**: ${input.event}
|
|
3075
|
-
- **Slot**: ${input.slot}
|
|
3076
|
-
|
|
3077
|
-
## Entity: ${input.entityName}
|
|
3078
|
-
${fieldList}
|
|
3079
|
-
|
|
3080
|
-
## Domain
|
|
3081
|
-
- **Category**: ${input.domainCategory || "business"}
|
|
3082
|
-
${vocab ? `- **Vocabulary**:
|
|
3083
|
-
${vocab}` : ""}
|
|
3084
|
-
${hints.length > 0 ? `- **Design Hints**: ${hints.join(", ")}` : ""}
|
|
3085
|
-
|
|
3086
|
-
${input.recommendationsSection || ""}
|
|
3087
|
-
|
|
3088
|
-
${input.existingEffects ? `## Existing Effects (enhance these)
|
|
3089
|
-
\`\`\`json
|
|
3090
|
-
${JSON.stringify(input.existingEffects, null, 2)}
|
|
3091
|
-
\`\`\`` : ""}
|
|
3092
|
-
|
|
3093
|
-
Return ONLY the JSON array of render-ui effect tuples.`;
|
|
3094
|
-
}
|
|
3095
|
-
var DesignTransitionSchema = z.object({
|
|
3096
|
-
from: z.string().describe('Source state name (e.g., "Browsing")'),
|
|
3097
|
-
to: z.string().describe('Target state name (e.g., "Browsing" for self-loop, "Creating" for transition)'),
|
|
3098
|
-
event: z.string().describe('Event name (e.g., "INIT", "CREATE", "VIEW", "EDIT", "DELETE", "SAVE", "CANCEL")'),
|
|
3099
|
-
slot: z.string().describe('UI slot to render into: "main", "modal", "drawer", "sidebar", "overlay"'),
|
|
3100
|
-
entityName: z.string().describe('Entity name (e.g., "Task", "Order")'),
|
|
3101
|
-
entityFields: z.array(z.object({
|
|
3102
|
-
name: z.string(),
|
|
3103
|
-
type: z.string(),
|
|
3104
|
-
values: z.array(z.string()).optional()
|
|
3105
|
-
})).describe("Entity fields with types and optional enum values"),
|
|
3106
|
-
domainCategory: AgentDomainCategorySchema.optional().describe("Domain category for pattern selection"),
|
|
3107
|
-
vocabulary: z.record(z.string(), z.string()).optional().describe('Domain vocabulary mapping (e.g., { "create": "Place Order", "item": "Order" })'),
|
|
3108
|
-
designStyle: z.enum(["minimal", "modern", "playful", "data-driven", "immersive"]).optional().describe("Visual style hint"),
|
|
3109
|
-
flowPattern: z.enum(["hub-spoke", "master-detail", "crud-cycle", "linear", "role-based"]).optional().describe("Application flow pattern"),
|
|
3110
|
-
listPattern: z.enum(["entity-table", "entity-cards", "entity-list"]).optional().describe("Preferred list pattern"),
|
|
3111
|
-
formPattern: z.enum(["modal", "drawer", "page"]).optional().describe("Preferred form pattern"),
|
|
3112
|
-
detailPattern: z.enum(["drawer", "page", "split"]).optional().describe("Preferred detail view pattern"),
|
|
3113
|
-
existingEffects: z.array(z.any()).optional().describe("Existing render-ui effects to enhance (for refinement passes)")
|
|
3114
|
-
});
|
|
3115
|
-
function createDesignTransitionTool(options = {}) {
|
|
3116
|
-
let eventCallback = options.onEvent;
|
|
3117
|
-
const setEventCallback = (callback) => {
|
|
3118
|
-
eventCallback = callback;
|
|
3119
|
-
};
|
|
3120
|
-
const emitEvent = (transitionId, type, data) => {
|
|
3121
|
-
if (eventCallback) {
|
|
3122
|
-
eventCallback(transitionId, {
|
|
3123
|
-
type,
|
|
3124
|
-
data,
|
|
3125
|
-
timestamp: Date.now()
|
|
3126
|
-
});
|
|
3127
|
-
}
|
|
3128
|
-
};
|
|
3129
|
-
const designTransitionTool = tool(
|
|
3130
|
-
async (input) => {
|
|
3131
|
-
const transitionId = `${input.entityName}:${input.from}->${input.to}:${input.event}`;
|
|
3132
|
-
const fingerprint = generateFingerprint2({
|
|
3133
|
-
from: input.from,
|
|
3134
|
-
to: input.to,
|
|
3135
|
-
event: input.event,
|
|
3136
|
-
slot: input.slot,
|
|
3137
|
-
entityName: input.entityName,
|
|
3138
|
-
entityFields: input.entityFields,
|
|
3139
|
-
domainCategory: input.domainCategory,
|
|
3140
|
-
designStyle: input.designStyle,
|
|
3141
|
-
flowPattern: input.flowPattern,
|
|
3142
|
-
listPattern: input.listPattern
|
|
3143
|
-
});
|
|
3144
|
-
try {
|
|
3145
|
-
emitEvent(transitionId, "message", {
|
|
3146
|
-
content: `Designing UI for ${transitionId}`,
|
|
3147
|
-
role: "assistant",
|
|
3148
|
-
isComplete: false
|
|
3149
|
-
});
|
|
3150
|
-
const cached = getCached2(fingerprint);
|
|
3151
|
-
if (cached) {
|
|
3152
|
-
emitEvent(transitionId, "generation_log", {
|
|
3153
|
-
level: "info",
|
|
3154
|
-
message: `Design cache HIT for ${transitionId}`,
|
|
3155
|
-
data: { fingerprint }
|
|
3156
|
-
});
|
|
3157
|
-
return JSON.stringify({
|
|
3158
|
-
success: true,
|
|
3159
|
-
transitionId,
|
|
3160
|
-
effects: cached.effects,
|
|
3161
|
-
cached: true,
|
|
3162
|
-
usage: cached.usage
|
|
3163
|
-
});
|
|
3164
|
-
}
|
|
3165
|
-
const recommendations = getPatternRecommendations(input);
|
|
3166
|
-
const recommendationsSection = formatRecommendationsForPrompt(recommendations);
|
|
3167
|
-
const systemPrompt = getDesignSystemPrompt();
|
|
3168
|
-
const userPrompt = buildDesignUserPrompt({
|
|
3169
|
-
...input,
|
|
3170
|
-
recommendationsSection
|
|
3171
|
-
});
|
|
3172
|
-
emitEvent(transitionId, "tool_call", {
|
|
3173
|
-
tool: "llm_design_transition",
|
|
3174
|
-
args: {
|
|
3175
|
-
transition: transitionId,
|
|
3176
|
-
slot: input.slot,
|
|
3177
|
-
domain: input.domainCategory
|
|
3178
|
-
}
|
|
3179
|
-
});
|
|
3180
|
-
const client = new LLMClient({
|
|
3181
|
-
provider: "anthropic",
|
|
3182
|
-
model: "claude-sonnet-4-20250514",
|
|
3183
|
-
temperature: 0.1
|
|
3184
|
-
// Slight creativity for design
|
|
3185
|
-
});
|
|
3186
|
-
const response = await client.callWithCache({
|
|
3187
|
-
systemPrompt: "",
|
|
3188
|
-
systemBlocks: [{
|
|
3189
|
-
type: "text",
|
|
3190
|
-
text: systemPrompt,
|
|
3191
|
-
cache_control: { type: "ephemeral" }
|
|
3192
|
-
}],
|
|
3193
|
-
userPrompt,
|
|
3194
|
-
maxTokens: 4096,
|
|
3195
|
-
rawText: true
|
|
3196
|
-
});
|
|
3197
|
-
const rawText = (response.raw || String(response.data) || "").trim();
|
|
3198
|
-
let effects;
|
|
3199
|
-
try {
|
|
3200
|
-
const jsonText = rawText.replace(/^```(?:json)?\n?/m, "").replace(/\n?```$/m, "").trim();
|
|
3201
|
-
effects = JSON.parse(jsonText);
|
|
3202
|
-
if (!Array.isArray(effects)) {
|
|
3203
|
-
effects = [effects];
|
|
3204
|
-
}
|
|
3205
|
-
} catch {
|
|
3206
|
-
return JSON.stringify({
|
|
3207
|
-
success: false,
|
|
3208
|
-
transitionId,
|
|
3209
|
-
error: "Failed to parse design output as JSON",
|
|
3210
|
-
rawOutput: rawText
|
|
3211
|
-
});
|
|
3212
|
-
}
|
|
3213
|
-
const usage = {
|
|
3214
|
-
inputTokens: response.usage?.promptTokens || 0,
|
|
3215
|
-
outputTokens: response.usage?.completionTokens || 0,
|
|
3216
|
-
totalTokens: response.usage?.totalTokens || 0
|
|
3217
|
-
};
|
|
3218
|
-
designCache.set(fingerprint, {
|
|
3219
|
-
effects,
|
|
3220
|
-
timestamp: Date.now(),
|
|
3221
|
-
usage
|
|
3222
|
-
});
|
|
3223
|
-
emitEvent(transitionId, "tool_result", {
|
|
3224
|
-
tool: "llm_design_transition",
|
|
3225
|
-
result: { fingerprint, effectCount: effects.length, usage },
|
|
3226
|
-
success: true
|
|
3227
|
-
});
|
|
3228
|
-
emitEvent(transitionId, "message", {
|
|
3229
|
-
content: `Designed ${effects.length} effect(s) for ${transitionId} (${usage.totalTokens} tokens)`,
|
|
3230
|
-
role: "assistant",
|
|
3231
|
-
isComplete: true
|
|
3232
|
-
});
|
|
3233
|
-
return JSON.stringify({
|
|
3234
|
-
success: true,
|
|
3235
|
-
transitionId,
|
|
3236
|
-
effects,
|
|
3237
|
-
cached: false,
|
|
3238
|
-
usage,
|
|
3239
|
-
recommendedPatterns: recommendations.map((r) => r.pattern)
|
|
3240
|
-
});
|
|
3241
|
-
} catch (error) {
|
|
3242
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
3243
|
-
emitEvent(transitionId, "error", {
|
|
3244
|
-
error: errorMessage,
|
|
3245
|
-
code: "DESIGN_TRANSITION_ERROR"
|
|
3246
|
-
});
|
|
3247
|
-
return JSON.stringify({
|
|
3248
|
-
success: false,
|
|
3249
|
-
transitionId,
|
|
3250
|
-
error: errorMessage
|
|
3251
|
-
});
|
|
3252
|
-
}
|
|
3253
|
-
},
|
|
3254
|
-
{
|
|
3255
|
-
name: "design_transition",
|
|
3256
|
-
description: `Design rich render-ui effects for a single orbital transition.
|
|
3257
|
-
|
|
3258
|
-
Takes the transition context (from/to state, event, entity, domain) and produces
|
|
3259
|
-
polished render-ui effects using the full pattern catalog.
|
|
3260
|
-
|
|
3261
|
-
USE THIS TOOL WHEN:
|
|
3262
|
-
- Generating INIT transitions (always compose header + stats + content)
|
|
3263
|
-
- Generating CREATE/EDIT transitions (form with proper fields)
|
|
3264
|
-
- Generating VIEW transitions (detail with tabs for related entities)
|
|
3265
|
-
- Enhancing existing render-ui effects that are too basic
|
|
3266
|
-
|
|
3267
|
-
The tool uses a specialized design skill with pattern catalog, layout composition,
|
|
3268
|
-
and domain-aware pattern selection to produce rich UI.
|
|
3269
|
-
|
|
3270
|
-
RETURNS: { success, effects: [["render-ui", slot, config], ...], transitionId, usage }
|
|
3271
|
-
|
|
3272
|
-
The effects array contains ONLY render-ui tuples. Non-UI effects (persist, emit, set)
|
|
3273
|
-
are NOT included \u2014 you must preserve those from the original transition.
|
|
3274
|
-
|
|
3275
|
-
INTEGRATION: After calling this tool, use extract_chunk to get the orbital,
|
|
3276
|
-
replace the render-ui effects in the target transition (keep persist/emit/set effects),
|
|
3277
|
-
then apply_chunk to merge back into schema.json.`,
|
|
3278
|
-
schema: DesignTransitionSchema
|
|
3279
|
-
}
|
|
3280
|
-
);
|
|
3281
|
-
return {
|
|
3282
|
-
tool: designTransitionTool,
|
|
3283
|
-
setEventCallback
|
|
3284
|
-
};
|
|
3285
|
-
}
|
|
3286
3939
|
function createGitHubTools(config) {
|
|
3287
3940
|
const { token, owner = "", repo = "", workDir } = config;
|
|
3288
3941
|
const integrationConfig = {
|
|
@@ -3652,9 +4305,7 @@ function createAgentTools(workDir) {
|
|
|
3652
4305
|
// Domain tools (now use internal functions)
|
|
3653
4306
|
domainOrbitalTools: createDomainOrbitalTools({ workDir }),
|
|
3654
4307
|
// Chunking tools
|
|
3655
|
-
schemaChunking: createSchemaChunkingTools(workDir)
|
|
3656
|
-
// Design tool
|
|
3657
|
-
designTransition: createDesignTransitionTool()
|
|
4308
|
+
schemaChunking: createSchemaChunkingTools(workDir)
|
|
3658
4309
|
};
|
|
3659
4310
|
}
|
|
3660
4311
|
function getSchemaReference() {
|
|
@@ -4867,6 +5518,21 @@ function createLLMClient(provider, model, verbose) {
|
|
|
4867
5518
|
model: model || OPENAI_MODELS.GPT4O,
|
|
4868
5519
|
temperature
|
|
4869
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
|
+
});
|
|
4870
5536
|
case "anthropic":
|
|
4871
5537
|
default:
|
|
4872
5538
|
if (verbose)
|
|
@@ -4891,6 +5557,8 @@ async function createSkillAgent(options) {
|
|
|
4891
5557
|
threadId: providedThreadId,
|
|
4892
5558
|
provider = "anthropic",
|
|
4893
5559
|
model,
|
|
5560
|
+
subagentProvider = "anthropic",
|
|
5561
|
+
subagentModel = "claude-sonnet-4-20250514",
|
|
4894
5562
|
verbose = false,
|
|
4895
5563
|
skillLoader,
|
|
4896
5564
|
skillRefLoader
|
|
@@ -4987,20 +5655,24 @@ ${skillContents}`;
|
|
|
4987
5655
|
const finishTaskTool = createFinishTaskTool(workDir);
|
|
4988
5656
|
const validateSchemaTool = createValidateSchemaTool(workDir);
|
|
4989
5657
|
const ORBITAL_SKILLS = ["kflow-orbitals", "kflow-orbital-games", "kflow-orbital-fixing"];
|
|
5658
|
+
const ORBITAL_BATCH_SKILLS = ["kflow-orbitals-batch"];
|
|
4990
5659
|
const LEAN_SKILLS = ["kflow-lean-orbitals", "kflow-lean-fixing"];
|
|
4991
|
-
const DESIGN_SKILLS = ["kflow-design", "kflow-lean-design"];
|
|
4992
5660
|
const isOrbitalSkill = primarySkill.name === "kflow-orbitals";
|
|
5661
|
+
const isOrbitalBatchSkill = ORBITAL_BATCH_SKILLS.includes(primarySkill.name);
|
|
4993
5662
|
const isLeanSkill = LEAN_SKILLS.includes(primarySkill.name);
|
|
4994
|
-
const
|
|
4995
|
-
const needsChunkingTools = ORBITAL_SKILLS.includes(primarySkill.name) || isDesignSkill;
|
|
5663
|
+
const needsChunkingTools = ORBITAL_SKILLS.includes(primarySkill.name);
|
|
4996
5664
|
let orbitalTool;
|
|
4997
5665
|
let setOrbitalEventCallback;
|
|
4998
5666
|
let setOrbitalCompleteCallback;
|
|
5667
|
+
let orbitalBatchTool;
|
|
5668
|
+
let setBatchEventCallback;
|
|
4999
5669
|
let domainOrbitalTools;
|
|
5000
5670
|
const chunkingTools = needsChunkingTools ? createSchemaChunkingTools(workDir) : null;
|
|
5001
5671
|
if (isOrbitalSkill) {
|
|
5002
5672
|
const orbitalResult = createOrbitalSubagentTool({
|
|
5003
|
-
requirements: options.requirements
|
|
5673
|
+
requirements: options.requirements,
|
|
5674
|
+
provider: subagentProvider,
|
|
5675
|
+
model: subagentModel
|
|
5004
5676
|
});
|
|
5005
5677
|
orbitalTool = orbitalResult.tool;
|
|
5006
5678
|
setOrbitalEventCallback = orbitalResult.setEventCallback;
|
|
@@ -5012,16 +5684,32 @@ ${skillContents}`;
|
|
|
5012
5684
|
console.log(`[SkillAgent] Orbital tools enabled for kflow-orbitals skill`);
|
|
5013
5685
|
}
|
|
5014
5686
|
}
|
|
5015
|
-
if (
|
|
5016
|
-
|
|
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
|
+
}
|
|
5017
5700
|
if (verbose) {
|
|
5018
|
-
console.log(`[SkillAgent]
|
|
5701
|
+
console.log(`[SkillAgent] Batch orbital tools enabled for kflow-orbitals-batch skill`);
|
|
5019
5702
|
}
|
|
5020
5703
|
}
|
|
5021
|
-
|
|
5022
|
-
|
|
5023
|
-
|
|
5024
|
-
|
|
5704
|
+
if (isLeanSkill) {
|
|
5705
|
+
domainOrbitalTools = createDomainOrbitalTools({
|
|
5706
|
+
workDir,
|
|
5707
|
+
provider: subagentProvider,
|
|
5708
|
+
model: subagentModel
|
|
5709
|
+
});
|
|
5710
|
+
if (verbose) {
|
|
5711
|
+
console.log(`[SkillAgent] Domain orbital tools enabled for ${primarySkill.name} skill (provider: ${subagentProvider})`);
|
|
5712
|
+
}
|
|
5025
5713
|
}
|
|
5026
5714
|
const githubTools = options.githubConfig ? createGitHubToolsArray({
|
|
5027
5715
|
token: options.githubConfig.token,
|
|
@@ -5035,8 +5723,9 @@ ${skillContents}`;
|
|
|
5035
5723
|
const tools = [
|
|
5036
5724
|
executeTool,
|
|
5037
5725
|
finishTaskTool,
|
|
5038
|
-
...isOrbitalSkill ? [] : [validateSchemaTool],
|
|
5726
|
+
...isOrbitalSkill || isOrbitalBatchSkill ? [] : [validateSchemaTool],
|
|
5039
5727
|
...orbitalTool ? [orbitalTool] : [],
|
|
5728
|
+
...orbitalBatchTool ? [orbitalBatchTool] : [],
|
|
5040
5729
|
...domainOrbitalTools ? [
|
|
5041
5730
|
domainOrbitalTools.generateOrbitalDomain,
|
|
5042
5731
|
domainOrbitalTools.constructCombinedDomain
|
|
@@ -5046,7 +5735,6 @@ ${skillContents}`;
|
|
|
5046
5735
|
chunkingTools.extractChunk,
|
|
5047
5736
|
chunkingTools.applyChunk
|
|
5048
5737
|
] : [],
|
|
5049
|
-
...designTool ? [designTool.tool] : [],
|
|
5050
5738
|
...githubTools || []
|
|
5051
5739
|
];
|
|
5052
5740
|
const checkpointer = sessions.getCheckpointer(threadId);
|