@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.
@@ -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
  };
@@ -2778,282 +2858,6 @@ function createSchemaChunkingTools(workDir) {
2778
2858
  applyChunk: createApplyChunkTool(workDir)
2779
2859
  };
2780
2860
  }
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
2861
  function createGitHubTools(config) {
3058
2862
  const { token, owner = "", repo = "", workDir } = config;
3059
2863
  const integrationConfig = {
@@ -3423,12 +3227,10 @@ function createAgentTools(workDir) {
3423
3227
  // Domain tools (now use internal functions)
3424
3228
  domainOrbitalTools: createDomainOrbitalTools({ workDir }),
3425
3229
  // Chunking tools
3426
- schemaChunking: createSchemaChunkingTools(workDir),
3427
- // Design tool
3428
- designTransition: createDesignTransitionTool()
3230
+ schemaChunking: createSchemaChunkingTools(workDir)
3429
3231
  };
3430
3232
  }
3431
3233
 
3432
- export { createAgentTools, createApplyChunkTool, createCombineSchemasTool, createConstructCombinedDomainTool, createDesignEventWrapper, createDesignTransitionTool, createDomainOrbitalTools, createExecuteTool, createExtractChunkTool, createFinishTaskTool, createGenerateOrbitalDomainTool, createGenerateSchemaTool, createGitHubTools, createGitHubToolsArray, createOrbitalSubagentTool, createQuerySchemaStructureTool, createSchemaChunkingTools, createSubagentEventWrapper, createTraitEventWrapper, createTraitSubagentTool, createValidateSchemaTool, validateCommandPaths };
3234
+ export { createAgentTools, createApplyChunkTool, createCombineSchemasTool, createConstructCombinedDomainTool, createDomainOrbitalTools, createExecuteTool, createExtractChunkTool, createFinishTaskTool, createGenerateOrbitalDomainTool, createGenerateSchemaTool, createGitHubTools, createGitHubToolsArray, createOrbitalSubagentTool, createQuerySchemaStructureTool, createSchemaChunkingTools, createSubagentEventWrapper, createTraitEventWrapper, createTraitSubagentTool, createValidateSchemaTool, validateCommandPaths };
3433
3235
  //# sourceMappingURL=index.js.map
3434
3236
  //# sourceMappingURL=index.js.map