@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/agent/index.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { AgentDomainCategorySchema, isOrbitalDefinition, isEntityReference, getTraitName } from '@almadar/core/types';
|
|
2
|
+
import { getFullOrbitalPrompt, getRequirementsTraitPrompt, getKeyBehaviorsReference, getSExprQuickRef, getCommonErrorsSection, getArchitectureSection } from '@almadar/skills';
|
|
3
|
+
import { tool } from '@langchain/core/tools';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { LLMClient, ANTHROPIC_MODELS, createAnthropicClient, OPENROUTER_MODELS, createOpenRouterClient, KIMI_MODELS, createKimiClient, OPENAI_MODELS, createOpenAIClient, DEEPSEEK_MODELS, createDeepSeekClient } from '@almadar/llm';
|
|
2
6
|
import { FilesystemBackend, createDeepAgent } from 'deepagents';
|
|
3
7
|
import { MemorySaver } from '@langchain/langgraph';
|
|
4
8
|
export { Command } from '@langchain/langgraph';
|
|
5
9
|
import { v4 } from 'uuid';
|
|
6
|
-
import { ANTHROPIC_MODELS, createAnthropicClient, OPENAI_MODELS, createOpenAIClient, DEEPSEEK_MODELS, createDeepSeekClient, LLMClient } from '@almadar/llm';
|
|
7
|
-
import { tool } from '@langchain/core/tools';
|
|
8
|
-
import { z } from 'zod';
|
|
9
10
|
import { exec, spawn } from 'child_process';
|
|
10
11
|
import * as path from 'path';
|
|
11
12
|
import { promisify } from 'util';
|
|
@@ -13,8 +14,6 @@ import * as fs4 from 'fs/promises';
|
|
|
13
14
|
import * as domain_language_star from '@almadar/core/domain-language';
|
|
14
15
|
import * as fs3 from 'fs';
|
|
15
16
|
import crypto, { randomUUID } from 'crypto';
|
|
16
|
-
import { getFullOrbitalPrompt, generateKflowDesignSkill, getRequirementsTraitPrompt, getKeyBehaviorsReference, getSExprQuickRef, getCommonErrorsSection, getArchitectureSection } from '@almadar/skills';
|
|
17
|
-
import { formatRecommendationsForPrompt, buildRecommendationContext, recommendPatterns } from '@almadar/patterns';
|
|
18
17
|
import { GitHubIntegration } from '@almadar/integrations';
|
|
19
18
|
import { BaseCheckpointSaver } from '@langchain/langgraph-checkpoint';
|
|
20
19
|
|
|
@@ -309,6 +308,855 @@ var init_cache = __esm({
|
|
|
309
308
|
init_prompt_assembler();
|
|
310
309
|
}
|
|
311
310
|
});
|
|
311
|
+
|
|
312
|
+
// src/orbitals/shared/constants.ts
|
|
313
|
+
var PROVIDER_CONCURRENCY_LIMITS, PROVIDER_BATCH_SIZES, BATCH_MAX_TOKENS;
|
|
314
|
+
var init_constants = __esm({
|
|
315
|
+
"src/orbitals/shared/constants.ts"() {
|
|
316
|
+
PROVIDER_CONCURRENCY_LIMITS = {
|
|
317
|
+
anthropic: 3,
|
|
318
|
+
openai: 5,
|
|
319
|
+
deepseek: 3,
|
|
320
|
+
kimi: 3,
|
|
321
|
+
openrouter: 5
|
|
322
|
+
};
|
|
323
|
+
PROVIDER_BATCH_SIZES = {
|
|
324
|
+
anthropic: 3,
|
|
325
|
+
// Anthropic works well with 3 orbitals per call
|
|
326
|
+
openai: 5,
|
|
327
|
+
// OpenAI can handle more
|
|
328
|
+
deepseek: 3,
|
|
329
|
+
// Conservative for DeepSeek
|
|
330
|
+
kimi: 3,
|
|
331
|
+
// Conservative for Kimi
|
|
332
|
+
openrouter: 5
|
|
333
|
+
// OpenRouter proxies multiple providers
|
|
334
|
+
};
|
|
335
|
+
BATCH_MAX_TOKENS = 12e3;
|
|
336
|
+
}
|
|
337
|
+
});
|
|
338
|
+
function getEntityName2(entity) {
|
|
339
|
+
if (isEntityReference(entity)) {
|
|
340
|
+
return entity.replace(".entity", "");
|
|
341
|
+
}
|
|
342
|
+
return entity.name;
|
|
343
|
+
}
|
|
344
|
+
function getInlineEntity3(entity) {
|
|
345
|
+
if (isEntityReference(entity)) {
|
|
346
|
+
return null;
|
|
347
|
+
}
|
|
348
|
+
return entity;
|
|
349
|
+
}
|
|
350
|
+
function getFieldNames(entity) {
|
|
351
|
+
const inlineEntity = getInlineEntity3(entity);
|
|
352
|
+
if (!inlineEntity?.fields?.length) {
|
|
353
|
+
return "N/A";
|
|
354
|
+
}
|
|
355
|
+
return inlineEntity.fields.map((f) => f.name).join(", ");
|
|
356
|
+
}
|
|
357
|
+
function createLog(level, message, data) {
|
|
358
|
+
return {
|
|
359
|
+
timestamp: Date.now(),
|
|
360
|
+
level,
|
|
361
|
+
message,
|
|
362
|
+
data
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
function buildContextSection2(orbital) {
|
|
366
|
+
const parts = [];
|
|
367
|
+
if (orbital.domainContext) {
|
|
368
|
+
const ctx = orbital.domainContext;
|
|
369
|
+
parts.push(`DomainContext: category=${ctx.category || "business"}`);
|
|
370
|
+
if (ctx.vocabulary) {
|
|
371
|
+
parts.push(`Vocabulary: ${JSON.stringify(ctx.vocabulary)}`);
|
|
372
|
+
}
|
|
373
|
+
if (ctx.requestFragment) {
|
|
374
|
+
parts.push(`RequestFragment: "${ctx.requestFragment}"`);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
if (orbital.design) {
|
|
378
|
+
const d = orbital.design;
|
|
379
|
+
if (d.style) parts.push(`Style: ${d.style}`);
|
|
380
|
+
if (d.uxHints) {
|
|
381
|
+
const hints = d.uxHints;
|
|
382
|
+
if (hints.flowPattern) parts.push(`FlowPattern: ${hints.flowPattern}`);
|
|
383
|
+
if (hints.listPattern) parts.push(`ListPattern: ${hints.listPattern}`);
|
|
384
|
+
if (hints.formPattern) parts.push(`FormPattern: ${hints.formPattern}`);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
return parts.length > 0 ? `Context: ${parts.join(", ")}
|
|
388
|
+
` : "";
|
|
389
|
+
}
|
|
390
|
+
function buildConnectivitySection(orbital) {
|
|
391
|
+
const parts = [];
|
|
392
|
+
if (orbital.emits?.length) {
|
|
393
|
+
parts.push(`Emits: ${orbital.emits.join(", ")}`);
|
|
394
|
+
}
|
|
395
|
+
if (orbital.listens?.length) {
|
|
396
|
+
parts.push(`Listens: ${orbital.listens.map((l) => `${l.event}\u2192${l.triggers}`).join(", ")}`);
|
|
397
|
+
}
|
|
398
|
+
return parts.join("\n");
|
|
399
|
+
}
|
|
400
|
+
function chunkArray(array, size) {
|
|
401
|
+
const chunks = [];
|
|
402
|
+
for (let i = 0; i < array.length; i += size) {
|
|
403
|
+
chunks.push(array.slice(i, i + size));
|
|
404
|
+
}
|
|
405
|
+
return chunks;
|
|
406
|
+
}
|
|
407
|
+
function getErrorMessage(error) {
|
|
408
|
+
if (error instanceof Error) {
|
|
409
|
+
return error.message;
|
|
410
|
+
}
|
|
411
|
+
return String(error);
|
|
412
|
+
}
|
|
413
|
+
var init_utils = __esm({
|
|
414
|
+
"src/orbitals/shared/utils.ts"() {
|
|
415
|
+
}
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
// src/orbitals/shared/index.ts
|
|
419
|
+
var init_shared = __esm({
|
|
420
|
+
"src/orbitals/shared/index.ts"() {
|
|
421
|
+
init_constants();
|
|
422
|
+
init_utils();
|
|
423
|
+
}
|
|
424
|
+
});
|
|
425
|
+
function extractSharedContext(orbitals) {
|
|
426
|
+
const vocabulary = {};
|
|
427
|
+
const styles = /* @__PURE__ */ new Set();
|
|
428
|
+
const patterns = /* @__PURE__ */ new Set();
|
|
429
|
+
const relationships = [];
|
|
430
|
+
for (const orbital of orbitals) {
|
|
431
|
+
if (orbital.domainContext?.vocabulary) {
|
|
432
|
+
Object.assign(vocabulary, orbital.domainContext.vocabulary);
|
|
433
|
+
}
|
|
434
|
+
if (orbital.design?.style) {
|
|
435
|
+
styles.add(orbital.design.style);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
new Map(orbitals.map((o) => [o.name, o]));
|
|
439
|
+
for (const orbital of orbitals) {
|
|
440
|
+
if (orbital.emits) {
|
|
441
|
+
for (const event of orbital.emits) {
|
|
442
|
+
for (const other of orbitals) {
|
|
443
|
+
if (other === orbital) continue;
|
|
444
|
+
if (other.listens) {
|
|
445
|
+
const listener = other.listens.find((l) => l.event === event.event);
|
|
446
|
+
if (listener) {
|
|
447
|
+
relationships.push({
|
|
448
|
+
emitter: orbital.name,
|
|
449
|
+
event: event.event,
|
|
450
|
+
listener: other.name,
|
|
451
|
+
handler: listener.triggers
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
return {
|
|
460
|
+
domainVocabulary: Object.keys(vocabulary).length > 0 ? vocabulary : void 0,
|
|
461
|
+
designStyle: styles.size === 1 ? Array.from(styles)[0] : void 0,
|
|
462
|
+
commonPatterns: patterns.size > 0 ? Array.from(patterns) : void 0,
|
|
463
|
+
eventRelationships: relationships.length > 0 ? relationships : void 0
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
function assembleBatchPrompt(orbitals, options = {}) {
|
|
467
|
+
const {
|
|
468
|
+
baseSystemPrompt = getFullOrbitalPrompt(),
|
|
469
|
+
includeConnectivity = true
|
|
470
|
+
} = options;
|
|
471
|
+
if (orbitals.length === 0) {
|
|
472
|
+
throw new Error("Cannot assemble batch prompt for empty orbitals array");
|
|
473
|
+
}
|
|
474
|
+
const sharedContext = extractSharedContext(orbitals);
|
|
475
|
+
const batchHeader = buildBatchHeader(orbitals, sharedContext);
|
|
476
|
+
const orbitalSections = orbitals.map(
|
|
477
|
+
(orbital, index) => buildOrbitalSection(orbital, index + 1, orbitals.length, includeConnectivity)
|
|
478
|
+
);
|
|
479
|
+
const outputSection = buildOutputSection(orbitals);
|
|
480
|
+
const prompt = `${baseSystemPrompt}
|
|
481
|
+
|
|
482
|
+
${"=".repeat(60)}
|
|
483
|
+
BATCH GENERATION: ${orbitals.length} ORBITALS
|
|
484
|
+
${"=".repeat(60)}
|
|
485
|
+
|
|
486
|
+
${batchHeader}
|
|
487
|
+
|
|
488
|
+
${orbitalSections.join("\n\n")}
|
|
489
|
+
|
|
490
|
+
${outputSection}`;
|
|
491
|
+
const fingerprint = generateBatchFingerprint(orbitals);
|
|
492
|
+
return {
|
|
493
|
+
prompt,
|
|
494
|
+
fingerprint,
|
|
495
|
+
usedCachedTemplate: false,
|
|
496
|
+
// Batch doesn't use templates yet
|
|
497
|
+
orbitalCount: orbitals.length,
|
|
498
|
+
orbitalNames: orbitals.map((o) => o.name)
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
function buildBatchHeader(orbitals, sharedContext) {
|
|
502
|
+
const lines = [
|
|
503
|
+
`## Batch Overview`,
|
|
504
|
+
`- Total Orbitals: ${orbitals.length}`,
|
|
505
|
+
`- Orbitals: ${orbitals.map((o) => o.name).join(", ")}`
|
|
506
|
+
];
|
|
507
|
+
if (sharedContext.designStyle) {
|
|
508
|
+
lines.push(`- Design Style: ${sharedContext.designStyle}`);
|
|
509
|
+
}
|
|
510
|
+
if (sharedContext.commonPatterns?.length) {
|
|
511
|
+
lines.push(`- Common Patterns: ${sharedContext.commonPatterns.join(", ")}`);
|
|
512
|
+
}
|
|
513
|
+
if (sharedContext.domainVocabulary && Object.keys(sharedContext.domainVocabulary).length > 0) {
|
|
514
|
+
lines.push(`
|
|
515
|
+
## Shared Domain Vocabulary`);
|
|
516
|
+
for (const [term, definition] of Object.entries(sharedContext.domainVocabulary)) {
|
|
517
|
+
lines.push(`- ${term}: ${definition}`);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
if (sharedContext.eventRelationships?.length) {
|
|
521
|
+
lines.push(`
|
|
522
|
+
## Cross-Orbital Event Relationships`);
|
|
523
|
+
for (const rel of sharedContext.eventRelationships) {
|
|
524
|
+
lines.push(`- ${rel.emitter} emits "${rel.event}" \u2192 ${rel.listener} handles with "${rel.handler}"`);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
return lines.join("\n");
|
|
528
|
+
}
|
|
529
|
+
function buildOrbitalSection(orbital, index, total, includeConnectivity) {
|
|
530
|
+
const entityName = getEntityName2(orbital.entity);
|
|
531
|
+
const fieldNames = getFieldNames(orbital.entity);
|
|
532
|
+
const contextSection = buildContextSection2(orbital);
|
|
533
|
+
const connectivitySection = includeConnectivity ? buildConnectivitySection(orbital) : "";
|
|
534
|
+
return `---
|
|
535
|
+
## ORBITAL ${index}/${total}: ${orbital.name}
|
|
536
|
+
|
|
537
|
+
**Entity**: ${entityName}
|
|
538
|
+
**Persistence**: ${orbital.entity.persistence || "persistent"}
|
|
539
|
+
**Fields**: ${fieldNames}
|
|
540
|
+
**Traits**: ${orbital.traits.map((t) => typeof t === "string" ? t : "ref" in t ? t.ref : t.name).join(", ")}
|
|
541
|
+
${contextSection}${connectivitySection ? `**Connectivity**:
|
|
542
|
+
${connectivitySection}
|
|
543
|
+
` : ""}
|
|
544
|
+
Generate a complete FullOrbitalUnit for ${orbital.name} with:
|
|
545
|
+
- Full field definitions with types and validation
|
|
546
|
+
- Trait state machines with transitions and effects
|
|
547
|
+
- Business rule validation using "guard" S-expression on SAVE transitions
|
|
548
|
+
- Pages with trait references
|
|
549
|
+
- domainContext with category, vocabulary, and requestFragment
|
|
550
|
+
- design with style and uxHints (flowPattern, listPattern, formPattern)
|
|
551
|
+
${orbital.emits?.length ? "- PRESERVE emits: " + orbital.emits.map((e) => e.event).join(", ") : ""}
|
|
552
|
+
${orbital.listens?.length ? "- PRESERVE listens: " + orbital.listens.map((l) => l.event).join(", ") : ""}`;
|
|
553
|
+
}
|
|
554
|
+
function buildOutputSection(orbitals) {
|
|
555
|
+
return `---
|
|
556
|
+
## OUTPUT FORMAT
|
|
557
|
+
|
|
558
|
+
Return a JSON object with this exact structure:
|
|
559
|
+
|
|
560
|
+
\`\`\`json
|
|
561
|
+
{
|
|
562
|
+
"orbitals": [
|
|
563
|
+
${orbitals.map((o, i) => ` {
|
|
564
|
+
"name": "${o.name}",
|
|
565
|
+
// ... complete FullOrbitalUnit for ${o.name}
|
|
566
|
+
}${i < orbitals.length - 1 ? "," : ""}`).join("\n")}
|
|
567
|
+
]
|
|
568
|
+
}
|
|
569
|
+
\`\`\`
|
|
570
|
+
|
|
571
|
+
**CRITICAL RULES:**
|
|
572
|
+
1. Return a SINGLE JSON object with an "orbitals" array
|
|
573
|
+
2. Each element in the array is a complete FullOrbitalUnit
|
|
574
|
+
3. Maintain the order: ${orbitals.map((o) => o.name).join(", ")}
|
|
575
|
+
4. PRESERVE all emits/listens as specified in each orbital section
|
|
576
|
+
5. Use shared domain vocabulary consistently across all orbitals
|
|
577
|
+
6. Ensure cross-orbital event wiring is maintained
|
|
578
|
+
`;
|
|
579
|
+
}
|
|
580
|
+
function generateBatchFingerprint(orbitals) {
|
|
581
|
+
const fingerprints = orbitals.map((o) => computeOrbitalFingerprint(o));
|
|
582
|
+
const combined = fingerprints.sort().join("|");
|
|
583
|
+
let hash = 0;
|
|
584
|
+
for (let i = 0; i < combined.length; i++) {
|
|
585
|
+
const char = combined.charCodeAt(i);
|
|
586
|
+
hash = (hash << 5) - hash + char;
|
|
587
|
+
hash = hash & hash;
|
|
588
|
+
}
|
|
589
|
+
return `batch:${orbitals.length}:${Math.abs(hash).toString(16).slice(0, 8)}`;
|
|
590
|
+
}
|
|
591
|
+
function splitIntoBatches(orbitals, options = {}) {
|
|
592
|
+
const {
|
|
593
|
+
maxBatchSize = 3,
|
|
594
|
+
preserveRelationships = true
|
|
595
|
+
} = options;
|
|
596
|
+
if (!preserveRelationships) {
|
|
597
|
+
return chunkArray(orbitals, maxBatchSize);
|
|
598
|
+
}
|
|
599
|
+
const clusters = groupByRelationships(orbitals);
|
|
600
|
+
const batches = [];
|
|
601
|
+
for (const cluster of clusters) {
|
|
602
|
+
if (cluster.length <= maxBatchSize) {
|
|
603
|
+
batches.push(cluster);
|
|
604
|
+
} else {
|
|
605
|
+
batches.push(...chunkArray(cluster, maxBatchSize));
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
return batches;
|
|
609
|
+
}
|
|
610
|
+
function groupByRelationships(orbitals) {
|
|
611
|
+
const visited = /* @__PURE__ */ new Set();
|
|
612
|
+
const clusters = [];
|
|
613
|
+
const adjacency = /* @__PURE__ */ new Map();
|
|
614
|
+
for (const orbital of orbitals) {
|
|
615
|
+
if (!adjacency.has(orbital.name)) {
|
|
616
|
+
adjacency.set(orbital.name, /* @__PURE__ */ new Set());
|
|
617
|
+
}
|
|
618
|
+
if (orbital.emits) {
|
|
619
|
+
for (const event of orbital.emits) {
|
|
620
|
+
for (const other of orbitals) {
|
|
621
|
+
if (other === orbital) continue;
|
|
622
|
+
if (other.listens?.some((l) => l.event === event.event)) {
|
|
623
|
+
adjacency.get(orbital.name)?.add(other.name);
|
|
624
|
+
if (!adjacency.has(other.name)) {
|
|
625
|
+
adjacency.set(other.name, /* @__PURE__ */ new Set());
|
|
626
|
+
}
|
|
627
|
+
adjacency.get(other.name)?.add(orbital.name);
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
function dfs(orbital, cluster) {
|
|
634
|
+
visited.add(orbital.name);
|
|
635
|
+
cluster.push(orbital);
|
|
636
|
+
const neighbors = adjacency.get(orbital.name) || /* @__PURE__ */ new Set();
|
|
637
|
+
for (const neighborName of neighbors) {
|
|
638
|
+
if (!visited.has(neighborName)) {
|
|
639
|
+
const neighbor = orbitals.find((o) => o.name === neighborName);
|
|
640
|
+
if (neighbor) {
|
|
641
|
+
dfs(neighbor, cluster);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
for (const orbital of orbitals) {
|
|
647
|
+
if (!visited.has(orbital.name)) {
|
|
648
|
+
const cluster = [];
|
|
649
|
+
dfs(orbital, cluster);
|
|
650
|
+
clusters.push(cluster);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
return clusters;
|
|
654
|
+
}
|
|
655
|
+
function estimateBatchTokens(orbitals) {
|
|
656
|
+
const baseTokens = 2e3;
|
|
657
|
+
const perOrbitalTokens = 800;
|
|
658
|
+
return baseTokens + orbitals.length * perOrbitalTokens;
|
|
659
|
+
}
|
|
660
|
+
function willBatchFit(orbitals, maxTokens = 12e3) {
|
|
661
|
+
const estimated = estimateBatchTokens(orbitals);
|
|
662
|
+
return estimated < maxTokens * 0.5;
|
|
663
|
+
}
|
|
664
|
+
var init_prompt_assembler2 = __esm({
|
|
665
|
+
"src/orbitals/batch/prompt-assembler.ts"() {
|
|
666
|
+
init_cache();
|
|
667
|
+
init_shared();
|
|
668
|
+
}
|
|
669
|
+
});
|
|
670
|
+
|
|
671
|
+
// src/orbitals/batch/concurrency.ts
|
|
672
|
+
function createConcurrencyController(maxConcurrency) {
|
|
673
|
+
let activeCount = 0;
|
|
674
|
+
const queue = [];
|
|
675
|
+
return {
|
|
676
|
+
async acquire() {
|
|
677
|
+
if (activeCount < maxConcurrency) {
|
|
678
|
+
activeCount++;
|
|
679
|
+
return Promise.resolve();
|
|
680
|
+
}
|
|
681
|
+
return new Promise((resolve2) => {
|
|
682
|
+
queue.push(() => {
|
|
683
|
+
activeCount++;
|
|
684
|
+
resolve2();
|
|
685
|
+
});
|
|
686
|
+
});
|
|
687
|
+
},
|
|
688
|
+
release() {
|
|
689
|
+
activeCount = Math.max(0, activeCount - 1);
|
|
690
|
+
const next = queue.shift();
|
|
691
|
+
if (next) {
|
|
692
|
+
next();
|
|
693
|
+
}
|
|
694
|
+
},
|
|
695
|
+
get activeCount() {
|
|
696
|
+
return activeCount;
|
|
697
|
+
},
|
|
698
|
+
get waitingCount() {
|
|
699
|
+
return queue.length;
|
|
700
|
+
}
|
|
701
|
+
};
|
|
702
|
+
}
|
|
703
|
+
async function runWithConcurrency(tasks, options) {
|
|
704
|
+
const { concurrency, onProgress } = options;
|
|
705
|
+
const controller = createConcurrencyController(concurrency);
|
|
706
|
+
const results = [];
|
|
707
|
+
let completed = 0;
|
|
708
|
+
await Promise.all(
|
|
709
|
+
tasks.map(async (task, index) => {
|
|
710
|
+
await controller.acquire();
|
|
711
|
+
try {
|
|
712
|
+
results[index] = await task();
|
|
713
|
+
completed++;
|
|
714
|
+
onProgress?.(completed, tasks.length);
|
|
715
|
+
} finally {
|
|
716
|
+
controller.release();
|
|
717
|
+
}
|
|
718
|
+
})
|
|
719
|
+
);
|
|
720
|
+
return results;
|
|
721
|
+
}
|
|
722
|
+
async function asyncMapWithConcurrency2(items, mapper, concurrency) {
|
|
723
|
+
return runWithConcurrency(
|
|
724
|
+
items.map((item, index) => () => mapper(item, index)),
|
|
725
|
+
{ concurrency }
|
|
726
|
+
);
|
|
727
|
+
}
|
|
728
|
+
var init_concurrency = __esm({
|
|
729
|
+
"src/orbitals/batch/concurrency.ts"() {
|
|
730
|
+
}
|
|
731
|
+
});
|
|
732
|
+
|
|
733
|
+
// src/orbitals/batch/batch-generator.ts
|
|
734
|
+
async function generateOrbitalsBatch(client, orbitals, options = {}) {
|
|
735
|
+
const startTime = Date.now();
|
|
736
|
+
const aggregateLogs = [];
|
|
737
|
+
const provider = client.getProvider();
|
|
738
|
+
const mode = options.mode || "single-call";
|
|
739
|
+
const maxConcurrency = options.concurrency ?? PROVIDER_CONCURRENCY_LIMITS[provider];
|
|
740
|
+
const maxBatchSize = options.batchSize ?? PROVIDER_BATCH_SIZES[provider];
|
|
741
|
+
console.log(`[BatchGenerator] Starting batch generation: ${orbitals.length} orbitals, mode=${mode}, concurrency=${maxConcurrency}`);
|
|
742
|
+
aggregateLogs.push(createLog("info", `Starting batch generation`, {
|
|
743
|
+
totalOrbitals: orbitals.length,
|
|
744
|
+
mode,
|
|
745
|
+
provider,
|
|
746
|
+
maxConcurrency,
|
|
747
|
+
maxBatchSize
|
|
748
|
+
}));
|
|
749
|
+
const batches = splitIntoBatches(orbitals, {
|
|
750
|
+
maxBatchSize,
|
|
751
|
+
preserveRelationships: options.preserveRelationships ?? true
|
|
752
|
+
});
|
|
753
|
+
console.log(`[BatchGenerator] Split into ${batches.length} batches: [${batches.map((b) => b.length).join(", ")}]`);
|
|
754
|
+
aggregateLogs.push(createLog("info", `Split into ${batches.length} batches`, {
|
|
755
|
+
batchSizes: batches.map((b) => b.length)
|
|
756
|
+
}));
|
|
757
|
+
options.onBatchProgress?.({
|
|
758
|
+
type: "batch_start",
|
|
759
|
+
batchIndex: 0,
|
|
760
|
+
totalBatches: batches.length,
|
|
761
|
+
completedOrbitals: 0,
|
|
762
|
+
totalOrbitals: orbitals.length
|
|
763
|
+
});
|
|
764
|
+
let batchResults;
|
|
765
|
+
if (mode === "parallel-individual") {
|
|
766
|
+
batchResults = await generateParallelIndividual(client, orbitals, {
|
|
767
|
+
...options,
|
|
768
|
+
concurrency: maxConcurrency,
|
|
769
|
+
onBatchProgress: options.onBatchProgress
|
|
770
|
+
});
|
|
771
|
+
} else if (mode === "single-call") {
|
|
772
|
+
batchResults = await generateSingleCallBatches(client, batches, {
|
|
773
|
+
...options,
|
|
774
|
+
concurrency: maxConcurrency,
|
|
775
|
+
onBatchProgress: options.onBatchProgress
|
|
776
|
+
});
|
|
777
|
+
} else {
|
|
778
|
+
batchResults = await generateAdaptive(client, orbitals, batches, {
|
|
779
|
+
...options,
|
|
780
|
+
concurrency: maxConcurrency,
|
|
781
|
+
maxBatchSize,
|
|
782
|
+
onBatchProgress: options.onBatchProgress
|
|
783
|
+
});
|
|
784
|
+
}
|
|
785
|
+
const totalDurationMs = Date.now() - startTime;
|
|
786
|
+
const allResults = batchResults.flatMap((b) => b.results);
|
|
787
|
+
const successful = allResults.filter((r) => r.success).length;
|
|
788
|
+
const failed = allResults.length - successful;
|
|
789
|
+
const totalTokens = batchResults.reduce(
|
|
790
|
+
(sum, b) => sum + (b.usage?.totalTokens ?? 0),
|
|
791
|
+
0
|
|
792
|
+
);
|
|
793
|
+
console.log(`[BatchGenerator] Complete: ${successful}/${allResults.length} successful, ${totalTokens} tokens, ${totalDurationMs}ms`);
|
|
794
|
+
aggregateLogs.push(createLog("info", `Batch generation completed`, {
|
|
795
|
+
totalDurationMs,
|
|
796
|
+
successful,
|
|
797
|
+
failed,
|
|
798
|
+
totalTokens,
|
|
799
|
+
totalBatches: batches.length
|
|
800
|
+
}));
|
|
801
|
+
options.onBatchProgress?.({
|
|
802
|
+
type: "batch_complete",
|
|
803
|
+
batchIndex: batches.length - 1,
|
|
804
|
+
totalBatches: batches.length,
|
|
805
|
+
completedOrbitals: successful,
|
|
806
|
+
totalOrbitals: orbitals.length
|
|
807
|
+
});
|
|
808
|
+
return {
|
|
809
|
+
results: allResults.map((r) => ({
|
|
810
|
+
orbital: r.orbital,
|
|
811
|
+
fingerprint: "",
|
|
812
|
+
// TODO: compute from orbital
|
|
813
|
+
usedTemplate: false,
|
|
814
|
+
usage: void 0,
|
|
815
|
+
validation: r.success ? { valid: true, errorCount: 0, warningCount: 0 } : { valid: false, errorCount: 1, warningCount: 0 },
|
|
816
|
+
logs: []
|
|
817
|
+
})),
|
|
818
|
+
totalDurationMs,
|
|
819
|
+
aggregateLogs,
|
|
820
|
+
summary: {
|
|
821
|
+
total: allResults.length,
|
|
822
|
+
successful,
|
|
823
|
+
failed,
|
|
824
|
+
totalTokens
|
|
825
|
+
},
|
|
826
|
+
batchResults,
|
|
827
|
+
totalBatches: batches.length
|
|
828
|
+
};
|
|
829
|
+
}
|
|
830
|
+
async function generateSingleCallBatches(client, batches, options) {
|
|
831
|
+
let completedOrbitals = 0;
|
|
832
|
+
const totalOrbitals = batches.reduce((sum, b) => sum + b.length, 0);
|
|
833
|
+
return asyncMapWithConcurrency2(
|
|
834
|
+
batches,
|
|
835
|
+
async (batch, batchIndex) => {
|
|
836
|
+
return generateSingleBatch(client, batch, batchIndex, {
|
|
837
|
+
...options,
|
|
838
|
+
onProgress: (completedInBatch) => {
|
|
839
|
+
const newCompleted = completedOrbitals + completedInBatch;
|
|
840
|
+
options.onBatchProgress?.({
|
|
841
|
+
type: "orbital_complete",
|
|
842
|
+
batchIndex,
|
|
843
|
+
totalBatches: batches.length,
|
|
844
|
+
completedOrbitals: newCompleted,
|
|
845
|
+
totalOrbitals
|
|
846
|
+
});
|
|
847
|
+
completedOrbitals = newCompleted;
|
|
848
|
+
}
|
|
849
|
+
});
|
|
850
|
+
},
|
|
851
|
+
options.concurrency
|
|
852
|
+
);
|
|
853
|
+
}
|
|
854
|
+
async function generateParallelIndividual(client, orbitals, options) {
|
|
855
|
+
const batches = orbitals.map((o) => [o]);
|
|
856
|
+
return generateSingleCallBatches(client, batches, {
|
|
857
|
+
...options,
|
|
858
|
+
concurrency: options.concurrency
|
|
859
|
+
});
|
|
860
|
+
}
|
|
861
|
+
async function generateAdaptive(client, orbitals, batches, options) {
|
|
862
|
+
const allFit = batches.every((batch) => willBatchFit(batch, BATCH_MAX_TOKENS));
|
|
863
|
+
if (allFit) {
|
|
864
|
+
console.log(`[BatchGenerator] Adaptive: Using single-call batches (${batches.length} batches)`);
|
|
865
|
+
return generateSingleCallBatches(client, batches, options);
|
|
866
|
+
}
|
|
867
|
+
console.log(`[BatchGenerator] Adaptive: Using parallel-individual (batches too large)`);
|
|
868
|
+
return generateParallelIndividual(client, orbitals, options);
|
|
869
|
+
}
|
|
870
|
+
async function generateSingleBatch(client, orbitals, batchIndex, options) {
|
|
871
|
+
const batchStartTime = Date.now();
|
|
872
|
+
const logs = [];
|
|
873
|
+
console.log(`[BatchGenerator] Starting batch ${batchIndex + 1}: ${orbitals.map((o) => o.name).join(", ")}`);
|
|
874
|
+
logs.push(createLog("info", `Starting batch ${batchIndex + 1}`, {
|
|
875
|
+
orbitalCount: orbitals.length,
|
|
876
|
+
orbitals: orbitals.map((o) => o.name)
|
|
877
|
+
}));
|
|
878
|
+
try {
|
|
879
|
+
const batchPrompt = assembleBatchPrompt(orbitals);
|
|
880
|
+
console.log(`[BatchGenerator] Batch ${batchIndex + 1} prompt assembled: ${batchPrompt.prompt.length} chars`);
|
|
881
|
+
logs.push(createLog("info", `Batch prompt assembled`, {
|
|
882
|
+
promptLength: batchPrompt.prompt.length,
|
|
883
|
+
estimatedTokens: Math.ceil(batchPrompt.prompt.length / 4)
|
|
884
|
+
}));
|
|
885
|
+
const llmResult = await client.callWithMetadata({
|
|
886
|
+
systemPrompt: batchPrompt.prompt,
|
|
887
|
+
userPrompt: "Generate all orbitals in the batch. Return valid JSON matching the output format specified.",
|
|
888
|
+
maxTokens: BATCH_MAX_TOKENS,
|
|
889
|
+
skipSchemaValidation: true
|
|
890
|
+
});
|
|
891
|
+
logs.push(createLog("info", `LLM call completed`, {
|
|
892
|
+
promptTokens: llmResult.usage?.promptTokens,
|
|
893
|
+
completionTokens: llmResult.usage?.completionTokens
|
|
894
|
+
}));
|
|
895
|
+
const parsed = parseBatchResult(llmResult.data, orbitals);
|
|
896
|
+
console.log(`[BatchGenerator] Batch ${batchIndex + 1} parsed: ${parsed.filter((p) => p.success).length}/${parsed.length} successful`);
|
|
897
|
+
for (let i = 0; i < parsed.length; i++) {
|
|
898
|
+
options.onProgress?.(i + 1);
|
|
899
|
+
}
|
|
900
|
+
const durationMs = Date.now() - batchStartTime;
|
|
901
|
+
logs.push(createLog("info", `Batch ${batchIndex + 1} completed`, {
|
|
902
|
+
durationMs,
|
|
903
|
+
successful: parsed.filter((r) => r.success).length
|
|
904
|
+
}));
|
|
905
|
+
return {
|
|
906
|
+
orbitals,
|
|
907
|
+
results: parsed,
|
|
908
|
+
usage: llmResult.usage ?? void 0,
|
|
909
|
+
durationMs,
|
|
910
|
+
logs
|
|
911
|
+
};
|
|
912
|
+
} catch (error) {
|
|
913
|
+
const errorMessage = getErrorMessage(error);
|
|
914
|
+
console.error(`[BatchGenerator] Batch ${batchIndex + 1} FAILED: ${errorMessage}`);
|
|
915
|
+
logs.push(createLog("error", `Batch ${batchIndex + 1} failed`, {
|
|
916
|
+
error: errorMessage
|
|
917
|
+
}));
|
|
918
|
+
return {
|
|
919
|
+
orbitals,
|
|
920
|
+
results: orbitals.map((o) => ({
|
|
921
|
+
orbital: o,
|
|
922
|
+
success: false,
|
|
923
|
+
error: errorMessage
|
|
924
|
+
})),
|
|
925
|
+
durationMs: Date.now() - batchStartTime,
|
|
926
|
+
logs
|
|
927
|
+
};
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
function parseBatchResult(data, expectedOrbitals) {
|
|
931
|
+
if (!data || typeof data !== "object") {
|
|
932
|
+
return expectedOrbitals.map((o) => ({
|
|
933
|
+
orbital: o,
|
|
934
|
+
success: false,
|
|
935
|
+
error: "Invalid response: expected object"
|
|
936
|
+
}));
|
|
937
|
+
}
|
|
938
|
+
const obj = data;
|
|
939
|
+
if (!obj.orbitals || !Array.isArray(obj.orbitals)) {
|
|
940
|
+
return expectedOrbitals.map((o) => ({
|
|
941
|
+
orbital: o,
|
|
942
|
+
success: false,
|
|
943
|
+
error: "Invalid response: missing orbitals array"
|
|
944
|
+
}));
|
|
945
|
+
}
|
|
946
|
+
const results = obj.orbitals;
|
|
947
|
+
return expectedOrbitals.map((expected, index) => {
|
|
948
|
+
const result = results[index];
|
|
949
|
+
if (!result) {
|
|
950
|
+
return {
|
|
951
|
+
orbital: expected,
|
|
952
|
+
success: false,
|
|
953
|
+
error: `Missing result for orbital ${index + 1}`
|
|
954
|
+
};
|
|
955
|
+
}
|
|
956
|
+
if (!result.name) {
|
|
957
|
+
return {
|
|
958
|
+
orbital: expected,
|
|
959
|
+
success: false,
|
|
960
|
+
error: "Generated orbital missing name"
|
|
961
|
+
};
|
|
962
|
+
}
|
|
963
|
+
return {
|
|
964
|
+
orbital: result,
|
|
965
|
+
success: true
|
|
966
|
+
};
|
|
967
|
+
});
|
|
968
|
+
}
|
|
969
|
+
var init_batch_generator = __esm({
|
|
970
|
+
"src/orbitals/batch/batch-generator.ts"() {
|
|
971
|
+
init_shared();
|
|
972
|
+
init_prompt_assembler2();
|
|
973
|
+
init_concurrency();
|
|
974
|
+
}
|
|
975
|
+
});
|
|
976
|
+
|
|
977
|
+
// src/orbitals/batch/index.ts
|
|
978
|
+
var init_batch = __esm({
|
|
979
|
+
"src/orbitals/batch/index.ts"() {
|
|
980
|
+
init_batch_generator();
|
|
981
|
+
init_prompt_assembler2();
|
|
982
|
+
init_concurrency();
|
|
983
|
+
}
|
|
984
|
+
});
|
|
985
|
+
|
|
986
|
+
// src/tools/orbital-batch-subagent.ts
|
|
987
|
+
var orbital_batch_subagent_exports = {};
|
|
988
|
+
__export(orbital_batch_subagent_exports, {
|
|
989
|
+
createOrbitalBatchSubagentTool: () => createOrbitalBatchSubagentTool
|
|
990
|
+
});
|
|
991
|
+
function createOrbitalBatchSubagentTool(options = {}) {
|
|
992
|
+
let eventCallback = options.onSubagentEvent;
|
|
993
|
+
let completeCallback = options.onBatchComplete;
|
|
994
|
+
const requirements = options.requirements;
|
|
995
|
+
const workDir = options.workDir;
|
|
996
|
+
const setEventCallback = (callback) => {
|
|
997
|
+
eventCallback = callback;
|
|
998
|
+
};
|
|
999
|
+
const setBatchCompleteCallback = (callback) => {
|
|
1000
|
+
completeCallback = callback;
|
|
1001
|
+
};
|
|
1002
|
+
const emitEvent = (orbitalName, orbitalIndex, totalOrbitals, type, data) => {
|
|
1003
|
+
if (eventCallback) {
|
|
1004
|
+
eventCallback(orbitalName, orbitalIndex, totalOrbitals, {
|
|
1005
|
+
type,
|
|
1006
|
+
data,
|
|
1007
|
+
timestamp: Date.now()
|
|
1008
|
+
});
|
|
1009
|
+
}
|
|
1010
|
+
};
|
|
1011
|
+
const batchTool = tool(
|
|
1012
|
+
async ({ orbitals, options: batchOptions }) => {
|
|
1013
|
+
if (!orbitals || orbitals.length === 0) {
|
|
1014
|
+
return JSON.stringify({
|
|
1015
|
+
success: false,
|
|
1016
|
+
error: "No orbitals provided for batch generation.",
|
|
1017
|
+
orbitals: []
|
|
1018
|
+
});
|
|
1019
|
+
}
|
|
1020
|
+
console.log(`[OrbitalBatchSubagent] Starting batch generation for ${orbitals.length} orbitals`);
|
|
1021
|
+
try {
|
|
1022
|
+
emitEvent("batch", 0, 1, "message", {
|
|
1023
|
+
content: `Starting batch generation for ${orbitals.length} orbitals`,
|
|
1024
|
+
role: "assistant",
|
|
1025
|
+
isComplete: false
|
|
1026
|
+
});
|
|
1027
|
+
emitEvent("batch", 0, 1, "todo_update", {
|
|
1028
|
+
todos: orbitals.map((o, i) => ({
|
|
1029
|
+
id: `orbital-${i}`,
|
|
1030
|
+
task: `Generate ${o.name}`,
|
|
1031
|
+
status: "pending"
|
|
1032
|
+
}))
|
|
1033
|
+
});
|
|
1034
|
+
const client = new LLMClient({
|
|
1035
|
+
provider: options.provider || "anthropic",
|
|
1036
|
+
model: options.model || "claude-sonnet-4-20250514"
|
|
1037
|
+
});
|
|
1038
|
+
const generationOptions = {
|
|
1039
|
+
mode: batchOptions?.mode || "adaptive",
|
|
1040
|
+
batchSize: batchOptions?.batchSize,
|
|
1041
|
+
concurrency: batchOptions?.maxConcurrency ?? PROVIDER_CONCURRENCY_LIMITS[client.getProvider()],
|
|
1042
|
+
preserveRelationships: batchOptions?.preserveRelationships ?? true,
|
|
1043
|
+
requirements,
|
|
1044
|
+
onBatchProgress: (event) => {
|
|
1045
|
+
if (event.type === "orbital_complete" && event.orbitalName) {
|
|
1046
|
+
emitEvent(event.orbitalName || "batch", event.batchIndex, event.totalBatches, "todo_update", {
|
|
1047
|
+
todos: orbitals.map((o, i) => ({
|
|
1048
|
+
id: `orbital-${i}`,
|
|
1049
|
+
task: `Generate ${o.name}`,
|
|
1050
|
+
status: o.name === event.orbitalName ? "completed" : event.completedOrbitals > i ? "completed" : "pending"
|
|
1051
|
+
}))
|
|
1052
|
+
});
|
|
1053
|
+
}
|
|
1054
|
+
emitEvent(event.orbitalName || "batch", event.batchIndex, event.totalBatches, "generation_log", {
|
|
1055
|
+
level: "info",
|
|
1056
|
+
message: `Progress: ${event.completedOrbitals}/${event.totalOrbitals} orbitals complete`,
|
|
1057
|
+
data: {
|
|
1058
|
+
batchIndex: event.batchIndex,
|
|
1059
|
+
completedOrbitals: event.completedOrbitals,
|
|
1060
|
+
totalOrbitals: event.totalOrbitals
|
|
1061
|
+
}
|
|
1062
|
+
});
|
|
1063
|
+
}
|
|
1064
|
+
};
|
|
1065
|
+
emitEvent("batch", 0, 1, "tool_call", {
|
|
1066
|
+
tool: "generateOrbitalsBatch",
|
|
1067
|
+
args: {
|
|
1068
|
+
orbitalCount: orbitals.length,
|
|
1069
|
+
mode: generationOptions.mode,
|
|
1070
|
+
concurrency: generationOptions.concurrency
|
|
1071
|
+
}
|
|
1072
|
+
});
|
|
1073
|
+
const result = await generateOrbitalsBatch(client, orbitals, generationOptions);
|
|
1074
|
+
emitEvent("batch", result.totalBatches - 1, result.totalBatches, "todo_update", {
|
|
1075
|
+
todos: orbitals.map((o, i) => ({
|
|
1076
|
+
id: `orbital-${i}`,
|
|
1077
|
+
task: `Generate ${o.name}`,
|
|
1078
|
+
status: result.batchResults.some(
|
|
1079
|
+
(b) => b.results.some((r) => r.orbital.name === o.name && r.success)
|
|
1080
|
+
) ? "completed" : "failed"
|
|
1081
|
+
}))
|
|
1082
|
+
});
|
|
1083
|
+
const generatedOrbitals = result.results.filter((r) => r.orbital).map((r) => r.orbital);
|
|
1084
|
+
const successCount = generatedOrbitals.length;
|
|
1085
|
+
const failedCount = orbitals.length - successCount;
|
|
1086
|
+
emitEvent("batch", result.totalBatches - 1, result.totalBatches, "message", {
|
|
1087
|
+
content: `Batch generation complete: ${successCount}/${orbitals.length} orbitals generated successfully`,
|
|
1088
|
+
role: "assistant",
|
|
1089
|
+
isComplete: true
|
|
1090
|
+
});
|
|
1091
|
+
if (workDir && completeCallback && generatedOrbitals.length > 0) {
|
|
1092
|
+
try {
|
|
1093
|
+
await completeCallback(generatedOrbitals, 0, 1);
|
|
1094
|
+
emitEvent("batch", result.totalBatches - 1, result.totalBatches, "generation_log", {
|
|
1095
|
+
level: "info",
|
|
1096
|
+
message: `Persisted ${generatedOrbitals.length} orbitals`
|
|
1097
|
+
});
|
|
1098
|
+
} catch (persistError) {
|
|
1099
|
+
console.error(`[OrbitalBatchSubagent] Failed to persist orbitals:`, persistError);
|
|
1100
|
+
emitEvent("batch", result.totalBatches - 1, result.totalBatches, "generation_log", {
|
|
1101
|
+
level: "warn",
|
|
1102
|
+
message: "Failed to persist some orbitals",
|
|
1103
|
+
data: { error: String(persistError) }
|
|
1104
|
+
});
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
return JSON.stringify({
|
|
1108
|
+
success: successCount === orbitals.length,
|
|
1109
|
+
generated: successCount,
|
|
1110
|
+
failed: failedCount,
|
|
1111
|
+
total: orbitals.length,
|
|
1112
|
+
orbitals: generatedOrbitals,
|
|
1113
|
+
duration: result.totalDurationMs,
|
|
1114
|
+
totalTokens: result.summary.totalTokens,
|
|
1115
|
+
batches: result.totalBatches
|
|
1116
|
+
});
|
|
1117
|
+
} catch (error) {
|
|
1118
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1119
|
+
console.error(`[OrbitalBatchSubagent] Batch generation failed:`, errorMessage);
|
|
1120
|
+
emitEvent("batch", 0, 1, "error", {
|
|
1121
|
+
error: errorMessage,
|
|
1122
|
+
code: "BATCH_GENERATION_ERROR"
|
|
1123
|
+
});
|
|
1124
|
+
return JSON.stringify({
|
|
1125
|
+
success: false,
|
|
1126
|
+
error: errorMessage,
|
|
1127
|
+
orbitals: []
|
|
1128
|
+
});
|
|
1129
|
+
}
|
|
1130
|
+
},
|
|
1131
|
+
{
|
|
1132
|
+
name: "generate_orbitals_batch",
|
|
1133
|
+
description: "Generate multiple orbitals in optimized batches. MUCH FASTER than calling generate_orbital multiple times. Use this when generating 3+ orbitals. Supports parallel generation with automatic concurrency control.",
|
|
1134
|
+
schema: OrbitalBatchInputSchema
|
|
1135
|
+
}
|
|
1136
|
+
);
|
|
1137
|
+
return {
|
|
1138
|
+
tool: batchTool,
|
|
1139
|
+
setEventCallback,
|
|
1140
|
+
setBatchCompleteCallback
|
|
1141
|
+
};
|
|
1142
|
+
}
|
|
1143
|
+
var OrbitalBatchInputSchema;
|
|
1144
|
+
var init_orbital_batch_subagent = __esm({
|
|
1145
|
+
"src/tools/orbital-batch-subagent.ts"() {
|
|
1146
|
+
init_shared();
|
|
1147
|
+
init_batch();
|
|
1148
|
+
OrbitalBatchInputSchema = z.object({
|
|
1149
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1150
|
+
orbitals: z.array(z.any()).describe("Array of OrbitalUnits to generate"),
|
|
1151
|
+
options: z.object({
|
|
1152
|
+
mode: z.enum(["single-call", "parallel-individual", "adaptive"]).optional().default("adaptive"),
|
|
1153
|
+
batchSize: z.number().optional(),
|
|
1154
|
+
maxConcurrency: z.number().optional(),
|
|
1155
|
+
preserveRelationships: z.boolean().optional().default(true)
|
|
1156
|
+
}).optional().describe("Batch generation options")
|
|
1157
|
+
});
|
|
1158
|
+
}
|
|
1159
|
+
});
|
|
312
1160
|
var DANGEROUS_COMMANDS = [
|
|
313
1161
|
"rm",
|
|
314
1162
|
"rmdir",
|
|
@@ -1051,6 +1899,77 @@ npx kflow domain:validate input.orb --verbose
|
|
|
1051
1899
|
|
|
1052
1900
|
// src/tools/finish-task.ts
|
|
1053
1901
|
var execAsync2 = promisify(exec);
|
|
1902
|
+
var PROP_CORRECTIONS = {
|
|
1903
|
+
onSubmit: "submitEvent",
|
|
1904
|
+
onCancel: "cancelEvent",
|
|
1905
|
+
headerActions: "actions",
|
|
1906
|
+
loading: "isLoading",
|
|
1907
|
+
fieldNames: "fields"
|
|
1908
|
+
};
|
|
1909
|
+
function autoCorrectProps(schema) {
|
|
1910
|
+
let corrections = 0;
|
|
1911
|
+
JSON.stringify(schema);
|
|
1912
|
+
function walkAndFix(obj) {
|
|
1913
|
+
if (Array.isArray(obj)) {
|
|
1914
|
+
return obj.map(walkAndFix);
|
|
1915
|
+
}
|
|
1916
|
+
if (obj && typeof obj === "object") {
|
|
1917
|
+
const result = {};
|
|
1918
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
1919
|
+
if (key in PROP_CORRECTIONS) {
|
|
1920
|
+
result[PROP_CORRECTIONS[key]] = walkAndFix(value);
|
|
1921
|
+
corrections++;
|
|
1922
|
+
} else {
|
|
1923
|
+
result[key] = walkAndFix(value);
|
|
1924
|
+
}
|
|
1925
|
+
}
|
|
1926
|
+
return result;
|
|
1927
|
+
}
|
|
1928
|
+
return obj;
|
|
1929
|
+
}
|
|
1930
|
+
const fixed = walkAndFix(schema);
|
|
1931
|
+
Object.assign(schema, fixed);
|
|
1932
|
+
return corrections;
|
|
1933
|
+
}
|
|
1934
|
+
function checkCompositionQuality(schema) {
|
|
1935
|
+
const warnings = [];
|
|
1936
|
+
const orbitals = schema.orbitals;
|
|
1937
|
+
if (!Array.isArray(orbitals)) return warnings;
|
|
1938
|
+
for (const orbital of orbitals) {
|
|
1939
|
+
const orbObj = orbital;
|
|
1940
|
+
const traits = orbObj.traits;
|
|
1941
|
+
if (!Array.isArray(traits)) continue;
|
|
1942
|
+
for (const trait of traits) {
|
|
1943
|
+
const traitObj = trait;
|
|
1944
|
+
const transitions = traitObj.stateMachine?.transitions;
|
|
1945
|
+
if (!Array.isArray(transitions)) continue;
|
|
1946
|
+
for (const transition of transitions) {
|
|
1947
|
+
const trans = transition;
|
|
1948
|
+
if (trans.event !== "INIT") continue;
|
|
1949
|
+
const effects = trans.effects;
|
|
1950
|
+
if (!Array.isArray(effects)) continue;
|
|
1951
|
+
const mainRenderUIs = effects.filter(
|
|
1952
|
+
(e) => Array.isArray(e) && e[0] === "render-ui" && e[1] === "main"
|
|
1953
|
+
);
|
|
1954
|
+
if (mainRenderUIs.length > 1) {
|
|
1955
|
+
warnings.push(
|
|
1956
|
+
`\u26A0\uFE0F ${orbObj.name}/${traitObj.name} INIT has ${mainRenderUIs.length} flat render-ui calls to main. Should be a single composed stack with children.`
|
|
1957
|
+
);
|
|
1958
|
+
}
|
|
1959
|
+
if (mainRenderUIs.length === 1) {
|
|
1960
|
+
const renderPayload = mainRenderUIs[0];
|
|
1961
|
+
const payload = renderPayload[2];
|
|
1962
|
+
if (payload && payload.type !== "stack" && !payload.children) {
|
|
1963
|
+
warnings.push(
|
|
1964
|
+
`\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.`
|
|
1965
|
+
);
|
|
1966
|
+
}
|
|
1967
|
+
}
|
|
1968
|
+
}
|
|
1969
|
+
}
|
|
1970
|
+
}
|
|
1971
|
+
return warnings;
|
|
1972
|
+
}
|
|
1054
1973
|
async function collectOrbitalsFromDir(workDir) {
|
|
1055
1974
|
const orbitalsDir = path.join(workDir, ".orbitals");
|
|
1056
1975
|
try {
|
|
@@ -1105,6 +2024,8 @@ function createFinishTaskTool(workDir) {
|
|
|
1105
2024
|
let stats = null;
|
|
1106
2025
|
let validationResult = null;
|
|
1107
2026
|
let source = null;
|
|
2027
|
+
let propCorrections = 0;
|
|
2028
|
+
let compositionWarnings = [];
|
|
1108
2029
|
if (workDir) {
|
|
1109
2030
|
const orbitals = await collectOrbitalsFromDir(workDir);
|
|
1110
2031
|
if (orbitals.length > 0) {
|
|
@@ -1149,6 +2070,10 @@ function createFinishTaskTool(workDir) {
|
|
|
1149
2070
|
} catch {
|
|
1150
2071
|
}
|
|
1151
2072
|
}
|
|
2073
|
+
if (combinedSchema) {
|
|
2074
|
+
propCorrections = autoCorrectProps(combinedSchema);
|
|
2075
|
+
compositionWarnings = checkCompositionQuality(combinedSchema);
|
|
2076
|
+
}
|
|
1152
2077
|
if (combinedSchema) {
|
|
1153
2078
|
const schemaPath = path.join(workDir, "schema.json");
|
|
1154
2079
|
await fs4.writeFile(schemaPath, JSON.stringify(combinedSchema, null, 2));
|
|
@@ -1168,6 +2093,10 @@ function createFinishTaskTool(workDir) {
|
|
|
1168
2093
|
errorCount: validationResult.errors?.length || 0,
|
|
1169
2094
|
warningCount: validationResult.warnings?.length || 0
|
|
1170
2095
|
} : void 0,
|
|
2096
|
+
designQuality: {
|
|
2097
|
+
propCorrections: propCorrections || 0,
|
|
2098
|
+
compositionWarnings: compositionWarnings || []
|
|
2099
|
+
},
|
|
1171
2100
|
schemaPath: combinedSchema ? path.join(workDir, "schema.json") : input.schemaPath,
|
|
1172
2101
|
nextAction: "NONE - Task is complete. Output a brief success message to the user."
|
|
1173
2102
|
};
|
|
@@ -1455,8 +2384,8 @@ function createGenerateOrbitalDomainTool(options = {}) {
|
|
|
1455
2384
|
orbitalName: spec.name
|
|
1456
2385
|
});
|
|
1457
2386
|
const client = new LLMClient({
|
|
1458
|
-
provider: "anthropic",
|
|
1459
|
-
model: "claude-sonnet-4-20250514",
|
|
2387
|
+
provider: options.provider ?? "anthropic",
|
|
2388
|
+
model: options.model ?? "claude-sonnet-4-20250514",
|
|
1460
2389
|
temperature: 0
|
|
1461
2390
|
});
|
|
1462
2391
|
const userPrompt = buildDynamicUserPrompt(spec);
|
|
@@ -1662,20 +2591,8 @@ function createDomainOrbitalTools(options = {}) {
|
|
|
1662
2591
|
|
|
1663
2592
|
// src/orbitals/generation/orbital-generator.ts
|
|
1664
2593
|
init_cache();
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
return entity.replace(".entity", "");
|
|
1668
|
-
}
|
|
1669
|
-
return entity.name;
|
|
1670
|
-
}
|
|
1671
|
-
function createLog(level, message, data) {
|
|
1672
|
-
return {
|
|
1673
|
-
timestamp: Date.now(),
|
|
1674
|
-
level,
|
|
1675
|
-
message,
|
|
1676
|
-
data
|
|
1677
|
-
};
|
|
1678
|
-
}
|
|
2594
|
+
init_shared();
|
|
2595
|
+
init_shared();
|
|
1679
2596
|
async function generateFullOrbital(client, orbital, options = {}) {
|
|
1680
2597
|
const {
|
|
1681
2598
|
maxTokens = 8192,
|
|
@@ -1936,8 +2853,8 @@ function createOrbitalSubagentTool(options = {}) {
|
|
|
1936
2853
|
]
|
|
1937
2854
|
});
|
|
1938
2855
|
const client = new LLMClient({
|
|
1939
|
-
provider: "anthropic",
|
|
1940
|
-
model: "claude-sonnet-4-20250514"
|
|
2856
|
+
provider: options.provider ?? "anthropic",
|
|
2857
|
+
model: options.model ?? "claude-sonnet-4-20250514"
|
|
1941
2858
|
});
|
|
1942
2859
|
emitEvent(orbitalUnit.name, orbitalIndex, totalOrbitals, "tool_call", {
|
|
1943
2860
|
tool: "llm_generate",
|
|
@@ -2054,6 +2971,9 @@ USAGE:
|
|
|
2054
2971
|
setOrbitalCompleteCallback
|
|
2055
2972
|
};
|
|
2056
2973
|
}
|
|
2974
|
+
|
|
2975
|
+
// src/tools/index.ts
|
|
2976
|
+
init_orbital_batch_subagent();
|
|
2057
2977
|
var TraitSpecSchema = z.object({
|
|
2058
2978
|
name: z.string().describe("Name of the trait"),
|
|
2059
2979
|
description: z.string().describe("Description of what this trait does"),
|
|
@@ -2328,273 +3248,6 @@ function createSchemaChunkingTools(workDir) {
|
|
|
2328
3248
|
applyChunk: createApplyChunkTool(workDir)
|
|
2329
3249
|
};
|
|
2330
3250
|
}
|
|
2331
|
-
var designCache = /* @__PURE__ */ new Map();
|
|
2332
|
-
var CACHE_TTL_MS2 = 24 * 60 * 60 * 1e3;
|
|
2333
|
-
var CACHE_VERSION2 = 1;
|
|
2334
|
-
function generateFingerprint2(input) {
|
|
2335
|
-
const normalized = JSON.stringify({
|
|
2336
|
-
version: CACHE_VERSION2,
|
|
2337
|
-
...input
|
|
2338
|
-
});
|
|
2339
|
-
return crypto.createHash("sha256").update(normalized).digest("hex").slice(0, 16);
|
|
2340
|
-
}
|
|
2341
|
-
function getCached2(fingerprint) {
|
|
2342
|
-
const entry = designCache.get(fingerprint);
|
|
2343
|
-
if (!entry) return null;
|
|
2344
|
-
if (Date.now() - entry.timestamp > CACHE_TTL_MS2) {
|
|
2345
|
-
designCache.delete(fingerprint);
|
|
2346
|
-
return null;
|
|
2347
|
-
}
|
|
2348
|
-
return entry;
|
|
2349
|
-
}
|
|
2350
|
-
var STATIC_DESIGN_PROMPT = null;
|
|
2351
|
-
function getDesignSystemPrompt() {
|
|
2352
|
-
if (!STATIC_DESIGN_PROMPT) {
|
|
2353
|
-
const skill = generateKflowDesignSkill();
|
|
2354
|
-
STATIC_DESIGN_PROMPT = skill.content;
|
|
2355
|
-
}
|
|
2356
|
-
return STATIC_DESIGN_PROMPT;
|
|
2357
|
-
}
|
|
2358
|
-
function getPatternRecommendations(input) {
|
|
2359
|
-
const recContext = buildRecommendationContext({
|
|
2360
|
-
state: input.from,
|
|
2361
|
-
event: input.event,
|
|
2362
|
-
slot: input.slot,
|
|
2363
|
-
domainCategory: input.domainCategory,
|
|
2364
|
-
entityFields: input.entityFields
|
|
2365
|
-
});
|
|
2366
|
-
return recommendPatterns(recContext, 8);
|
|
2367
|
-
}
|
|
2368
|
-
function buildDesignUserPrompt(input) {
|
|
2369
|
-
const fieldList = input.entityFields.map((f) => {
|
|
2370
|
-
let desc = ` - ${f.name}: ${f.type}`;
|
|
2371
|
-
if (f.values) desc += ` (values: ${f.values.join(", ")})`;
|
|
2372
|
-
return desc;
|
|
2373
|
-
}).join("\n");
|
|
2374
|
-
const hints = [];
|
|
2375
|
-
if (input.designStyle) hints.push(`Style: ${input.designStyle}`);
|
|
2376
|
-
if (input.flowPattern) hints.push(`Flow: ${input.flowPattern}`);
|
|
2377
|
-
if (input.listPattern) hints.push(`List: ${input.listPattern}`);
|
|
2378
|
-
if (input.formPattern) hints.push(`Form: ${input.formPattern}`);
|
|
2379
|
-
if (input.detailPattern) hints.push(`Detail: ${input.detailPattern}`);
|
|
2380
|
-
const vocab = input.vocabulary ? Object.entries(input.vocabulary).map(([k, v]) => ` ${k} \u2192 "${v}"`).join("\n") : "";
|
|
2381
|
-
return `Design render-ui effects for this transition:
|
|
2382
|
-
|
|
2383
|
-
## Transition
|
|
2384
|
-
- **From**: ${input.from}
|
|
2385
|
-
- **To**: ${input.to}
|
|
2386
|
-
- **Event**: ${input.event}
|
|
2387
|
-
- **Slot**: ${input.slot}
|
|
2388
|
-
|
|
2389
|
-
## Entity: ${input.entityName}
|
|
2390
|
-
${fieldList}
|
|
2391
|
-
|
|
2392
|
-
## Domain
|
|
2393
|
-
- **Category**: ${input.domainCategory || "business"}
|
|
2394
|
-
${vocab ? `- **Vocabulary**:
|
|
2395
|
-
${vocab}` : ""}
|
|
2396
|
-
${hints.length > 0 ? `- **Design Hints**: ${hints.join(", ")}` : ""}
|
|
2397
|
-
|
|
2398
|
-
${input.recommendationsSection || ""}
|
|
2399
|
-
|
|
2400
|
-
${input.existingEffects ? `## Existing Effects (enhance these)
|
|
2401
|
-
\`\`\`json
|
|
2402
|
-
${JSON.stringify(input.existingEffects, null, 2)}
|
|
2403
|
-
\`\`\`` : ""}
|
|
2404
|
-
|
|
2405
|
-
Return ONLY the JSON array of render-ui effect tuples.`;
|
|
2406
|
-
}
|
|
2407
|
-
var DesignTransitionSchema = z.object({
|
|
2408
|
-
from: z.string().describe('Source state name (e.g., "Browsing")'),
|
|
2409
|
-
to: z.string().describe('Target state name (e.g., "Browsing" for self-loop, "Creating" for transition)'),
|
|
2410
|
-
event: z.string().describe('Event name (e.g., "INIT", "CREATE", "VIEW", "EDIT", "DELETE", "SAVE", "CANCEL")'),
|
|
2411
|
-
slot: z.string().describe('UI slot to render into: "main", "modal", "drawer", "sidebar", "overlay"'),
|
|
2412
|
-
entityName: z.string().describe('Entity name (e.g., "Task", "Order")'),
|
|
2413
|
-
entityFields: z.array(z.object({
|
|
2414
|
-
name: z.string(),
|
|
2415
|
-
type: z.string(),
|
|
2416
|
-
values: z.array(z.string()).optional()
|
|
2417
|
-
})).describe("Entity fields with types and optional enum values"),
|
|
2418
|
-
domainCategory: AgentDomainCategorySchema.optional().describe("Domain category for pattern selection"),
|
|
2419
|
-
vocabulary: z.record(z.string(), z.string()).optional().describe('Domain vocabulary mapping (e.g., { "create": "Place Order", "item": "Order" })'),
|
|
2420
|
-
designStyle: z.enum(["minimal", "modern", "playful", "data-driven", "immersive"]).optional().describe("Visual style hint"),
|
|
2421
|
-
flowPattern: z.enum(["hub-spoke", "master-detail", "crud-cycle", "linear", "role-based"]).optional().describe("Application flow pattern"),
|
|
2422
|
-
listPattern: z.enum(["entity-table", "entity-cards", "entity-list"]).optional().describe("Preferred list pattern"),
|
|
2423
|
-
formPattern: z.enum(["modal", "drawer", "page"]).optional().describe("Preferred form pattern"),
|
|
2424
|
-
detailPattern: z.enum(["drawer", "page", "split"]).optional().describe("Preferred detail view pattern"),
|
|
2425
|
-
existingEffects: z.array(z.any()).optional().describe("Existing render-ui effects to enhance (for refinement passes)")
|
|
2426
|
-
});
|
|
2427
|
-
function createDesignTransitionTool(options = {}) {
|
|
2428
|
-
let eventCallback = options.onEvent;
|
|
2429
|
-
const setEventCallback = (callback) => {
|
|
2430
|
-
eventCallback = callback;
|
|
2431
|
-
};
|
|
2432
|
-
const emitEvent = (transitionId, type, data) => {
|
|
2433
|
-
if (eventCallback) {
|
|
2434
|
-
eventCallback(transitionId, {
|
|
2435
|
-
type,
|
|
2436
|
-
data,
|
|
2437
|
-
timestamp: Date.now()
|
|
2438
|
-
});
|
|
2439
|
-
}
|
|
2440
|
-
};
|
|
2441
|
-
const designTransitionTool = tool(
|
|
2442
|
-
async (input) => {
|
|
2443
|
-
const transitionId = `${input.entityName}:${input.from}->${input.to}:${input.event}`;
|
|
2444
|
-
const fingerprint = generateFingerprint2({
|
|
2445
|
-
from: input.from,
|
|
2446
|
-
to: input.to,
|
|
2447
|
-
event: input.event,
|
|
2448
|
-
slot: input.slot,
|
|
2449
|
-
entityName: input.entityName,
|
|
2450
|
-
entityFields: input.entityFields,
|
|
2451
|
-
domainCategory: input.domainCategory,
|
|
2452
|
-
designStyle: input.designStyle,
|
|
2453
|
-
flowPattern: input.flowPattern,
|
|
2454
|
-
listPattern: input.listPattern
|
|
2455
|
-
});
|
|
2456
|
-
try {
|
|
2457
|
-
emitEvent(transitionId, "message", {
|
|
2458
|
-
content: `Designing UI for ${transitionId}`,
|
|
2459
|
-
role: "assistant",
|
|
2460
|
-
isComplete: false
|
|
2461
|
-
});
|
|
2462
|
-
const cached = getCached2(fingerprint);
|
|
2463
|
-
if (cached) {
|
|
2464
|
-
emitEvent(transitionId, "generation_log", {
|
|
2465
|
-
level: "info",
|
|
2466
|
-
message: `Design cache HIT for ${transitionId}`,
|
|
2467
|
-
data: { fingerprint }
|
|
2468
|
-
});
|
|
2469
|
-
return JSON.stringify({
|
|
2470
|
-
success: true,
|
|
2471
|
-
transitionId,
|
|
2472
|
-
effects: cached.effects,
|
|
2473
|
-
cached: true,
|
|
2474
|
-
usage: cached.usage
|
|
2475
|
-
});
|
|
2476
|
-
}
|
|
2477
|
-
const recommendations = getPatternRecommendations(input);
|
|
2478
|
-
const recommendationsSection = formatRecommendationsForPrompt(recommendations);
|
|
2479
|
-
const systemPrompt = getDesignSystemPrompt();
|
|
2480
|
-
const userPrompt = buildDesignUserPrompt({
|
|
2481
|
-
...input,
|
|
2482
|
-
recommendationsSection
|
|
2483
|
-
});
|
|
2484
|
-
emitEvent(transitionId, "tool_call", {
|
|
2485
|
-
tool: "llm_design_transition",
|
|
2486
|
-
args: {
|
|
2487
|
-
transition: transitionId,
|
|
2488
|
-
slot: input.slot,
|
|
2489
|
-
domain: input.domainCategory
|
|
2490
|
-
}
|
|
2491
|
-
});
|
|
2492
|
-
const client = new LLMClient({
|
|
2493
|
-
provider: "anthropic",
|
|
2494
|
-
model: "claude-sonnet-4-20250514",
|
|
2495
|
-
temperature: 0.1
|
|
2496
|
-
// Slight creativity for design
|
|
2497
|
-
});
|
|
2498
|
-
const response = await client.callWithCache({
|
|
2499
|
-
systemPrompt: "",
|
|
2500
|
-
systemBlocks: [{
|
|
2501
|
-
type: "text",
|
|
2502
|
-
text: systemPrompt,
|
|
2503
|
-
cache_control: { type: "ephemeral" }
|
|
2504
|
-
}],
|
|
2505
|
-
userPrompt,
|
|
2506
|
-
maxTokens: 4096,
|
|
2507
|
-
rawText: true
|
|
2508
|
-
});
|
|
2509
|
-
const rawText = (response.raw || String(response.data) || "").trim();
|
|
2510
|
-
let effects;
|
|
2511
|
-
try {
|
|
2512
|
-
const jsonText = rawText.replace(/^```(?:json)?\n?/m, "").replace(/\n?```$/m, "").trim();
|
|
2513
|
-
effects = JSON.parse(jsonText);
|
|
2514
|
-
if (!Array.isArray(effects)) {
|
|
2515
|
-
effects = [effects];
|
|
2516
|
-
}
|
|
2517
|
-
} catch {
|
|
2518
|
-
return JSON.stringify({
|
|
2519
|
-
success: false,
|
|
2520
|
-
transitionId,
|
|
2521
|
-
error: "Failed to parse design output as JSON",
|
|
2522
|
-
rawOutput: rawText
|
|
2523
|
-
});
|
|
2524
|
-
}
|
|
2525
|
-
const usage = {
|
|
2526
|
-
inputTokens: response.usage?.promptTokens || 0,
|
|
2527
|
-
outputTokens: response.usage?.completionTokens || 0,
|
|
2528
|
-
totalTokens: response.usage?.totalTokens || 0
|
|
2529
|
-
};
|
|
2530
|
-
designCache.set(fingerprint, {
|
|
2531
|
-
effects,
|
|
2532
|
-
timestamp: Date.now(),
|
|
2533
|
-
usage
|
|
2534
|
-
});
|
|
2535
|
-
emitEvent(transitionId, "tool_result", {
|
|
2536
|
-
tool: "llm_design_transition",
|
|
2537
|
-
result: { fingerprint, effectCount: effects.length, usage },
|
|
2538
|
-
success: true
|
|
2539
|
-
});
|
|
2540
|
-
emitEvent(transitionId, "message", {
|
|
2541
|
-
content: `Designed ${effects.length} effect(s) for ${transitionId} (${usage.totalTokens} tokens)`,
|
|
2542
|
-
role: "assistant",
|
|
2543
|
-
isComplete: true
|
|
2544
|
-
});
|
|
2545
|
-
return JSON.stringify({
|
|
2546
|
-
success: true,
|
|
2547
|
-
transitionId,
|
|
2548
|
-
effects,
|
|
2549
|
-
cached: false,
|
|
2550
|
-
usage,
|
|
2551
|
-
recommendedPatterns: recommendations.map((r) => r.pattern)
|
|
2552
|
-
});
|
|
2553
|
-
} catch (error) {
|
|
2554
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2555
|
-
emitEvent(transitionId, "error", {
|
|
2556
|
-
error: errorMessage,
|
|
2557
|
-
code: "DESIGN_TRANSITION_ERROR"
|
|
2558
|
-
});
|
|
2559
|
-
return JSON.stringify({
|
|
2560
|
-
success: false,
|
|
2561
|
-
transitionId,
|
|
2562
|
-
error: errorMessage
|
|
2563
|
-
});
|
|
2564
|
-
}
|
|
2565
|
-
},
|
|
2566
|
-
{
|
|
2567
|
-
name: "design_transition",
|
|
2568
|
-
description: `Design rich render-ui effects for a single orbital transition.
|
|
2569
|
-
|
|
2570
|
-
Takes the transition context (from/to state, event, entity, domain) and produces
|
|
2571
|
-
polished render-ui effects using the full pattern catalog.
|
|
2572
|
-
|
|
2573
|
-
USE THIS TOOL WHEN:
|
|
2574
|
-
- Generating INIT transitions (always compose header + stats + content)
|
|
2575
|
-
- Generating CREATE/EDIT transitions (form with proper fields)
|
|
2576
|
-
- Generating VIEW transitions (detail with tabs for related entities)
|
|
2577
|
-
- Enhancing existing render-ui effects that are too basic
|
|
2578
|
-
|
|
2579
|
-
The tool uses a specialized design skill with pattern catalog, layout composition,
|
|
2580
|
-
and domain-aware pattern selection to produce rich UI.
|
|
2581
|
-
|
|
2582
|
-
RETURNS: { success, effects: [["render-ui", slot, config], ...], transitionId, usage }
|
|
2583
|
-
|
|
2584
|
-
The effects array contains ONLY render-ui tuples. Non-UI effects (persist, emit, set)
|
|
2585
|
-
are NOT included \u2014 you must preserve those from the original transition.
|
|
2586
|
-
|
|
2587
|
-
INTEGRATION: After calling this tool, use extract_chunk to get the orbital,
|
|
2588
|
-
replace the render-ui effects in the target transition (keep persist/emit/set effects),
|
|
2589
|
-
then apply_chunk to merge back into schema.json.`,
|
|
2590
|
-
schema: DesignTransitionSchema
|
|
2591
|
-
}
|
|
2592
|
-
);
|
|
2593
|
-
return {
|
|
2594
|
-
tool: designTransitionTool,
|
|
2595
|
-
setEventCallback
|
|
2596
|
-
};
|
|
2597
|
-
}
|
|
2598
3251
|
function createGitHubTools(config) {
|
|
2599
3252
|
const { token, owner = "", repo = "", workDir } = config;
|
|
2600
3253
|
const integrationConfig = {
|
|
@@ -3693,6 +4346,21 @@ function createLLMClient(provider, model, verbose) {
|
|
|
3693
4346
|
model: model || OPENAI_MODELS.GPT4O,
|
|
3694
4347
|
temperature
|
|
3695
4348
|
});
|
|
4349
|
+
case "kimi":
|
|
4350
|
+
if (verbose)
|
|
4351
|
+
console.log(`[SkillAgent] Using Kimi: ${model || KIMI_MODELS.K2_5}`);
|
|
4352
|
+
return createKimiClient({
|
|
4353
|
+
model: model || KIMI_MODELS.K2_5,
|
|
4354
|
+
temperature: 0.6
|
|
4355
|
+
// Kimi with thinking disabled requires 0.6
|
|
4356
|
+
});
|
|
4357
|
+
case "openrouter":
|
|
4358
|
+
if (verbose)
|
|
4359
|
+
console.log(`[SkillAgent] Using OpenRouter: ${model || OPENROUTER_MODELS.QWEN_2_5_72B}`);
|
|
4360
|
+
return createOpenRouterClient({
|
|
4361
|
+
model: model || OPENROUTER_MODELS.QWEN_2_5_72B,
|
|
4362
|
+
temperature: 0.3
|
|
4363
|
+
});
|
|
3696
4364
|
case "anthropic":
|
|
3697
4365
|
default:
|
|
3698
4366
|
if (verbose)
|
|
@@ -3717,6 +4385,8 @@ async function createSkillAgent(options) {
|
|
|
3717
4385
|
threadId: providedThreadId,
|
|
3718
4386
|
provider = "anthropic",
|
|
3719
4387
|
model,
|
|
4388
|
+
subagentProvider = "anthropic",
|
|
4389
|
+
subagentModel = "claude-sonnet-4-20250514",
|
|
3720
4390
|
verbose = false,
|
|
3721
4391
|
skillLoader,
|
|
3722
4392
|
skillRefLoader
|
|
@@ -3813,20 +4483,24 @@ ${skillContents}`;
|
|
|
3813
4483
|
const finishTaskTool = createFinishTaskTool(workDir);
|
|
3814
4484
|
const validateSchemaTool = createValidateSchemaTool(workDir);
|
|
3815
4485
|
const ORBITAL_SKILLS = ["kflow-orbitals", "kflow-orbital-games", "kflow-orbital-fixing"];
|
|
4486
|
+
const ORBITAL_BATCH_SKILLS = ["kflow-orbitals-batch"];
|
|
3816
4487
|
const LEAN_SKILLS = ["kflow-lean-orbitals", "kflow-lean-fixing"];
|
|
3817
|
-
const DESIGN_SKILLS = ["kflow-design", "kflow-lean-design"];
|
|
3818
4488
|
const isOrbitalSkill = primarySkill.name === "kflow-orbitals";
|
|
4489
|
+
const isOrbitalBatchSkill = ORBITAL_BATCH_SKILLS.includes(primarySkill.name);
|
|
3819
4490
|
const isLeanSkill = LEAN_SKILLS.includes(primarySkill.name);
|
|
3820
|
-
const
|
|
3821
|
-
const needsChunkingTools = ORBITAL_SKILLS.includes(primarySkill.name) || isDesignSkill;
|
|
4491
|
+
const needsChunkingTools = ORBITAL_SKILLS.includes(primarySkill.name);
|
|
3822
4492
|
let orbitalTool;
|
|
3823
4493
|
let setOrbitalEventCallback;
|
|
3824
4494
|
let setOrbitalCompleteCallback;
|
|
4495
|
+
let orbitalBatchTool;
|
|
4496
|
+
let setBatchEventCallback;
|
|
3825
4497
|
let domainOrbitalTools;
|
|
3826
4498
|
const chunkingTools = needsChunkingTools ? createSchemaChunkingTools(workDir) : null;
|
|
3827
4499
|
if (isOrbitalSkill) {
|
|
3828
4500
|
const orbitalResult = createOrbitalSubagentTool({
|
|
3829
|
-
requirements: options.requirements
|
|
4501
|
+
requirements: options.requirements,
|
|
4502
|
+
provider: subagentProvider,
|
|
4503
|
+
model: subagentModel
|
|
3830
4504
|
});
|
|
3831
4505
|
orbitalTool = orbitalResult.tool;
|
|
3832
4506
|
setOrbitalEventCallback = orbitalResult.setEventCallback;
|
|
@@ -3838,16 +4512,32 @@ ${skillContents}`;
|
|
|
3838
4512
|
console.log(`[SkillAgent] Orbital tools enabled for kflow-orbitals skill`);
|
|
3839
4513
|
}
|
|
3840
4514
|
}
|
|
3841
|
-
if (
|
|
3842
|
-
|
|
4515
|
+
if (isOrbitalBatchSkill) {
|
|
4516
|
+
const { createOrbitalBatchSubagentTool: createOrbitalBatchSubagentTool2 } = await Promise.resolve().then(() => (init_orbital_batch_subagent(), orbital_batch_subagent_exports));
|
|
4517
|
+
const batchResult = createOrbitalBatchSubagentTool2({
|
|
4518
|
+
requirements: options.requirements,
|
|
4519
|
+
provider: subagentProvider,
|
|
4520
|
+
model: subagentModel,
|
|
4521
|
+
workDir
|
|
4522
|
+
});
|
|
4523
|
+
orbitalBatchTool = batchResult.tool;
|
|
4524
|
+
setBatchEventCallback = batchResult.setEventCallback;
|
|
4525
|
+
if (options.onSubagentEvent) {
|
|
4526
|
+
setBatchEventCallback(options.onSubagentEvent);
|
|
4527
|
+
}
|
|
3843
4528
|
if (verbose) {
|
|
3844
|
-
console.log(`[SkillAgent]
|
|
4529
|
+
console.log(`[SkillAgent] Batch orbital tools enabled for kflow-orbitals-batch skill`);
|
|
3845
4530
|
}
|
|
3846
4531
|
}
|
|
3847
|
-
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
|
|
4532
|
+
if (isLeanSkill) {
|
|
4533
|
+
domainOrbitalTools = createDomainOrbitalTools({
|
|
4534
|
+
workDir,
|
|
4535
|
+
provider: subagentProvider,
|
|
4536
|
+
model: subagentModel
|
|
4537
|
+
});
|
|
4538
|
+
if (verbose) {
|
|
4539
|
+
console.log(`[SkillAgent] Domain orbital tools enabled for ${primarySkill.name} skill (provider: ${subagentProvider})`);
|
|
4540
|
+
}
|
|
3851
4541
|
}
|
|
3852
4542
|
const githubTools = options.githubConfig ? createGitHubToolsArray({
|
|
3853
4543
|
token: options.githubConfig.token,
|
|
@@ -3861,8 +4551,9 @@ ${skillContents}`;
|
|
|
3861
4551
|
const tools = [
|
|
3862
4552
|
executeTool,
|
|
3863
4553
|
finishTaskTool,
|
|
3864
|
-
...isOrbitalSkill ? [] : [validateSchemaTool],
|
|
4554
|
+
...isOrbitalSkill || isOrbitalBatchSkill ? [] : [validateSchemaTool],
|
|
3865
4555
|
...orbitalTool ? [orbitalTool] : [],
|
|
4556
|
+
...orbitalBatchTool ? [orbitalBatchTool] : [],
|
|
3866
4557
|
...domainOrbitalTools ? [
|
|
3867
4558
|
domainOrbitalTools.generateOrbitalDomain,
|
|
3868
4559
|
domainOrbitalTools.constructCombinedDomain
|
|
@@ -3872,7 +4563,6 @@ ${skillContents}`;
|
|
|
3872
4563
|
chunkingTools.extractChunk,
|
|
3873
4564
|
chunkingTools.applyChunk
|
|
3874
4565
|
] : [],
|
|
3875
|
-
...designTool ? [designTool.tool] : [],
|
|
3876
4566
|
...githubTools || []
|
|
3877
4567
|
];
|
|
3878
4568
|
const checkpointer = sessions.getCheckpointer(threadId);
|