@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 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
@@ -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-D-Ahuo6F.js';
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-cNfTLdXQ.js';
5
+ import '../orbital-subagent-CiOIu9Ax.js';
6
6
  import '@langchain/core/tools';
7
7
  import 'zod';
8
8
  import '../api-types-BW_58thJ.js';
@@ -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, generateKflowDesignSkill, getRequirementsTraitPrompt, getKeyBehaviorsReference, getSExprQuickRef, getCommonErrorsSection, getArchitectureSection } from '@almadar/skills';
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 isDesignSkill = DESIGN_SKILLS.includes(primarySkill.name);
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);