@almadar/agent 1.2.1 → 1.3.0
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/LICENSE +72 -0
- package/dist/agent/index.d.ts +2 -2
- package/dist/agent/index.js +83 -278
- package/dist/agent/index.js.map +1 -1
- package/dist/{index-D-Ahuo6F.d.ts → index-DNe7JzkE.d.ts} +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +84 -281
- package/dist/index.js.map +1 -1
- package/dist/{orbital-subagent-cNfTLdXQ.d.ts → orbital-subagent-CiOIu9Ax.d.ts} +25 -25
- package/dist/tools/index.d.ts +28 -257
- package/dist/tools/index.js +84 -282
- package/dist/tools/index.js.map +1 -1
- package/package.json +15 -17
package/LICENSE
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
Business Source License 1.1
|
|
2
|
+
|
|
3
|
+
Parameters
|
|
4
|
+
|
|
5
|
+
Licensor: Almadar FZE
|
|
6
|
+
Licensed Work: KFlow Builder / Almadar
|
|
7
|
+
The Licensed Work is (c) 2025-2026 Almadar FZE.
|
|
8
|
+
Additional Use Grant: You may make production use of the Licensed Work for
|
|
9
|
+
non-commercial purposes and for internal evaluation.
|
|
10
|
+
Production use for commercial purposes requires a
|
|
11
|
+
commercial license from the Licensor.
|
|
12
|
+
Change Date: 2030-02-01
|
|
13
|
+
Change License: Apache License, Version 2.0
|
|
14
|
+
|
|
15
|
+
Terms
|
|
16
|
+
|
|
17
|
+
The Licensor hereby grants you the right to copy, modify, create derivative
|
|
18
|
+
works, redistribute, and make non-production use of the Licensed Work. The
|
|
19
|
+
Licensor may make an Additional Use Grant, above, permitting limited
|
|
20
|
+
production use.
|
|
21
|
+
|
|
22
|
+
Effective on the Change Date, or the fourth anniversary of the first publicly
|
|
23
|
+
available distribution of a specific version of the Licensed Work under this
|
|
24
|
+
License, whichever comes first, the Licensor hereby grants you rights under
|
|
25
|
+
the terms of the Change License, and the rights granted in the paragraph
|
|
26
|
+
above terminate.
|
|
27
|
+
|
|
28
|
+
If your use of the Licensed Work does not comply with the requirements
|
|
29
|
+
currently in effect as described in this License, you must purchase a
|
|
30
|
+
commercial license from the Licensor, its affiliated entities, or authorized
|
|
31
|
+
resellers, or you must refrain from using the Licensed Work.
|
|
32
|
+
|
|
33
|
+
All copies of the original and modified Licensed Work, and derivative works
|
|
34
|
+
of the Licensed Work, are subject to this License. This License applies
|
|
35
|
+
separately for each version of the Licensed Work and the Change Date may vary
|
|
36
|
+
for each version of the Licensed Work released by Licensor.
|
|
37
|
+
|
|
38
|
+
You must conspicuously display this License on each original or modified copy
|
|
39
|
+
of the Licensed Work. If you receive the Licensed Work in original or
|
|
40
|
+
modified form from a third party, the terms and conditions set forth in this
|
|
41
|
+
License apply to your use of that work.
|
|
42
|
+
|
|
43
|
+
Any use of the Licensed Work in violation of this License will automatically
|
|
44
|
+
terminate your rights under this License for the current and all other
|
|
45
|
+
versions of the Licensed Work.
|
|
46
|
+
|
|
47
|
+
This License does not grant you any right in any trademark or logo of
|
|
48
|
+
Licensor or its affiliates (provided that you may use a trademark or logo of
|
|
49
|
+
Licensor as expressly required by this License).
|
|
50
|
+
|
|
51
|
+
TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON
|
|
52
|
+
AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS,
|
|
53
|
+
EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF
|
|
54
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND
|
|
55
|
+
TITLE.
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved.
|
|
60
|
+
"Business Source License" is a trademark of MariaDB Corporation Ab.
|
|
61
|
+
|
|
62
|
+
ADDITIONAL TERMS:
|
|
63
|
+
|
|
64
|
+
Documentation (builder/packages/website/docs/) is licensed under CC BY 4.0.
|
|
65
|
+
|
|
66
|
+
TRADEMARKS:
|
|
67
|
+
|
|
68
|
+
"Orbital", "KFlow", "Almadar", and the Almadar logo are trademarks of
|
|
69
|
+
Almadar FZE. You may not use these trademarks without prior written
|
|
70
|
+
permission from Almadar FZE.
|
|
71
|
+
|
|
72
|
+
For licensing inquiries: licensing@almadar.io
|
package/dist/agent/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
export { E as EVENT_BUDGETS, S as SessionManager, e as SessionManagerOptions, f as Skill, g as SkillAgentOptions, h as SkillAgentResult, i as SkillLoader, j as SkillMeta, k as SkillRefLoader, m as createSkillAgent, p as getBudgetWarningMessage, q as getEventBudget, r as getInterruptConfig, t as resumeSkillAgent } from '../index-
|
|
1
|
+
export { E as EVENT_BUDGETS, S as SessionManager, e as SessionManagerOptions, f as Skill, g as SkillAgentOptions, h as SkillAgentResult, i as SkillLoader, j as SkillMeta, k as SkillRefLoader, m as createSkillAgent, p as getBudgetWarningMessage, q as getEventBudget, r as getInterruptConfig, t as resumeSkillAgent } from '../index-DNe7JzkE.js';
|
|
2
2
|
export { Command } from '@langchain/langgraph';
|
|
3
3
|
export { P as PersistenceMode, S as SessionMetadata, e as SessionRecord } from '../firestore-checkpointer-CkNKXoun.js';
|
|
4
4
|
import '@almadar/llm';
|
|
5
|
-
import '../orbital-subagent-
|
|
5
|
+
import '../orbital-subagent-CiOIu9Ax.js';
|
|
6
6
|
import '@langchain/core/tools';
|
|
7
7
|
import 'zod';
|
|
8
8
|
import '../api-types-BW_58thJ.js';
|
package/dist/agent/index.js
CHANGED
|
@@ -13,8 +13,7 @@ import * as fs4 from 'fs/promises';
|
|
|
13
13
|
import * as domain_language_star from '@almadar/core/domain-language';
|
|
14
14
|
import * as fs3 from 'fs';
|
|
15
15
|
import crypto, { randomUUID } from 'crypto';
|
|
16
|
-
import { getFullOrbitalPrompt,
|
|
17
|
-
import { formatRecommendationsForPrompt, buildRecommendationContext, recommendPatterns } from '@almadar/patterns';
|
|
16
|
+
import { getFullOrbitalPrompt, getRequirementsTraitPrompt, getKeyBehaviorsReference, getSExprQuickRef, getCommonErrorsSection, getArchitectureSection } from '@almadar/skills';
|
|
18
17
|
import { GitHubIntegration } from '@almadar/integrations';
|
|
19
18
|
import { BaseCheckpointSaver } from '@langchain/langgraph-checkpoint';
|
|
20
19
|
|
|
@@ -1051,6 +1050,77 @@ npx kflow domain:validate input.orb --verbose
|
|
|
1051
1050
|
|
|
1052
1051
|
// src/tools/finish-task.ts
|
|
1053
1052
|
var execAsync2 = promisify(exec);
|
|
1053
|
+
var PROP_CORRECTIONS = {
|
|
1054
|
+
onSubmit: "submitEvent",
|
|
1055
|
+
onCancel: "cancelEvent",
|
|
1056
|
+
headerActions: "actions",
|
|
1057
|
+
loading: "isLoading",
|
|
1058
|
+
fieldNames: "fields"
|
|
1059
|
+
};
|
|
1060
|
+
function autoCorrectProps(schema) {
|
|
1061
|
+
let corrections = 0;
|
|
1062
|
+
JSON.stringify(schema);
|
|
1063
|
+
function walkAndFix(obj) {
|
|
1064
|
+
if (Array.isArray(obj)) {
|
|
1065
|
+
return obj.map(walkAndFix);
|
|
1066
|
+
}
|
|
1067
|
+
if (obj && typeof obj === "object") {
|
|
1068
|
+
const result = {};
|
|
1069
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
1070
|
+
if (key in PROP_CORRECTIONS) {
|
|
1071
|
+
result[PROP_CORRECTIONS[key]] = walkAndFix(value);
|
|
1072
|
+
corrections++;
|
|
1073
|
+
} else {
|
|
1074
|
+
result[key] = walkAndFix(value);
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
return result;
|
|
1078
|
+
}
|
|
1079
|
+
return obj;
|
|
1080
|
+
}
|
|
1081
|
+
const fixed = walkAndFix(schema);
|
|
1082
|
+
Object.assign(schema, fixed);
|
|
1083
|
+
return corrections;
|
|
1084
|
+
}
|
|
1085
|
+
function checkCompositionQuality(schema) {
|
|
1086
|
+
const warnings = [];
|
|
1087
|
+
const orbitals = schema.orbitals;
|
|
1088
|
+
if (!Array.isArray(orbitals)) return warnings;
|
|
1089
|
+
for (const orbital of orbitals) {
|
|
1090
|
+
const orbObj = orbital;
|
|
1091
|
+
const traits = orbObj.traits;
|
|
1092
|
+
if (!Array.isArray(traits)) continue;
|
|
1093
|
+
for (const trait of traits) {
|
|
1094
|
+
const traitObj = trait;
|
|
1095
|
+
const transitions = traitObj.stateMachine?.transitions;
|
|
1096
|
+
if (!Array.isArray(transitions)) continue;
|
|
1097
|
+
for (const transition of transitions) {
|
|
1098
|
+
const trans = transition;
|
|
1099
|
+
if (trans.event !== "INIT") continue;
|
|
1100
|
+
const effects = trans.effects;
|
|
1101
|
+
if (!Array.isArray(effects)) continue;
|
|
1102
|
+
const mainRenderUIs = effects.filter(
|
|
1103
|
+
(e) => Array.isArray(e) && e[0] === "render-ui" && e[1] === "main"
|
|
1104
|
+
);
|
|
1105
|
+
if (mainRenderUIs.length > 1) {
|
|
1106
|
+
warnings.push(
|
|
1107
|
+
`\u26A0\uFE0F ${orbObj.name}/${traitObj.name} INIT has ${mainRenderUIs.length} flat render-ui calls to main. Should be a single composed stack with children.`
|
|
1108
|
+
);
|
|
1109
|
+
}
|
|
1110
|
+
if (mainRenderUIs.length === 1) {
|
|
1111
|
+
const renderPayload = mainRenderUIs[0];
|
|
1112
|
+
const payload = renderPayload[2];
|
|
1113
|
+
if (payload && payload.type !== "stack" && !payload.children) {
|
|
1114
|
+
warnings.push(
|
|
1115
|
+
`\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.`
|
|
1116
|
+
);
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
return warnings;
|
|
1123
|
+
}
|
|
1054
1124
|
async function collectOrbitalsFromDir(workDir) {
|
|
1055
1125
|
const orbitalsDir = path.join(workDir, ".orbitals");
|
|
1056
1126
|
try {
|
|
@@ -1105,6 +1175,8 @@ function createFinishTaskTool(workDir) {
|
|
|
1105
1175
|
let stats = null;
|
|
1106
1176
|
let validationResult = null;
|
|
1107
1177
|
let source = null;
|
|
1178
|
+
let propCorrections = 0;
|
|
1179
|
+
let compositionWarnings = [];
|
|
1108
1180
|
if (workDir) {
|
|
1109
1181
|
const orbitals = await collectOrbitalsFromDir(workDir);
|
|
1110
1182
|
if (orbitals.length > 0) {
|
|
@@ -1149,6 +1221,10 @@ function createFinishTaskTool(workDir) {
|
|
|
1149
1221
|
} catch {
|
|
1150
1222
|
}
|
|
1151
1223
|
}
|
|
1224
|
+
if (combinedSchema) {
|
|
1225
|
+
propCorrections = autoCorrectProps(combinedSchema);
|
|
1226
|
+
compositionWarnings = checkCompositionQuality(combinedSchema);
|
|
1227
|
+
}
|
|
1152
1228
|
if (combinedSchema) {
|
|
1153
1229
|
const schemaPath = path.join(workDir, "schema.json");
|
|
1154
1230
|
await fs4.writeFile(schemaPath, JSON.stringify(combinedSchema, null, 2));
|
|
@@ -1168,6 +1244,10 @@ function createFinishTaskTool(workDir) {
|
|
|
1168
1244
|
errorCount: validationResult.errors?.length || 0,
|
|
1169
1245
|
warningCount: validationResult.warnings?.length || 0
|
|
1170
1246
|
} : void 0,
|
|
1247
|
+
designQuality: {
|
|
1248
|
+
propCorrections: propCorrections || 0,
|
|
1249
|
+
compositionWarnings: compositionWarnings || []
|
|
1250
|
+
},
|
|
1171
1251
|
schemaPath: combinedSchema ? path.join(workDir, "schema.json") : input.schemaPath,
|
|
1172
1252
|
nextAction: "NONE - Task is complete. Output a brief success message to the user."
|
|
1173
1253
|
};
|
|
@@ -2328,273 +2408,6 @@ function createSchemaChunkingTools(workDir) {
|
|
|
2328
2408
|
applyChunk: createApplyChunkTool(workDir)
|
|
2329
2409
|
};
|
|
2330
2410
|
}
|
|
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
2411
|
function createGitHubTools(config) {
|
|
2599
2412
|
const { token, owner = "", repo = "", workDir } = config;
|
|
2600
2413
|
const integrationConfig = {
|
|
@@ -3814,11 +3627,9 @@ ${skillContents}`;
|
|
|
3814
3627
|
const validateSchemaTool = createValidateSchemaTool(workDir);
|
|
3815
3628
|
const ORBITAL_SKILLS = ["kflow-orbitals", "kflow-orbital-games", "kflow-orbital-fixing"];
|
|
3816
3629
|
const LEAN_SKILLS = ["kflow-lean-orbitals", "kflow-lean-fixing"];
|
|
3817
|
-
const DESIGN_SKILLS = ["kflow-design", "kflow-lean-design"];
|
|
3818
3630
|
const isOrbitalSkill = primarySkill.name === "kflow-orbitals";
|
|
3819
3631
|
const isLeanSkill = LEAN_SKILLS.includes(primarySkill.name);
|
|
3820
|
-
const
|
|
3821
|
-
const needsChunkingTools = ORBITAL_SKILLS.includes(primarySkill.name) || isDesignSkill;
|
|
3632
|
+
const needsChunkingTools = ORBITAL_SKILLS.includes(primarySkill.name);
|
|
3822
3633
|
let orbitalTool;
|
|
3823
3634
|
let setOrbitalEventCallback;
|
|
3824
3635
|
let setOrbitalCompleteCallback;
|
|
@@ -3844,11 +3655,6 @@ ${skillContents}`;
|
|
|
3844
3655
|
console.log(`[SkillAgent] Domain orbital tools enabled for ${primarySkill.name} skill`);
|
|
3845
3656
|
}
|
|
3846
3657
|
}
|
|
3847
|
-
const needsDesignTool = isDesignSkill || ORBITAL_SKILLS.includes(primarySkill.name);
|
|
3848
|
-
const designTool = needsDesignTool ? createDesignTransitionTool() : null;
|
|
3849
|
-
if (designTool && verbose) {
|
|
3850
|
-
console.log(`[SkillAgent] Design transition tool enabled for ${primarySkill.name} skill`);
|
|
3851
|
-
}
|
|
3852
3658
|
const githubTools = options.githubConfig ? createGitHubToolsArray({
|
|
3853
3659
|
token: options.githubConfig.token,
|
|
3854
3660
|
owner: options.githubConfig.owner,
|
|
@@ -3872,7 +3678,6 @@ ${skillContents}`;
|
|
|
3872
3678
|
chunkingTools.extractChunk,
|
|
3873
3679
|
chunkingTools.applyChunk
|
|
3874
3680
|
] : [],
|
|
3875
|
-
...designTool ? [designTool.tool] : [],
|
|
3876
3681
|
...githubTools || []
|
|
3877
3682
|
];
|
|
3878
3683
|
const checkpointer = sessions.getCheckpointer(threadId);
|