@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.
@@ -9,8 +9,7 @@ import { isStructuredOutputAvailable, getStructuredOutputClient, LLMClient } fro
9
9
  import * as domain_language_star from '@almadar/core/domain-language';
10
10
  import * as fs3 from 'fs';
11
11
  import crypto, { randomUUID } from 'crypto';
12
- import { getKeyBehaviorsReference, getSExprQuickRef, getCommonErrorsSection, getArchitectureSection, getFullOrbitalPrompt, generateKflowDesignSkill, getRequirementsTraitPrompt } from '@almadar/skills';
13
- import { formatRecommendationsForPrompt, buildRecommendationContext, recommendPatterns } from '@almadar/patterns';
12
+ import { getKeyBehaviorsReference, getSExprQuickRef, getCommonErrorsSection, getArchitectureSection, getFullOrbitalPrompt, getRequirementsTraitPrompt } from '@almadar/skills';
14
13
  import { GitHubIntegration } from '@almadar/integrations';
15
14
 
16
15
  var __defProp = Object.defineProperty;
@@ -1115,6 +1114,77 @@ npx kflow domain:validate input.orb --verbose
1115
1114
 
1116
1115
  // src/tools/finish-task.ts
1117
1116
  var execAsync2 = promisify(exec);
1117
+ var PROP_CORRECTIONS = {
1118
+ onSubmit: "submitEvent",
1119
+ onCancel: "cancelEvent",
1120
+ headerActions: "actions",
1121
+ loading: "isLoading",
1122
+ fieldNames: "fields"
1123
+ };
1124
+ function autoCorrectProps(schema) {
1125
+ let corrections = 0;
1126
+ JSON.stringify(schema);
1127
+ function walkAndFix(obj) {
1128
+ if (Array.isArray(obj)) {
1129
+ return obj.map(walkAndFix);
1130
+ }
1131
+ if (obj && typeof obj === "object") {
1132
+ const result = {};
1133
+ for (const [key, value] of Object.entries(obj)) {
1134
+ if (key in PROP_CORRECTIONS) {
1135
+ result[PROP_CORRECTIONS[key]] = walkAndFix(value);
1136
+ corrections++;
1137
+ } else {
1138
+ result[key] = walkAndFix(value);
1139
+ }
1140
+ }
1141
+ return result;
1142
+ }
1143
+ return obj;
1144
+ }
1145
+ const fixed = walkAndFix(schema);
1146
+ Object.assign(schema, fixed);
1147
+ return corrections;
1148
+ }
1149
+ function checkCompositionQuality(schema) {
1150
+ const warnings = [];
1151
+ const orbitals = schema.orbitals;
1152
+ if (!Array.isArray(orbitals)) return warnings;
1153
+ for (const orbital of orbitals) {
1154
+ const orbObj = orbital;
1155
+ const traits = orbObj.traits;
1156
+ if (!Array.isArray(traits)) continue;
1157
+ for (const trait of traits) {
1158
+ const traitObj = trait;
1159
+ const transitions = traitObj.stateMachine?.transitions;
1160
+ if (!Array.isArray(transitions)) continue;
1161
+ for (const transition of transitions) {
1162
+ const trans = transition;
1163
+ if (trans.event !== "INIT") continue;
1164
+ const effects = trans.effects;
1165
+ if (!Array.isArray(effects)) continue;
1166
+ const mainRenderUIs = effects.filter(
1167
+ (e) => Array.isArray(e) && e[0] === "render-ui" && e[1] === "main"
1168
+ );
1169
+ if (mainRenderUIs.length > 1) {
1170
+ warnings.push(
1171
+ `\u26A0\uFE0F ${orbObj.name}/${traitObj.name} INIT has ${mainRenderUIs.length} flat render-ui calls to main. Should be a single composed stack with children.`
1172
+ );
1173
+ }
1174
+ if (mainRenderUIs.length === 1) {
1175
+ const renderPayload = mainRenderUIs[0];
1176
+ const payload = renderPayload[2];
1177
+ if (payload && payload.type !== "stack" && !payload.children) {
1178
+ warnings.push(
1179
+ `\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.`
1180
+ );
1181
+ }
1182
+ }
1183
+ }
1184
+ }
1185
+ }
1186
+ return warnings;
1187
+ }
1118
1188
  async function collectOrbitalsFromDir(workDir) {
1119
1189
  const orbitalsDir = path.join(workDir, ".orbitals");
1120
1190
  try {
@@ -1169,6 +1239,8 @@ function createFinishTaskTool(workDir) {
1169
1239
  let stats = null;
1170
1240
  let validationResult = null;
1171
1241
  let source = null;
1242
+ let propCorrections = 0;
1243
+ let compositionWarnings = [];
1172
1244
  if (workDir) {
1173
1245
  const orbitals = await collectOrbitalsFromDir(workDir);
1174
1246
  if (orbitals.length > 0) {
@@ -1213,6 +1285,10 @@ function createFinishTaskTool(workDir) {
1213
1285
  } catch {
1214
1286
  }
1215
1287
  }
1288
+ if (combinedSchema) {
1289
+ propCorrections = autoCorrectProps(combinedSchema);
1290
+ compositionWarnings = checkCompositionQuality(combinedSchema);
1291
+ }
1216
1292
  if (combinedSchema) {
1217
1293
  const schemaPath = path.join(workDir, "schema.json");
1218
1294
  await fs4.writeFile(schemaPath, JSON.stringify(combinedSchema, null, 2));
@@ -1232,6 +1308,10 @@ function createFinishTaskTool(workDir) {
1232
1308
  errorCount: validationResult.errors?.length || 0,
1233
1309
  warningCount: validationResult.warnings?.length || 0
1234
1310
  } : void 0,
1311
+ designQuality: {
1312
+ propCorrections: propCorrections || 0,
1313
+ compositionWarnings: compositionWarnings || []
1314
+ },
1235
1315
  schemaPath: combinedSchema ? path.join(workDir, "schema.json") : input.schemaPath,
1236
1316
  nextAction: "NONE - Task is complete. Output a brief success message to the user."
1237
1317
  };
@@ -1519,8 +1599,8 @@ function createGenerateOrbitalDomainTool(options = {}) {
1519
1599
  orbitalName: spec.name
1520
1600
  });
1521
1601
  const client = new LLMClient({
1522
- provider: "anthropic",
1523
- model: "claude-sonnet-4-20250514",
1602
+ provider: options.provider ?? "anthropic",
1603
+ model: options.model ?? "claude-sonnet-4-20250514",
1524
1604
  temperature: 0
1525
1605
  });
1526
1606
  const userPrompt = buildDynamicUserPrompt(spec);
@@ -1726,12 +1806,47 @@ function createDomainOrbitalTools(options = {}) {
1726
1806
 
1727
1807
  // src/orbitals/generation/orbital-generator.ts
1728
1808
  init_cache();
1809
+
1810
+ // src/orbitals/shared/constants.ts
1811
+ var PROVIDER_CONCURRENCY_LIMITS = {
1812
+ anthropic: 3,
1813
+ openai: 5,
1814
+ deepseek: 3,
1815
+ kimi: 3,
1816
+ openrouter: 5
1817
+ };
1818
+ var PROVIDER_BATCH_SIZES = {
1819
+ anthropic: 3,
1820
+ // Anthropic works well with 3 orbitals per call
1821
+ openai: 5,
1822
+ // OpenAI can handle more
1823
+ deepseek: 3,
1824
+ // Conservative for DeepSeek
1825
+ kimi: 3,
1826
+ // Conservative for Kimi
1827
+ openrouter: 5
1828
+ // OpenRouter proxies multiple providers
1829
+ };
1830
+ var BATCH_MAX_TOKENS = 12e3;
1729
1831
  function getEntityName2(entity) {
1730
1832
  if (isEntityReference(entity)) {
1731
1833
  return entity.replace(".entity", "");
1732
1834
  }
1733
1835
  return entity.name;
1734
1836
  }
1837
+ function getInlineEntity3(entity) {
1838
+ if (isEntityReference(entity)) {
1839
+ return null;
1840
+ }
1841
+ return entity;
1842
+ }
1843
+ function getFieldNames(entity) {
1844
+ const inlineEntity = getInlineEntity3(entity);
1845
+ if (!inlineEntity?.fields?.length) {
1846
+ return "N/A";
1847
+ }
1848
+ return inlineEntity.fields.map((f) => f.name).join(", ");
1849
+ }
1735
1850
  function createLog(level, message, data) {
1736
1851
  return {
1737
1852
  timestamp: Date.now(),
@@ -1740,6 +1855,56 @@ function createLog(level, message, data) {
1740
1855
  data
1741
1856
  };
1742
1857
  }
1858
+ function buildContextSection2(orbital) {
1859
+ const parts = [];
1860
+ if (orbital.domainContext) {
1861
+ const ctx = orbital.domainContext;
1862
+ parts.push(`DomainContext: category=${ctx.category || "business"}`);
1863
+ if (ctx.vocabulary) {
1864
+ parts.push(`Vocabulary: ${JSON.stringify(ctx.vocabulary)}`);
1865
+ }
1866
+ if (ctx.requestFragment) {
1867
+ parts.push(`RequestFragment: "${ctx.requestFragment}"`);
1868
+ }
1869
+ }
1870
+ if (orbital.design) {
1871
+ const d = orbital.design;
1872
+ if (d.style) parts.push(`Style: ${d.style}`);
1873
+ if (d.uxHints) {
1874
+ const hints = d.uxHints;
1875
+ if (hints.flowPattern) parts.push(`FlowPattern: ${hints.flowPattern}`);
1876
+ if (hints.listPattern) parts.push(`ListPattern: ${hints.listPattern}`);
1877
+ if (hints.formPattern) parts.push(`FormPattern: ${hints.formPattern}`);
1878
+ }
1879
+ }
1880
+ return parts.length > 0 ? `Context: ${parts.join(", ")}
1881
+ ` : "";
1882
+ }
1883
+ function buildConnectivitySection(orbital) {
1884
+ const parts = [];
1885
+ if (orbital.emits?.length) {
1886
+ parts.push(`Emits: ${orbital.emits.join(", ")}`);
1887
+ }
1888
+ if (orbital.listens?.length) {
1889
+ parts.push(`Listens: ${orbital.listens.map((l) => `${l.event}\u2192${l.triggers}`).join(", ")}`);
1890
+ }
1891
+ return parts.join("\n");
1892
+ }
1893
+ function chunkArray(array, size) {
1894
+ const chunks = [];
1895
+ for (let i = 0; i < array.length; i += size) {
1896
+ chunks.push(array.slice(i, i + size));
1897
+ }
1898
+ return chunks;
1899
+ }
1900
+ function getErrorMessage(error) {
1901
+ if (error instanceof Error) {
1902
+ return error.message;
1903
+ }
1904
+ return String(error);
1905
+ }
1906
+
1907
+ // src/orbitals/generation/orbital-generator.ts
1743
1908
  async function generateFullOrbital(client, orbital, options = {}) {
1744
1909
  const {
1745
1910
  maxTokens = 8192,
@@ -2000,8 +2165,8 @@ function createOrbitalSubagentTool(options = {}) {
2000
2165
  ]
2001
2166
  });
2002
2167
  const client = new LLMClient({
2003
- provider: "anthropic",
2004
- model: "claude-sonnet-4-20250514"
2168
+ provider: options.provider ?? "anthropic",
2169
+ model: options.model ?? "claude-sonnet-4-20250514"
2005
2170
  });
2006
2171
  emitEvent(orbitalUnit.name, orbitalIndex, totalOrbitals, "tool_call", {
2007
2172
  tool: "llm_generate",
@@ -2133,6 +2298,707 @@ function createSubagentEventWrapper(writeEvent) {
2133
2298
  writeEvent(sseEvent);
2134
2299
  };
2135
2300
  }
2301
+
2302
+ // src/orbitals/batch/prompt-assembler.ts
2303
+ init_cache();
2304
+ function extractSharedContext(orbitals) {
2305
+ const vocabulary = {};
2306
+ const styles = /* @__PURE__ */ new Set();
2307
+ const patterns = /* @__PURE__ */ new Set();
2308
+ const relationships = [];
2309
+ for (const orbital of orbitals) {
2310
+ if (orbital.domainContext?.vocabulary) {
2311
+ Object.assign(vocabulary, orbital.domainContext.vocabulary);
2312
+ }
2313
+ if (orbital.design?.style) {
2314
+ styles.add(orbital.design.style);
2315
+ }
2316
+ }
2317
+ new Map(orbitals.map((o) => [o.name, o]));
2318
+ for (const orbital of orbitals) {
2319
+ if (orbital.emits) {
2320
+ for (const event of orbital.emits) {
2321
+ for (const other of orbitals) {
2322
+ if (other === orbital) continue;
2323
+ if (other.listens) {
2324
+ const listener = other.listens.find((l) => l.event === event.event);
2325
+ if (listener) {
2326
+ relationships.push({
2327
+ emitter: orbital.name,
2328
+ event: event.event,
2329
+ listener: other.name,
2330
+ handler: listener.triggers
2331
+ });
2332
+ }
2333
+ }
2334
+ }
2335
+ }
2336
+ }
2337
+ }
2338
+ return {
2339
+ domainVocabulary: Object.keys(vocabulary).length > 0 ? vocabulary : void 0,
2340
+ designStyle: styles.size === 1 ? Array.from(styles)[0] : void 0,
2341
+ commonPatterns: patterns.size > 0 ? Array.from(patterns) : void 0,
2342
+ eventRelationships: relationships.length > 0 ? relationships : void 0
2343
+ };
2344
+ }
2345
+ function assembleBatchPrompt(orbitals, options = {}) {
2346
+ const {
2347
+ baseSystemPrompt = getFullOrbitalPrompt(),
2348
+ includeConnectivity = true
2349
+ } = options;
2350
+ if (orbitals.length === 0) {
2351
+ throw new Error("Cannot assemble batch prompt for empty orbitals array");
2352
+ }
2353
+ const sharedContext = extractSharedContext(orbitals);
2354
+ const batchHeader = buildBatchHeader(orbitals, sharedContext);
2355
+ const orbitalSections = orbitals.map(
2356
+ (orbital, index) => buildOrbitalSection(orbital, index + 1, orbitals.length, includeConnectivity)
2357
+ );
2358
+ const outputSection = buildOutputSection(orbitals);
2359
+ const prompt = `${baseSystemPrompt}
2360
+
2361
+ ${"=".repeat(60)}
2362
+ BATCH GENERATION: ${orbitals.length} ORBITALS
2363
+ ${"=".repeat(60)}
2364
+
2365
+ ${batchHeader}
2366
+
2367
+ ${orbitalSections.join("\n\n")}
2368
+
2369
+ ${outputSection}`;
2370
+ const fingerprint = generateBatchFingerprint(orbitals);
2371
+ return {
2372
+ prompt,
2373
+ fingerprint,
2374
+ usedCachedTemplate: false,
2375
+ // Batch doesn't use templates yet
2376
+ orbitalCount: orbitals.length,
2377
+ orbitalNames: orbitals.map((o) => o.name)
2378
+ };
2379
+ }
2380
+ function buildBatchHeader(orbitals, sharedContext) {
2381
+ const lines = [
2382
+ `## Batch Overview`,
2383
+ `- Total Orbitals: ${orbitals.length}`,
2384
+ `- Orbitals: ${orbitals.map((o) => o.name).join(", ")}`
2385
+ ];
2386
+ if (sharedContext.designStyle) {
2387
+ lines.push(`- Design Style: ${sharedContext.designStyle}`);
2388
+ }
2389
+ if (sharedContext.commonPatterns?.length) {
2390
+ lines.push(`- Common Patterns: ${sharedContext.commonPatterns.join(", ")}`);
2391
+ }
2392
+ if (sharedContext.domainVocabulary && Object.keys(sharedContext.domainVocabulary).length > 0) {
2393
+ lines.push(`
2394
+ ## Shared Domain Vocabulary`);
2395
+ for (const [term, definition] of Object.entries(sharedContext.domainVocabulary)) {
2396
+ lines.push(`- ${term}: ${definition}`);
2397
+ }
2398
+ }
2399
+ if (sharedContext.eventRelationships?.length) {
2400
+ lines.push(`
2401
+ ## Cross-Orbital Event Relationships`);
2402
+ for (const rel of sharedContext.eventRelationships) {
2403
+ lines.push(`- ${rel.emitter} emits "${rel.event}" \u2192 ${rel.listener} handles with "${rel.handler}"`);
2404
+ }
2405
+ }
2406
+ return lines.join("\n");
2407
+ }
2408
+ function buildOrbitalSection(orbital, index, total, includeConnectivity) {
2409
+ const entityName = getEntityName2(orbital.entity);
2410
+ const fieldNames = getFieldNames(orbital.entity);
2411
+ const contextSection = buildContextSection2(orbital);
2412
+ const connectivitySection = includeConnectivity ? buildConnectivitySection(orbital) : "";
2413
+ return `---
2414
+ ## ORBITAL ${index}/${total}: ${orbital.name}
2415
+
2416
+ **Entity**: ${entityName}
2417
+ **Persistence**: ${orbital.entity.persistence || "persistent"}
2418
+ **Fields**: ${fieldNames}
2419
+ **Traits**: ${orbital.traits.map((t) => typeof t === "string" ? t : "ref" in t ? t.ref : t.name).join(", ")}
2420
+ ${contextSection}${connectivitySection ? `**Connectivity**:
2421
+ ${connectivitySection}
2422
+ ` : ""}
2423
+ Generate a complete FullOrbitalUnit for ${orbital.name} with:
2424
+ - Full field definitions with types and validation
2425
+ - Trait state machines with transitions and effects
2426
+ - Business rule validation using "guard" S-expression on SAVE transitions
2427
+ - Pages with trait references
2428
+ - domainContext with category, vocabulary, and requestFragment
2429
+ - design with style and uxHints (flowPattern, listPattern, formPattern)
2430
+ ${orbital.emits?.length ? "- PRESERVE emits: " + orbital.emits.map((e) => e.event).join(", ") : ""}
2431
+ ${orbital.listens?.length ? "- PRESERVE listens: " + orbital.listens.map((l) => l.event).join(", ") : ""}`;
2432
+ }
2433
+ function buildOutputSection(orbitals) {
2434
+ return `---
2435
+ ## OUTPUT FORMAT
2436
+
2437
+ Return a JSON object with this exact structure:
2438
+
2439
+ \`\`\`json
2440
+ {
2441
+ "orbitals": [
2442
+ ${orbitals.map((o, i) => ` {
2443
+ "name": "${o.name}",
2444
+ // ... complete FullOrbitalUnit for ${o.name}
2445
+ }${i < orbitals.length - 1 ? "," : ""}`).join("\n")}
2446
+ ]
2447
+ }
2448
+ \`\`\`
2449
+
2450
+ **CRITICAL RULES:**
2451
+ 1. Return a SINGLE JSON object with an "orbitals" array
2452
+ 2. Each element in the array is a complete FullOrbitalUnit
2453
+ 3. Maintain the order: ${orbitals.map((o) => o.name).join(", ")}
2454
+ 4. PRESERVE all emits/listens as specified in each orbital section
2455
+ 5. Use shared domain vocabulary consistently across all orbitals
2456
+ 6. Ensure cross-orbital event wiring is maintained
2457
+ `;
2458
+ }
2459
+ function generateBatchFingerprint(orbitals) {
2460
+ const fingerprints = orbitals.map((o) => computeOrbitalFingerprint(o));
2461
+ const combined = fingerprints.sort().join("|");
2462
+ let hash = 0;
2463
+ for (let i = 0; i < combined.length; i++) {
2464
+ const char = combined.charCodeAt(i);
2465
+ hash = (hash << 5) - hash + char;
2466
+ hash = hash & hash;
2467
+ }
2468
+ return `batch:${orbitals.length}:${Math.abs(hash).toString(16).slice(0, 8)}`;
2469
+ }
2470
+ function splitIntoBatches(orbitals, options = {}) {
2471
+ const {
2472
+ maxBatchSize = 3,
2473
+ preserveRelationships = true
2474
+ } = options;
2475
+ if (!preserveRelationships) {
2476
+ return chunkArray(orbitals, maxBatchSize);
2477
+ }
2478
+ const clusters = groupByRelationships(orbitals);
2479
+ const batches = [];
2480
+ for (const cluster of clusters) {
2481
+ if (cluster.length <= maxBatchSize) {
2482
+ batches.push(cluster);
2483
+ } else {
2484
+ batches.push(...chunkArray(cluster, maxBatchSize));
2485
+ }
2486
+ }
2487
+ return batches;
2488
+ }
2489
+ function groupByRelationships(orbitals) {
2490
+ const visited = /* @__PURE__ */ new Set();
2491
+ const clusters = [];
2492
+ const adjacency = /* @__PURE__ */ new Map();
2493
+ for (const orbital of orbitals) {
2494
+ if (!adjacency.has(orbital.name)) {
2495
+ adjacency.set(orbital.name, /* @__PURE__ */ new Set());
2496
+ }
2497
+ if (orbital.emits) {
2498
+ for (const event of orbital.emits) {
2499
+ for (const other of orbitals) {
2500
+ if (other === orbital) continue;
2501
+ if (other.listens?.some((l) => l.event === event.event)) {
2502
+ adjacency.get(orbital.name)?.add(other.name);
2503
+ if (!adjacency.has(other.name)) {
2504
+ adjacency.set(other.name, /* @__PURE__ */ new Set());
2505
+ }
2506
+ adjacency.get(other.name)?.add(orbital.name);
2507
+ }
2508
+ }
2509
+ }
2510
+ }
2511
+ }
2512
+ function dfs(orbital, cluster) {
2513
+ visited.add(orbital.name);
2514
+ cluster.push(orbital);
2515
+ const neighbors = adjacency.get(orbital.name) || /* @__PURE__ */ new Set();
2516
+ for (const neighborName of neighbors) {
2517
+ if (!visited.has(neighborName)) {
2518
+ const neighbor = orbitals.find((o) => o.name === neighborName);
2519
+ if (neighbor) {
2520
+ dfs(neighbor, cluster);
2521
+ }
2522
+ }
2523
+ }
2524
+ }
2525
+ for (const orbital of orbitals) {
2526
+ if (!visited.has(orbital.name)) {
2527
+ const cluster = [];
2528
+ dfs(orbital, cluster);
2529
+ clusters.push(cluster);
2530
+ }
2531
+ }
2532
+ return clusters;
2533
+ }
2534
+ function estimateBatchTokens(orbitals) {
2535
+ const baseTokens = 2e3;
2536
+ const perOrbitalTokens = 800;
2537
+ return baseTokens + orbitals.length * perOrbitalTokens;
2538
+ }
2539
+ function willBatchFit(orbitals, maxTokens = 12e3) {
2540
+ const estimated = estimateBatchTokens(orbitals);
2541
+ return estimated < maxTokens * 0.5;
2542
+ }
2543
+
2544
+ // src/orbitals/batch/concurrency.ts
2545
+ function createConcurrencyController(maxConcurrency) {
2546
+ let activeCount = 0;
2547
+ const queue = [];
2548
+ return {
2549
+ async acquire() {
2550
+ if (activeCount < maxConcurrency) {
2551
+ activeCount++;
2552
+ return Promise.resolve();
2553
+ }
2554
+ return new Promise((resolve2) => {
2555
+ queue.push(() => {
2556
+ activeCount++;
2557
+ resolve2();
2558
+ });
2559
+ });
2560
+ },
2561
+ release() {
2562
+ activeCount = Math.max(0, activeCount - 1);
2563
+ const next = queue.shift();
2564
+ if (next) {
2565
+ next();
2566
+ }
2567
+ },
2568
+ get activeCount() {
2569
+ return activeCount;
2570
+ },
2571
+ get waitingCount() {
2572
+ return queue.length;
2573
+ }
2574
+ };
2575
+ }
2576
+ async function runWithConcurrency(tasks, options) {
2577
+ const { concurrency, onProgress } = options;
2578
+ const controller = createConcurrencyController(concurrency);
2579
+ const results = [];
2580
+ let completed = 0;
2581
+ await Promise.all(
2582
+ tasks.map(async (task, index) => {
2583
+ await controller.acquire();
2584
+ try {
2585
+ results[index] = await task();
2586
+ completed++;
2587
+ onProgress?.(completed, tasks.length);
2588
+ } finally {
2589
+ controller.release();
2590
+ }
2591
+ })
2592
+ );
2593
+ return results;
2594
+ }
2595
+ async function asyncMapWithConcurrency2(items, mapper, concurrency) {
2596
+ return runWithConcurrency(
2597
+ items.map((item, index) => () => mapper(item, index)),
2598
+ { concurrency }
2599
+ );
2600
+ }
2601
+
2602
+ // src/orbitals/batch/batch-generator.ts
2603
+ async function generateOrbitalsBatch(client, orbitals, options = {}) {
2604
+ const startTime = Date.now();
2605
+ const aggregateLogs = [];
2606
+ const provider = client.getProvider();
2607
+ const mode = options.mode || "single-call";
2608
+ const maxConcurrency = options.concurrency ?? PROVIDER_CONCURRENCY_LIMITS[provider];
2609
+ const maxBatchSize = options.batchSize ?? PROVIDER_BATCH_SIZES[provider];
2610
+ console.log(`[BatchGenerator] Starting batch generation: ${orbitals.length} orbitals, mode=${mode}, concurrency=${maxConcurrency}`);
2611
+ aggregateLogs.push(createLog("info", `Starting batch generation`, {
2612
+ totalOrbitals: orbitals.length,
2613
+ mode,
2614
+ provider,
2615
+ maxConcurrency,
2616
+ maxBatchSize
2617
+ }));
2618
+ const batches = splitIntoBatches(orbitals, {
2619
+ maxBatchSize,
2620
+ preserveRelationships: options.preserveRelationships ?? true
2621
+ });
2622
+ console.log(`[BatchGenerator] Split into ${batches.length} batches: [${batches.map((b) => b.length).join(", ")}]`);
2623
+ aggregateLogs.push(createLog("info", `Split into ${batches.length} batches`, {
2624
+ batchSizes: batches.map((b) => b.length)
2625
+ }));
2626
+ options.onBatchProgress?.({
2627
+ type: "batch_start",
2628
+ batchIndex: 0,
2629
+ totalBatches: batches.length,
2630
+ completedOrbitals: 0,
2631
+ totalOrbitals: orbitals.length
2632
+ });
2633
+ let batchResults;
2634
+ if (mode === "parallel-individual") {
2635
+ batchResults = await generateParallelIndividual(client, orbitals, {
2636
+ ...options,
2637
+ concurrency: maxConcurrency,
2638
+ onBatchProgress: options.onBatchProgress
2639
+ });
2640
+ } else if (mode === "single-call") {
2641
+ batchResults = await generateSingleCallBatches(client, batches, {
2642
+ ...options,
2643
+ concurrency: maxConcurrency,
2644
+ onBatchProgress: options.onBatchProgress
2645
+ });
2646
+ } else {
2647
+ batchResults = await generateAdaptive(client, orbitals, batches, {
2648
+ ...options,
2649
+ concurrency: maxConcurrency,
2650
+ maxBatchSize,
2651
+ onBatchProgress: options.onBatchProgress
2652
+ });
2653
+ }
2654
+ const totalDurationMs = Date.now() - startTime;
2655
+ const allResults = batchResults.flatMap((b) => b.results);
2656
+ const successful = allResults.filter((r) => r.success).length;
2657
+ const failed = allResults.length - successful;
2658
+ const totalTokens = batchResults.reduce(
2659
+ (sum, b) => sum + (b.usage?.totalTokens ?? 0),
2660
+ 0
2661
+ );
2662
+ console.log(`[BatchGenerator] Complete: ${successful}/${allResults.length} successful, ${totalTokens} tokens, ${totalDurationMs}ms`);
2663
+ aggregateLogs.push(createLog("info", `Batch generation completed`, {
2664
+ totalDurationMs,
2665
+ successful,
2666
+ failed,
2667
+ totalTokens,
2668
+ totalBatches: batches.length
2669
+ }));
2670
+ options.onBatchProgress?.({
2671
+ type: "batch_complete",
2672
+ batchIndex: batches.length - 1,
2673
+ totalBatches: batches.length,
2674
+ completedOrbitals: successful,
2675
+ totalOrbitals: orbitals.length
2676
+ });
2677
+ return {
2678
+ results: allResults.map((r) => ({
2679
+ orbital: r.orbital,
2680
+ fingerprint: "",
2681
+ // TODO: compute from orbital
2682
+ usedTemplate: false,
2683
+ usage: void 0,
2684
+ validation: r.success ? { valid: true, errorCount: 0, warningCount: 0 } : { valid: false, errorCount: 1, warningCount: 0 },
2685
+ logs: []
2686
+ })),
2687
+ totalDurationMs,
2688
+ aggregateLogs,
2689
+ summary: {
2690
+ total: allResults.length,
2691
+ successful,
2692
+ failed,
2693
+ totalTokens
2694
+ },
2695
+ batchResults,
2696
+ totalBatches: batches.length
2697
+ };
2698
+ }
2699
+ async function generateSingleCallBatches(client, batches, options) {
2700
+ let completedOrbitals = 0;
2701
+ const totalOrbitals = batches.reduce((sum, b) => sum + b.length, 0);
2702
+ return asyncMapWithConcurrency2(
2703
+ batches,
2704
+ async (batch, batchIndex) => {
2705
+ return generateSingleBatch(client, batch, batchIndex, {
2706
+ ...options,
2707
+ onProgress: (completedInBatch) => {
2708
+ const newCompleted = completedOrbitals + completedInBatch;
2709
+ options.onBatchProgress?.({
2710
+ type: "orbital_complete",
2711
+ batchIndex,
2712
+ totalBatches: batches.length,
2713
+ completedOrbitals: newCompleted,
2714
+ totalOrbitals
2715
+ });
2716
+ completedOrbitals = newCompleted;
2717
+ }
2718
+ });
2719
+ },
2720
+ options.concurrency
2721
+ );
2722
+ }
2723
+ async function generateParallelIndividual(client, orbitals, options) {
2724
+ const batches = orbitals.map((o) => [o]);
2725
+ return generateSingleCallBatches(client, batches, {
2726
+ ...options,
2727
+ concurrency: options.concurrency
2728
+ });
2729
+ }
2730
+ async function generateAdaptive(client, orbitals, batches, options) {
2731
+ const allFit = batches.every((batch) => willBatchFit(batch, BATCH_MAX_TOKENS));
2732
+ if (allFit) {
2733
+ console.log(`[BatchGenerator] Adaptive: Using single-call batches (${batches.length} batches)`);
2734
+ return generateSingleCallBatches(client, batches, options);
2735
+ }
2736
+ console.log(`[BatchGenerator] Adaptive: Using parallel-individual (batches too large)`);
2737
+ return generateParallelIndividual(client, orbitals, options);
2738
+ }
2739
+ async function generateSingleBatch(client, orbitals, batchIndex, options) {
2740
+ const batchStartTime = Date.now();
2741
+ const logs = [];
2742
+ console.log(`[BatchGenerator] Starting batch ${batchIndex + 1}: ${orbitals.map((o) => o.name).join(", ")}`);
2743
+ logs.push(createLog("info", `Starting batch ${batchIndex + 1}`, {
2744
+ orbitalCount: orbitals.length,
2745
+ orbitals: orbitals.map((o) => o.name)
2746
+ }));
2747
+ try {
2748
+ const batchPrompt = assembleBatchPrompt(orbitals);
2749
+ console.log(`[BatchGenerator] Batch ${batchIndex + 1} prompt assembled: ${batchPrompt.prompt.length} chars`);
2750
+ logs.push(createLog("info", `Batch prompt assembled`, {
2751
+ promptLength: batchPrompt.prompt.length,
2752
+ estimatedTokens: Math.ceil(batchPrompt.prompt.length / 4)
2753
+ }));
2754
+ const llmResult = await client.callWithMetadata({
2755
+ systemPrompt: batchPrompt.prompt,
2756
+ userPrompt: "Generate all orbitals in the batch. Return valid JSON matching the output format specified.",
2757
+ maxTokens: BATCH_MAX_TOKENS,
2758
+ skipSchemaValidation: true
2759
+ });
2760
+ logs.push(createLog("info", `LLM call completed`, {
2761
+ promptTokens: llmResult.usage?.promptTokens,
2762
+ completionTokens: llmResult.usage?.completionTokens
2763
+ }));
2764
+ const parsed = parseBatchResult(llmResult.data, orbitals);
2765
+ console.log(`[BatchGenerator] Batch ${batchIndex + 1} parsed: ${parsed.filter((p) => p.success).length}/${parsed.length} successful`);
2766
+ for (let i = 0; i < parsed.length; i++) {
2767
+ options.onProgress?.(i + 1);
2768
+ }
2769
+ const durationMs = Date.now() - batchStartTime;
2770
+ logs.push(createLog("info", `Batch ${batchIndex + 1} completed`, {
2771
+ durationMs,
2772
+ successful: parsed.filter((r) => r.success).length
2773
+ }));
2774
+ return {
2775
+ orbitals,
2776
+ results: parsed,
2777
+ usage: llmResult.usage ?? void 0,
2778
+ durationMs,
2779
+ logs
2780
+ };
2781
+ } catch (error) {
2782
+ const errorMessage = getErrorMessage(error);
2783
+ console.error(`[BatchGenerator] Batch ${batchIndex + 1} FAILED: ${errorMessage}`);
2784
+ logs.push(createLog("error", `Batch ${batchIndex + 1} failed`, {
2785
+ error: errorMessage
2786
+ }));
2787
+ return {
2788
+ orbitals,
2789
+ results: orbitals.map((o) => ({
2790
+ orbital: o,
2791
+ success: false,
2792
+ error: errorMessage
2793
+ })),
2794
+ durationMs: Date.now() - batchStartTime,
2795
+ logs
2796
+ };
2797
+ }
2798
+ }
2799
+ function parseBatchResult(data, expectedOrbitals) {
2800
+ if (!data || typeof data !== "object") {
2801
+ return expectedOrbitals.map((o) => ({
2802
+ orbital: o,
2803
+ success: false,
2804
+ error: "Invalid response: expected object"
2805
+ }));
2806
+ }
2807
+ const obj = data;
2808
+ if (!obj.orbitals || !Array.isArray(obj.orbitals)) {
2809
+ return expectedOrbitals.map((o) => ({
2810
+ orbital: o,
2811
+ success: false,
2812
+ error: "Invalid response: missing orbitals array"
2813
+ }));
2814
+ }
2815
+ const results = obj.orbitals;
2816
+ return expectedOrbitals.map((expected, index) => {
2817
+ const result = results[index];
2818
+ if (!result) {
2819
+ return {
2820
+ orbital: expected,
2821
+ success: false,
2822
+ error: `Missing result for orbital ${index + 1}`
2823
+ };
2824
+ }
2825
+ if (!result.name) {
2826
+ return {
2827
+ orbital: expected,
2828
+ success: false,
2829
+ error: "Generated orbital missing name"
2830
+ };
2831
+ }
2832
+ return {
2833
+ orbital: result,
2834
+ success: true
2835
+ };
2836
+ });
2837
+ }
2838
+
2839
+ // src/tools/orbital-batch-subagent.ts
2840
+ var OrbitalBatchInputSchema = z.object({
2841
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2842
+ orbitals: z.array(z.any()).describe("Array of OrbitalUnits to generate"),
2843
+ options: z.object({
2844
+ mode: z.enum(["single-call", "parallel-individual", "adaptive"]).optional().default("adaptive"),
2845
+ batchSize: z.number().optional(),
2846
+ maxConcurrency: z.number().optional(),
2847
+ preserveRelationships: z.boolean().optional().default(true)
2848
+ }).optional().describe("Batch generation options")
2849
+ });
2850
+ function createOrbitalBatchSubagentTool(options = {}) {
2851
+ let eventCallback = options.onSubagentEvent;
2852
+ let completeCallback = options.onBatchComplete;
2853
+ const requirements = options.requirements;
2854
+ const workDir = options.workDir;
2855
+ const setEventCallback = (callback) => {
2856
+ eventCallback = callback;
2857
+ };
2858
+ const setBatchCompleteCallback = (callback) => {
2859
+ completeCallback = callback;
2860
+ };
2861
+ const emitEvent = (orbitalName, orbitalIndex, totalOrbitals, type, data) => {
2862
+ if (eventCallback) {
2863
+ eventCallback(orbitalName, orbitalIndex, totalOrbitals, {
2864
+ type,
2865
+ data,
2866
+ timestamp: Date.now()
2867
+ });
2868
+ }
2869
+ };
2870
+ const batchTool = tool(
2871
+ async ({ orbitals, options: batchOptions }) => {
2872
+ if (!orbitals || orbitals.length === 0) {
2873
+ return JSON.stringify({
2874
+ success: false,
2875
+ error: "No orbitals provided for batch generation.",
2876
+ orbitals: []
2877
+ });
2878
+ }
2879
+ console.log(`[OrbitalBatchSubagent] Starting batch generation for ${orbitals.length} orbitals`);
2880
+ try {
2881
+ emitEvent("batch", 0, 1, "message", {
2882
+ content: `Starting batch generation for ${orbitals.length} orbitals`,
2883
+ role: "assistant",
2884
+ isComplete: false
2885
+ });
2886
+ emitEvent("batch", 0, 1, "todo_update", {
2887
+ todos: orbitals.map((o, i) => ({
2888
+ id: `orbital-${i}`,
2889
+ task: `Generate ${o.name}`,
2890
+ status: "pending"
2891
+ }))
2892
+ });
2893
+ const client = new LLMClient({
2894
+ provider: options.provider || "anthropic",
2895
+ model: options.model || "claude-sonnet-4-20250514"
2896
+ });
2897
+ const generationOptions = {
2898
+ mode: batchOptions?.mode || "adaptive",
2899
+ batchSize: batchOptions?.batchSize,
2900
+ concurrency: batchOptions?.maxConcurrency ?? PROVIDER_CONCURRENCY_LIMITS[client.getProvider()],
2901
+ preserveRelationships: batchOptions?.preserveRelationships ?? true,
2902
+ requirements,
2903
+ onBatchProgress: (event) => {
2904
+ if (event.type === "orbital_complete" && event.orbitalName) {
2905
+ emitEvent(event.orbitalName || "batch", event.batchIndex, event.totalBatches, "todo_update", {
2906
+ todos: orbitals.map((o, i) => ({
2907
+ id: `orbital-${i}`,
2908
+ task: `Generate ${o.name}`,
2909
+ status: o.name === event.orbitalName ? "completed" : event.completedOrbitals > i ? "completed" : "pending"
2910
+ }))
2911
+ });
2912
+ }
2913
+ emitEvent(event.orbitalName || "batch", event.batchIndex, event.totalBatches, "generation_log", {
2914
+ level: "info",
2915
+ message: `Progress: ${event.completedOrbitals}/${event.totalOrbitals} orbitals complete`,
2916
+ data: {
2917
+ batchIndex: event.batchIndex,
2918
+ completedOrbitals: event.completedOrbitals,
2919
+ totalOrbitals: event.totalOrbitals
2920
+ }
2921
+ });
2922
+ }
2923
+ };
2924
+ emitEvent("batch", 0, 1, "tool_call", {
2925
+ tool: "generateOrbitalsBatch",
2926
+ args: {
2927
+ orbitalCount: orbitals.length,
2928
+ mode: generationOptions.mode,
2929
+ concurrency: generationOptions.concurrency
2930
+ }
2931
+ });
2932
+ const result = await generateOrbitalsBatch(client, orbitals, generationOptions);
2933
+ emitEvent("batch", result.totalBatches - 1, result.totalBatches, "todo_update", {
2934
+ todos: orbitals.map((o, i) => ({
2935
+ id: `orbital-${i}`,
2936
+ task: `Generate ${o.name}`,
2937
+ status: result.batchResults.some(
2938
+ (b) => b.results.some((r) => r.orbital.name === o.name && r.success)
2939
+ ) ? "completed" : "failed"
2940
+ }))
2941
+ });
2942
+ const generatedOrbitals = result.results.filter((r) => r.orbital).map((r) => r.orbital);
2943
+ const successCount = generatedOrbitals.length;
2944
+ const failedCount = orbitals.length - successCount;
2945
+ emitEvent("batch", result.totalBatches - 1, result.totalBatches, "message", {
2946
+ content: `Batch generation complete: ${successCount}/${orbitals.length} orbitals generated successfully`,
2947
+ role: "assistant",
2948
+ isComplete: true
2949
+ });
2950
+ if (workDir && completeCallback && generatedOrbitals.length > 0) {
2951
+ try {
2952
+ await completeCallback(generatedOrbitals, 0, 1);
2953
+ emitEvent("batch", result.totalBatches - 1, result.totalBatches, "generation_log", {
2954
+ level: "info",
2955
+ message: `Persisted ${generatedOrbitals.length} orbitals`
2956
+ });
2957
+ } catch (persistError) {
2958
+ console.error(`[OrbitalBatchSubagent] Failed to persist orbitals:`, persistError);
2959
+ emitEvent("batch", result.totalBatches - 1, result.totalBatches, "generation_log", {
2960
+ level: "warn",
2961
+ message: "Failed to persist some orbitals",
2962
+ data: { error: String(persistError) }
2963
+ });
2964
+ }
2965
+ }
2966
+ return JSON.stringify({
2967
+ success: successCount === orbitals.length,
2968
+ generated: successCount,
2969
+ failed: failedCount,
2970
+ total: orbitals.length,
2971
+ orbitals: generatedOrbitals,
2972
+ duration: result.totalDurationMs,
2973
+ totalTokens: result.summary.totalTokens,
2974
+ batches: result.totalBatches
2975
+ });
2976
+ } catch (error) {
2977
+ const errorMessage = error instanceof Error ? error.message : String(error);
2978
+ console.error(`[OrbitalBatchSubagent] Batch generation failed:`, errorMessage);
2979
+ emitEvent("batch", 0, 1, "error", {
2980
+ error: errorMessage,
2981
+ code: "BATCH_GENERATION_ERROR"
2982
+ });
2983
+ return JSON.stringify({
2984
+ success: false,
2985
+ error: errorMessage,
2986
+ orbitals: []
2987
+ });
2988
+ }
2989
+ },
2990
+ {
2991
+ name: "generate_orbitals_batch",
2992
+ description: "Generate multiple orbitals in optimized batches. MUCH FASTER than calling generate_orbital multiple times. Use this when generating 3+ orbitals. Supports parallel generation with automatic concurrency control.",
2993
+ schema: OrbitalBatchInputSchema
2994
+ }
2995
+ );
2996
+ return {
2997
+ tool: batchTool,
2998
+ setEventCallback,
2999
+ setBatchCompleteCallback
3000
+ };
3001
+ }
2136
3002
  function getTraitGenerationPrompt() {
2137
3003
  return `You are a Trait Generator for KFlow orbital schemas.
2138
3004
 
@@ -2778,282 +3644,6 @@ function createSchemaChunkingTools(workDir) {
2778
3644
  applyChunk: createApplyChunkTool(workDir)
2779
3645
  };
2780
3646
  }
2781
- var designCache = /* @__PURE__ */ new Map();
2782
- var CACHE_TTL_MS2 = 24 * 60 * 60 * 1e3;
2783
- var CACHE_VERSION2 = 1;
2784
- function generateFingerprint2(input) {
2785
- const normalized = JSON.stringify({
2786
- version: CACHE_VERSION2,
2787
- ...input
2788
- });
2789
- return crypto.createHash("sha256").update(normalized).digest("hex").slice(0, 16);
2790
- }
2791
- function getCached2(fingerprint) {
2792
- const entry = designCache.get(fingerprint);
2793
- if (!entry) return null;
2794
- if (Date.now() - entry.timestamp > CACHE_TTL_MS2) {
2795
- designCache.delete(fingerprint);
2796
- return null;
2797
- }
2798
- return entry;
2799
- }
2800
- var STATIC_DESIGN_PROMPT = null;
2801
- function getDesignSystemPrompt() {
2802
- if (!STATIC_DESIGN_PROMPT) {
2803
- const skill = generateKflowDesignSkill();
2804
- STATIC_DESIGN_PROMPT = skill.content;
2805
- }
2806
- return STATIC_DESIGN_PROMPT;
2807
- }
2808
- function getPatternRecommendations(input) {
2809
- const recContext = buildRecommendationContext({
2810
- state: input.from,
2811
- event: input.event,
2812
- slot: input.slot,
2813
- domainCategory: input.domainCategory,
2814
- entityFields: input.entityFields
2815
- });
2816
- return recommendPatterns(recContext, 8);
2817
- }
2818
- function buildDesignUserPrompt(input) {
2819
- const fieldList = input.entityFields.map((f) => {
2820
- let desc = ` - ${f.name}: ${f.type}`;
2821
- if (f.values) desc += ` (values: ${f.values.join(", ")})`;
2822
- return desc;
2823
- }).join("\n");
2824
- const hints = [];
2825
- if (input.designStyle) hints.push(`Style: ${input.designStyle}`);
2826
- if (input.flowPattern) hints.push(`Flow: ${input.flowPattern}`);
2827
- if (input.listPattern) hints.push(`List: ${input.listPattern}`);
2828
- if (input.formPattern) hints.push(`Form: ${input.formPattern}`);
2829
- if (input.detailPattern) hints.push(`Detail: ${input.detailPattern}`);
2830
- const vocab = input.vocabulary ? Object.entries(input.vocabulary).map(([k, v]) => ` ${k} \u2192 "${v}"`).join("\n") : "";
2831
- return `Design render-ui effects for this transition:
2832
-
2833
- ## Transition
2834
- - **From**: ${input.from}
2835
- - **To**: ${input.to}
2836
- - **Event**: ${input.event}
2837
- - **Slot**: ${input.slot}
2838
-
2839
- ## Entity: ${input.entityName}
2840
- ${fieldList}
2841
-
2842
- ## Domain
2843
- - **Category**: ${input.domainCategory || "business"}
2844
- ${vocab ? `- **Vocabulary**:
2845
- ${vocab}` : ""}
2846
- ${hints.length > 0 ? `- **Design Hints**: ${hints.join(", ")}` : ""}
2847
-
2848
- ${input.recommendationsSection || ""}
2849
-
2850
- ${input.existingEffects ? `## Existing Effects (enhance these)
2851
- \`\`\`json
2852
- ${JSON.stringify(input.existingEffects, null, 2)}
2853
- \`\`\`` : ""}
2854
-
2855
- Return ONLY the JSON array of render-ui effect tuples.`;
2856
- }
2857
- var DesignTransitionSchema = z.object({
2858
- from: z.string().describe('Source state name (e.g., "Browsing")'),
2859
- to: z.string().describe('Target state name (e.g., "Browsing" for self-loop, "Creating" for transition)'),
2860
- event: z.string().describe('Event name (e.g., "INIT", "CREATE", "VIEW", "EDIT", "DELETE", "SAVE", "CANCEL")'),
2861
- slot: z.string().describe('UI slot to render into: "main", "modal", "drawer", "sidebar", "overlay"'),
2862
- entityName: z.string().describe('Entity name (e.g., "Task", "Order")'),
2863
- entityFields: z.array(z.object({
2864
- name: z.string(),
2865
- type: z.string(),
2866
- values: z.array(z.string()).optional()
2867
- })).describe("Entity fields with types and optional enum values"),
2868
- domainCategory: AgentDomainCategorySchema.optional().describe("Domain category for pattern selection"),
2869
- vocabulary: z.record(z.string(), z.string()).optional().describe('Domain vocabulary mapping (e.g., { "create": "Place Order", "item": "Order" })'),
2870
- designStyle: z.enum(["minimal", "modern", "playful", "data-driven", "immersive"]).optional().describe("Visual style hint"),
2871
- flowPattern: z.enum(["hub-spoke", "master-detail", "crud-cycle", "linear", "role-based"]).optional().describe("Application flow pattern"),
2872
- listPattern: z.enum(["entity-table", "entity-cards", "entity-list"]).optional().describe("Preferred list pattern"),
2873
- formPattern: z.enum(["modal", "drawer", "page"]).optional().describe("Preferred form pattern"),
2874
- detailPattern: z.enum(["drawer", "page", "split"]).optional().describe("Preferred detail view pattern"),
2875
- existingEffects: z.array(z.any()).optional().describe("Existing render-ui effects to enhance (for refinement passes)")
2876
- });
2877
- function createDesignTransitionTool(options = {}) {
2878
- let eventCallback = options.onEvent;
2879
- const setEventCallback = (callback) => {
2880
- eventCallback = callback;
2881
- };
2882
- const emitEvent = (transitionId, type, data) => {
2883
- if (eventCallback) {
2884
- eventCallback(transitionId, {
2885
- type,
2886
- data,
2887
- timestamp: Date.now()
2888
- });
2889
- }
2890
- };
2891
- const designTransitionTool = tool(
2892
- async (input) => {
2893
- const transitionId = `${input.entityName}:${input.from}->${input.to}:${input.event}`;
2894
- const fingerprint = generateFingerprint2({
2895
- from: input.from,
2896
- to: input.to,
2897
- event: input.event,
2898
- slot: input.slot,
2899
- entityName: input.entityName,
2900
- entityFields: input.entityFields,
2901
- domainCategory: input.domainCategory,
2902
- designStyle: input.designStyle,
2903
- flowPattern: input.flowPattern,
2904
- listPattern: input.listPattern
2905
- });
2906
- try {
2907
- emitEvent(transitionId, "message", {
2908
- content: `Designing UI for ${transitionId}`,
2909
- role: "assistant",
2910
- isComplete: false
2911
- });
2912
- const cached = getCached2(fingerprint);
2913
- if (cached) {
2914
- emitEvent(transitionId, "generation_log", {
2915
- level: "info",
2916
- message: `Design cache HIT for ${transitionId}`,
2917
- data: { fingerprint }
2918
- });
2919
- return JSON.stringify({
2920
- success: true,
2921
- transitionId,
2922
- effects: cached.effects,
2923
- cached: true,
2924
- usage: cached.usage
2925
- });
2926
- }
2927
- const recommendations = getPatternRecommendations(input);
2928
- const recommendationsSection = formatRecommendationsForPrompt(recommendations);
2929
- const systemPrompt = getDesignSystemPrompt();
2930
- const userPrompt = buildDesignUserPrompt({
2931
- ...input,
2932
- recommendationsSection
2933
- });
2934
- emitEvent(transitionId, "tool_call", {
2935
- tool: "llm_design_transition",
2936
- args: {
2937
- transition: transitionId,
2938
- slot: input.slot,
2939
- domain: input.domainCategory
2940
- }
2941
- });
2942
- const client = new LLMClient({
2943
- provider: "anthropic",
2944
- model: "claude-sonnet-4-20250514",
2945
- temperature: 0.1
2946
- // Slight creativity for design
2947
- });
2948
- const response = await client.callWithCache({
2949
- systemPrompt: "",
2950
- systemBlocks: [{
2951
- type: "text",
2952
- text: systemPrompt,
2953
- cache_control: { type: "ephemeral" }
2954
- }],
2955
- userPrompt,
2956
- maxTokens: 4096,
2957
- rawText: true
2958
- });
2959
- const rawText = (response.raw || String(response.data) || "").trim();
2960
- let effects;
2961
- try {
2962
- const jsonText = rawText.replace(/^```(?:json)?\n?/m, "").replace(/\n?```$/m, "").trim();
2963
- effects = JSON.parse(jsonText);
2964
- if (!Array.isArray(effects)) {
2965
- effects = [effects];
2966
- }
2967
- } catch {
2968
- return JSON.stringify({
2969
- success: false,
2970
- transitionId,
2971
- error: "Failed to parse design output as JSON",
2972
- rawOutput: rawText
2973
- });
2974
- }
2975
- const usage = {
2976
- inputTokens: response.usage?.promptTokens || 0,
2977
- outputTokens: response.usage?.completionTokens || 0,
2978
- totalTokens: response.usage?.totalTokens || 0
2979
- };
2980
- designCache.set(fingerprint, {
2981
- effects,
2982
- timestamp: Date.now(),
2983
- usage
2984
- });
2985
- emitEvent(transitionId, "tool_result", {
2986
- tool: "llm_design_transition",
2987
- result: { fingerprint, effectCount: effects.length, usage },
2988
- success: true
2989
- });
2990
- emitEvent(transitionId, "message", {
2991
- content: `Designed ${effects.length} effect(s) for ${transitionId} (${usage.totalTokens} tokens)`,
2992
- role: "assistant",
2993
- isComplete: true
2994
- });
2995
- return JSON.stringify({
2996
- success: true,
2997
- transitionId,
2998
- effects,
2999
- cached: false,
3000
- usage,
3001
- recommendedPatterns: recommendations.map((r) => r.pattern)
3002
- });
3003
- } catch (error) {
3004
- const errorMessage = error instanceof Error ? error.message : String(error);
3005
- emitEvent(transitionId, "error", {
3006
- error: errorMessage,
3007
- code: "DESIGN_TRANSITION_ERROR"
3008
- });
3009
- return JSON.stringify({
3010
- success: false,
3011
- transitionId,
3012
- error: errorMessage
3013
- });
3014
- }
3015
- },
3016
- {
3017
- name: "design_transition",
3018
- description: `Design rich render-ui effects for a single orbital transition.
3019
-
3020
- Takes the transition context (from/to state, event, entity, domain) and produces
3021
- polished render-ui effects using the full pattern catalog.
3022
-
3023
- USE THIS TOOL WHEN:
3024
- - Generating INIT transitions (always compose header + stats + content)
3025
- - Generating CREATE/EDIT transitions (form with proper fields)
3026
- - Generating VIEW transitions (detail with tabs for related entities)
3027
- - Enhancing existing render-ui effects that are too basic
3028
-
3029
- The tool uses a specialized design skill with pattern catalog, layout composition,
3030
- and domain-aware pattern selection to produce rich UI.
3031
-
3032
- RETURNS: { success, effects: [["render-ui", slot, config], ...], transitionId, usage }
3033
-
3034
- The effects array contains ONLY render-ui tuples. Non-UI effects (persist, emit, set)
3035
- are NOT included \u2014 you must preserve those from the original transition.
3036
-
3037
- INTEGRATION: After calling this tool, use extract_chunk to get the orbital,
3038
- replace the render-ui effects in the target transition (keep persist/emit/set effects),
3039
- then apply_chunk to merge back into schema.json.`,
3040
- schema: DesignTransitionSchema
3041
- }
3042
- );
3043
- return {
3044
- tool: designTransitionTool,
3045
- setEventCallback
3046
- };
3047
- }
3048
- function createDesignEventWrapper(writeEvent) {
3049
- return (transitionId, event) => {
3050
- writeEvent({
3051
- type: "subagent_event",
3052
- timestamp: Date.now(),
3053
- data: { transitionId, event }
3054
- });
3055
- };
3056
- }
3057
3647
  function createGitHubTools(config) {
3058
3648
  const { token, owner = "", repo = "", workDir } = config;
3059
3649
  const integrationConfig = {
@@ -3423,12 +4013,10 @@ function createAgentTools(workDir) {
3423
4013
  // Domain tools (now use internal functions)
3424
4014
  domainOrbitalTools: createDomainOrbitalTools({ workDir }),
3425
4015
  // Chunking tools
3426
- schemaChunking: createSchemaChunkingTools(workDir),
3427
- // Design tool
3428
- designTransition: createDesignTransitionTool()
4016
+ schemaChunking: createSchemaChunkingTools(workDir)
3429
4017
  };
3430
4018
  }
3431
4019
 
3432
- export { createAgentTools, createApplyChunkTool, createCombineSchemasTool, createConstructCombinedDomainTool, createDesignEventWrapper, createDesignTransitionTool, createDomainOrbitalTools, createExecuteTool, createExtractChunkTool, createFinishTaskTool, createGenerateOrbitalDomainTool, createGenerateSchemaTool, createGitHubTools, createGitHubToolsArray, createOrbitalSubagentTool, createQuerySchemaStructureTool, createSchemaChunkingTools, createSubagentEventWrapper, createTraitEventWrapper, createTraitSubagentTool, createValidateSchemaTool, validateCommandPaths };
4020
+ export { createAgentTools, createApplyChunkTool, createCombineSchemasTool, createConstructCombinedDomainTool, createDomainOrbitalTools, createExecuteTool, createExtractChunkTool, createFinishTaskTool, createGenerateOrbitalDomainTool, createGenerateSchemaTool, createGitHubTools, createGitHubToolsArray, createOrbitalBatchSubagentTool, createOrbitalSubagentTool, createQuerySchemaStructureTool, createSchemaChunkingTools, createSubagentEventWrapper, createTraitEventWrapper, createTraitSubagentTool, createValidateSchemaTool, validateCommandPaths };
3433
4021
  //# sourceMappingURL=index.js.map
3434
4022
  //# sourceMappingURL=index.js.map