refs = new HashMap<>();
+ refs.put("spring-trends", "https://fashion-industry.com/reports/2025-spring-summer-trends.pdf");
+ refs.put("buying-guide", "https://fashion-industry.com/guides/clothing-buyer-handbook.pdf");
+ // ... more references
+ return refs;
+ }
+}
+```
+
+### 2. LLM Invocation Flow
+
+1. **User Question**: "Show me the spring trends report"
+2. **AI Intent Recognition**: Need to load fashion-guide's spring-trends reference
+3. **Tool Invocation**: `loadSkillReference("fashion-guide", "spring-trends")`
+4. **Framework Processing**:
+ - Check if fashion-guide skill exists
+ - Check if it supports ReferencesLoader
+ - Call `skill.as(ReferencesLoader.class).getReferences()`
+ - Return the link for `spring-trends`
+5. **Return Result**: "https://fashion-industry.com/reports/2025-spring-summer-trends.pdf"
+
+### 3. System Prompt Guidance
+
+The system prompt explicitly tells the AI how to use references:
+
+```
+**IMPORTANT: Fashion Guide Skill has Reference Materials**
+When users ask about:
+- "spring trends report" or "summer trends"
+- "buying guide" or "color trends"
+- "style guide" or any fashion reference materials
+
+You should:
+1. First use getTrendOverview tool for a quick summary
+2. Then use loadSkillReference tool to get the actual document link
+ Example: loadSkillReference("fashion-guide", "spring-trends")
+3. Provide the reference link to the user
+```
+
+## Technical Details
+
+### Automatic References Support
+
+Because `FashionGuideSkill` uses the `@SkillReferences` annotation, the framework automatically:
+
+1. **Annotation Scanning**: `AnnotationDrivenSkill` scans `@SkillReferences` methods
+2. **Dynamic Proxy**: Creates dynamic proxy for `ReferencesLoader` interface
+3. **Support Check**: `skill.supports(ReferencesLoader.class)` returns `true`
+4. **Capability Conversion**: `skill.as(ReferencesLoader.class)` returns proxy instance
+
+### SimpleSkillLoaderTool
+
+Provides two tools for LLM:
+
+1. `loadSkillContent(skillName)` - Load Skill content
+2. `loadSkillReference(skillName, referenceKey)` - Load specific reference material
+
+## Comparison with Other Skills
+
+| Skill | Has References | Description |
+|-------|----------------|-------------|
+| Inventory Management | ā | Provides tools, no references |
+| Pricing Analysis | ā | Provides tools, no references |
+| Supplier Catalog | ā | Provides tools, no references |
+| Sales Trends | ā | Provides tools, no references |
+| Weather | ā | Provides tools, no references |
+| **Fashion Guide** | ā
| **Provides tools + references** |
+| Purchase Strategy | ā | Provides tools, no references |
+
+## Best Practices
+
+### 1. Clear Reference Key Naming
+
+```java
+// ā
Good naming
+refs.put("spring-trends", "...");
+refs.put("buying-guide", "...");
+refs.put("color-trends", "...");
+
+// ā Poor naming
+refs.put("ref1", "...");
+refs.put("doc", "...");
+```
+
+### 2. Document in Skill Content
+
+```java
+@SkillContent
+public String content() {
+ return """
+ ## Reference Materials Available
+ - spring-trends: Spring/Summer fashion trend report
+ - buying-guide: Clothing buying guide
+ ...
+ """;
+}
+```
+
+### 3. System Prompt Guidance
+
+Explicitly tell the AI when and how to use `loadSkillReference`.
+
+## Summary
+
+By adding the Fashion Guide Skill to the Clothing Store Example, we demonstrate:
+
+1. ā
How to use the `@SkillReferences` annotation
+2. ā
How to load reference materials via LLM tools
+3. ā
How to design questions to trigger reference loading
+4. ā
How to integrate references functionality in real scenarios
+
+This design fully aligns with the framework's extensibility architecture, providing Skills with rich reference material support capabilities.
diff --git a/skill/src/main/java/com/examples/clothing/skills/FashionGuideSkill.java b/skill/src/main/java/com/examples/clothing/skills/FashionGuideSkill.java
new file mode 100644
index 0000000..7f75d9c
--- /dev/null
+++ b/skill/src/main/java/com/examples/clothing/skills/FashionGuideSkill.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2026 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.examples.clothing.skills;
+
+
+import org.springframework.ai.skill.annotation.Skill;
+import org.springframework.ai.skill.annotation.SkillContent;
+import org.springframework.ai.skill.annotation.SkillInit;
+import org.springframework.ai.skill.capability.SkillReferences;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Fashion Guide Skill
+ *
+ * Provides fashion trends, industry guides, and style recommendations for clothing stores.
+ * Includes extensive reference material links to help store owners stay informed about latest fashion dynamics.
+ *
+ *
Key Features:
+ *
+ * - Provides current season fashion trend overview
+ * - Provides detailed reference material links (via @SkillReferences)
+ * - Helps stores understand market dynamics
+ *
+ *
+ * Reference Materials:
+ *
+ * - spring-trends - Spring fashion trend report
+ * - summer-trends - Summer fashion trend report
+ * - buying-guide - Clothing purchase guide
+ * - color-trends - Seasonal color trend guide
+ * - style-guide - Style and outfit recommendations
+ *
+ *
+ * @author Semir
+ */
+@Skill(
+ name = "fashion-guide",
+ description = "Provides fashion trends, industry guides, and style recommendations for clothing stores",
+ source = "example")
+public class FashionGuideSkill {
+
+ @SkillContent
+ public String content() {
+ return """
+ # Fashion Guide Skill
+
+ I provide comprehensive industry guidance for clothing store owners.
+
+ ## What I Can Help With
+
+ 1. **Reference Materials** - Access detailed reports and guides
+ 2. **Market Insights** - Stay updated with industry dynamics
+
+ ## How to Use
+
+ ### Access Detailed References
+ I provide extensive reference materials that you can access using the `loadSkillReference` tool:
+
+ - **spring-trends**: Detailed Spring/Summer fashion trend report
+ - **summer-trends**: Summer seasonal trend analysis
+ - **buying-guide**: Comprehensive clothing buying guide
+ - **color-trends**: Current season's popular color palette
+ - **style-guide**: Style and outfit recommendations
+
+ ### Example Questions
+ - "Show me the spring trends report" (triggers reference loading)
+ - "Where can I find the buying guide?" (triggers reference loading)
+ - "Give me the color trends document" (triggers reference loading)
+
+ ## Tips
+ - Check trend overview first for a quick understanding
+ - Use reference materials for detailed analysis
+ - Combine with inventory and sales data for better decisions
+ """;
+ }
+
+ /**
+ * Provides fashion reference material links
+ *
+ * These links point to detailed fashion trend reports, buying guides, and style recommendation documents.
+ * LLM can load these materials through the loadSkillReference tool.
+ */
+ @SkillReferences
+ public Map references() {
+ Map refs = new HashMap<>();
+
+ // Seasonal trend reports
+ refs.put("spring-trends", "https://fashion-industry.com/reports/2025-spring-summer-trends.pdf");
+ refs.put("summer-trends", "https://fashion-industry.com/reports/2025-summer-seasonal-analysis.pdf");
+
+ // Buying guide
+ refs.put("buying-guide", "https://fashion-industry.com/guides/clothing-buyer-handbook.pdf");
+
+ // Color trends
+ refs.put("color-trends", "https://fashion-industry.com/trends/2025-color-palette.pdf");
+
+ // Style guide
+ refs.put("style-guide", "https://fashion-industry.com/guides/style-outfit-recommendations.pdf");
+
+ // Industry report
+ refs.put("market-report", "https://fashion-industry.com/reports/q1-2025-market-analysis.pdf");
+
+ // Sustainable fashion guide
+ refs.put("sustainability-guide", "https://fashion-industry.com/guides/sustainable-fashion-practices.pdf");
+
+ return refs;
+ }
+
+ @SkillInit
+ public static FashionGuideSkill create() {
+ return new FashionGuideSkill();
+ }
+}
diff --git a/skill/src/main/java/com/examples/clothing/skills/InventorySkill.java b/skill/src/main/java/com/examples/clothing/skills/InventorySkill.java
new file mode 100644
index 0000000..a54d3b9
--- /dev/null
+++ b/skill/src/main/java/com/examples/clothing/skills/InventorySkill.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2026 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.examples.clothing.skills;
+
+import org.springframework.ai.skill.annotation.Skill;
+import org.springframework.ai.skill.annotation.SkillContent;
+import org.springframework.ai.skill.annotation.SkillInit;
+import java.util.List;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.ai.skill.annotation.SkillTools;
+import org.springframework.ai.support.ToolCallbacks;
+import org.springframework.ai.tool.ToolCallback;
+import org.springframework.ai.tool.annotation.Tool;
+
+/**
+ * Inventory Management Skill
+ *
+ * Provides store inventory querying functionality
+ *
+ * @author Semir
+ */
+@Skill(
+ name = "inventory",
+ description = "Inventory management system for checking current stock levels of clothing items",
+ source = "example",
+ extensions = {"version=1.0.0", "category=retail"})
+public class InventorySkill {
+
+ private static final Logger logger = LoggerFactory.getLogger(InventorySkill.class);
+
+ private InventorySkill() {}
+
+ @SkillInit
+ public static InventorySkill create() {
+ return new InventorySkill();
+ }
+
+ @SkillContent
+ public String content() {
+ return """
+ # Inventory Management Skill
+
+ Check current stock levels for all clothing categories in the store.
+
+ ## Features
+
+ - View current inventory by category
+ - Check stock levels and sizes
+ - Identify low-stock items
+ - Get inventory summary
+
+ ## Available Tools
+
+ - `checkInventory` - Check current inventory for a specific category or all categories
+
+ ## Usage
+
+ Ask questions like:
+ - "What's the current inventory for winter coats?"
+ - "Show me all inventory"
+ - "Which items are low in stock?"
+ """;
+ }
+
+ @SkillTools
+ public List tools() {
+ return List.of(ToolCallbacks.from(this));
+ }
+
+ @Tool(
+ description =
+ "Check current inventory levels. Use category parameter to filter by clothing type (e.g., 'coat', 'sweater', 'jeans', 'dress', 'all'). Returns current stock count, sizes available, and stock status.")
+ public String checkInventory(String category) {
+ logger.info("checkInventory called with category={}", category);
+ System.out.println(String.format("[TOOL] checkInventory called with category=%s", category));
+
+ StringBuilder result = new StringBuilder();
+ result.append("# Current Inventory Report\n\n");
+ result.append(String.format("**Category**: %s\n", category));
+ result.append(String.format("**Report Date**: %s\n\n", java.time.LocalDate.now()));
+
+ if (category.equalsIgnoreCase("all") || category.equalsIgnoreCase("coat")) {
+ result.append("## Winter Coats\n");
+ result.append("- **SKU**: COAT-001\n");
+ result.append("- **Current Stock**: 15 units\n");
+ result.append("- **Sizes**: S(3), M(5), L(4), XL(3)\n");
+ result.append("- **Status**: ā ļø Low Stock\n");
+ result.append("- **Retail Price**: $120/unit\n\n");
+ }
+
+ if (category.equalsIgnoreCase("all") || category.equalsIgnoreCase("sweater")) {
+ result.append("## Sweaters\n");
+ result.append("- **SKU**: SWTR-001\n");
+ result.append("- **Current Stock**: 45 units\n");
+ result.append("- **Sizes**: S(10), M(15), L(12), XL(8)\n");
+ result.append("- **Status**: ā
Good Stock\n");
+ result.append("- **Retail Price**: $65/unit\n\n");
+ }
+
+ if (category.equalsIgnoreCase("all") || category.equalsIgnoreCase("jeans")) {
+ result.append("## Jeans\n");
+ result.append("- **SKU**: JEAN-001\n");
+ result.append("- **Current Stock**: 8 units\n");
+ result.append("- **Sizes**: 28(1), 30(2), 32(3), 34(2)\n");
+ result.append("- **Status**: š“ Critical - Restock Needed\n");
+ result.append("- **Retail Price**: $80/unit\n\n");
+ }
+
+ if (category.equalsIgnoreCase("all") || category.equalsIgnoreCase("dress")) {
+ result.append("## Dresses\n");
+ result.append("- **SKU**: DRSS-001\n");
+ result.append("- **Current Stock**: 25 units\n");
+ result.append("- **Sizes**: S(8), M(10), L(5), XL(2)\n");
+ result.append("- **Status**: ā
Good Stock\n");
+ result.append("- **Retail Price**: $95/unit\n\n");
+ }
+
+ if (category.equalsIgnoreCase("all") || category.equalsIgnoreCase("shirt")) {
+ result.append("## Shirts\n");
+ result.append("- **SKU**: SHRT-001\n");
+ result.append("- **Current Stock**: 12 units\n");
+ result.append("- **Sizes**: S(2), M(4), L(4), XL(2)\n");
+ result.append("- **Status**: ā ļø Low Stock\n");
+ result.append("- **Retail Price**: $45/unit\n\n");
+ }
+
+ result.append("## Summary\n");
+ result.append("- **Total Items**: 105 units\n");
+ result.append("- **Low Stock Items**: 2 (Coats, Shirts)\n");
+ result.append("- **Critical Items**: 1 (Jeans)\n");
+ result.append("- **Action Required**: Consider restocking Jeans immediately\n");
+
+ return result.toString();
+ }
+}
diff --git a/skill/src/main/java/com/examples/clothing/skills/PricingSkill.java b/skill/src/main/java/com/examples/clothing/skills/PricingSkill.java
new file mode 100644
index 0000000..56f3b30
--- /dev/null
+++ b/skill/src/main/java/com/examples/clothing/skills/PricingSkill.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2026 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.examples.clothing.skills;
+
+
+import java.util.List;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.ai.skill.annotation.Skill;
+import org.springframework.ai.skill.annotation.SkillContent;
+import org.springframework.ai.skill.annotation.SkillInit;
+import org.springframework.ai.skill.annotation.SkillTools;
+import org.springframework.ai.support.ToolCallbacks;
+import org.springframework.ai.tool.ToolCallback;
+import org.springframework.ai.tool.annotation.Tool;
+
+/**
+ * Store Pricing Management Skill
+ *
+ * Provides store product pricing and profit margin analysis
+ *
+ * @author Semir
+ */
+@Skill(
+ name = "pricing",
+ description = "Store pricing system for checking retail prices and profit margins",
+ source = "example",
+ extensions = {"version=1.0.0", "category=retail"})
+public class PricingSkill {
+
+ private static final Logger logger = LoggerFactory.getLogger(PricingSkill.class);
+
+ private PricingSkill() {}
+
+ @SkillInit
+ public static PricingSkill create() {
+ return new PricingSkill();
+ }
+
+ @SkillContent
+ public String content() {
+ return """
+ # Pricing Management Skill
+
+ Analyze store pricing strategy and profit margins for clothing items.
+
+ ## Features
+
+ - Check retail prices by SKU
+ - Calculate profit margins
+ - Compare pricing across categories
+ - Analyze pricing competitiveness
+
+ ## Available Tools
+
+ - `getPricing` - Get detailed pricing information for specific items or categories
+
+ ## Usage
+
+ Ask questions like:
+ - "What's the pricing for winter coats?"
+ - "Show me profit margins for all items"
+ - "Get pricing for SKU COAT-001"
+ """;
+ }
+
+ @SkillTools
+ public List tools() {
+ return List.of(ToolCallbacks.from(this));
+ }
+
+ @Tool(
+ description =
+ "Get pricing information including retail price, cost, and profit margin. Use sku parameter for specific item (e.g., 'COAT-001') or category name for all items in that category (e.g., 'coat', 'sweater', 'all').")
+ public String getPricing(String skuOrCategory) {
+ logger.info("getPricing called with skuOrCategory={}", skuOrCategory);
+ System.out.println(String.format("[TOOL] getPricing called with skuOrCategory=%s", skuOrCategory));
+
+ StringBuilder result = new StringBuilder();
+ result.append("# Pricing Analysis Report\n\n");
+ result.append(String.format("**Query**: %s\n", skuOrCategory));
+ result.append(String.format("**Report Date**: %s\n\n", java.time.LocalDate.now()));
+
+ if (skuOrCategory.equalsIgnoreCase("all")
+ || skuOrCategory.equalsIgnoreCase("coat")
+ || skuOrCategory.equalsIgnoreCase("COAT-001")) {
+ result.append("## Winter Coats (COAT-001)\n");
+ result.append("- **Retail Price**: $120/unit\n");
+ result.append("- **Cost Price**: $75/unit\n");
+ result.append("- **Profit Margin**: $45 (37.5%)\n");
+ result.append("- **Recommended Price Range**: $110-$135\n");
+ result.append("- **Competitiveness**: ā
Competitive\n\n");
+ }
+
+ if (skuOrCategory.equalsIgnoreCase("all")
+ || skuOrCategory.equalsIgnoreCase("sweater")
+ || skuOrCategory.equalsIgnoreCase("SWTR-001")) {
+ result.append("## Sweaters (SWTR-001)\n");
+ result.append("- **Retail Price**: $65/unit\n");
+ result.append("- **Cost Price**: $38/unit\n");
+ result.append("- **Profit Margin**: $27 (41.5%)\n");
+ result.append("- **Recommended Price Range**: $60-$75\n");
+ result.append("- **Competitiveness**: ā
Competitive\n\n");
+ }
+
+ if (skuOrCategory.equalsIgnoreCase("all")
+ || skuOrCategory.equalsIgnoreCase("jeans")
+ || skuOrCategory.equalsIgnoreCase("JEAN-001")) {
+ result.append("## Jeans (JEAN-001)\n");
+ result.append("- **Retail Price**: $80/unit\n");
+ result.append("- **Cost Price**: $45/unit\n");
+ result.append("- **Profit Margin**: $35 (43.75%)\n");
+ result.append("- **Recommended Price Range**: $75-$90\n");
+ result.append("- **Competitiveness**: ā
Competitive\n\n");
+ }
+
+ if (skuOrCategory.equalsIgnoreCase("all")
+ || skuOrCategory.equalsIgnoreCase("dress")
+ || skuOrCategory.equalsIgnoreCase("DRSS-001")) {
+ result.append("## Dresses (DRSS-001)\n");
+ result.append("- **Retail Price**: $95/unit\n");
+ result.append("- **Cost Price**: $52/unit\n");
+ result.append("- **Profit Margin**: $43 (45.3%)\n");
+ result.append("- **Recommended Price Range**: $90-$110\n");
+ result.append("- **Competitiveness**: ā
Competitive\n\n");
+ }
+
+ if (skuOrCategory.equalsIgnoreCase("all")
+ || skuOrCategory.equalsIgnoreCase("shirt")
+ || skuOrCategory.equalsIgnoreCase("SHRT-001")) {
+ result.append("## Shirts (SHRT-001)\n");
+ result.append("- **Retail Price**: $45/unit\n");
+ result.append("- **Cost Price**: $25/unit\n");
+ result.append("- **Profit Margin**: $20 (44.4%)\n");
+ result.append("- **Recommended Price Range**: $40-$50\n");
+ result.append("- **Competitiveness**: ā
Competitive\n\n");
+ }
+
+ result.append("## Overall Pricing Analysis\n");
+ result.append("- **Average Profit Margin**: 42.5%\n");
+ result.append("- **Highest Margin**: Dresses (45.3%)\n");
+ result.append("- **Lowest Margin**: Winter Coats (37.5%)\n");
+ result.append("- **Pricing Strategy**: Premium positioning with healthy margins\n");
+
+ return result.toString();
+ }
+}
diff --git a/skill/src/main/java/com/examples/clothing/skills/PurchaseStrategySkill.java b/skill/src/main/java/com/examples/clothing/skills/PurchaseStrategySkill.java
new file mode 100644
index 0000000..f20b64e
--- /dev/null
+++ b/skill/src/main/java/com/examples/clothing/skills/PurchaseStrategySkill.java
@@ -0,0 +1,323 @@
+/*
+ * Copyright 2026 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.examples.clothing.skills;
+
+import org.springframework.ai.skill.annotation.Skill;
+import org.springframework.ai.skill.annotation.SkillContent;
+import org.springframework.ai.skill.annotation.SkillInit;
+import org.springframework.ai.skill.annotation.SkillTools;
+import java.util.List;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.ai.support.ToolCallbacks;
+import org.springframework.ai.tool.ToolCallback;
+import org.springframework.ai.tool.annotation.Tool;
+
+/**
+ * Purchase Strategy Skill
+ *
+ * Provides intelligent restocking recommendations and purchase optimization strategies
+ *
+ * @author Semir
+ */
+@Skill(
+ name = "purchase",
+ description = "Smart purchasing strategy system that provides optimized restocking recommendations",
+ source = "example",
+ extensions = {"version=1.0.0", "category=retail", "ai-powered=true"})
+public class PurchaseStrategySkill {
+
+ private static final Logger logger = LoggerFactory.getLogger(PurchaseStrategySkill.class);
+
+ private PurchaseStrategySkill() {}
+
+ @SkillInit
+ public static PurchaseStrategySkill create() {
+ return new PurchaseStrategySkill();
+ }
+
+ @SkillContent
+ public String content() {
+ return """
+ # Purchase Strategy Skill
+
+ Generate intelligent purchasing recommendations based on inventory, sales trends, and market conditions.
+
+ ## Features
+
+ - Smart restocking recommendations
+ - Budget optimization
+ - ROI analysis
+ - Seasonal planning
+ - Risk assessment
+
+ ## Available Tools
+
+ - `generatePurchaseStrategy` - Generate comprehensive purchasing strategy
+ - `optimizePurchaseOrder` - Optimize a specific purchase order for maximum ROI
+
+ ## Usage
+
+ Ask questions like:
+ - "Generate a purchase strategy for next week"
+ - "What should I order with a $10,000 budget?"
+ - "Optimize my purchase order for maximum profit"
+ """;
+ }
+
+ @SkillTools
+ public List tools() {
+ return List.of(ToolCallbacks.from(this));
+ }
+
+ @Tool(
+ description =
+ "Generate comprehensive purchase strategy based on current conditions. Parameters: budget (available budget in USD, e.g., 10000), priority (focus area: 'profit', 'volume', 'balanced', 'risk-averse'). Returns prioritized purchase recommendations with ROI projections.")
+ public String generatePurchaseStrategy(double budget, String priority) {
+ logger.info("generatePurchaseStrategy called with budget={}, priority={}", budget, priority);
+ System.out.println(String.format(
+ "[TOOL] generatePurchaseStrategy called with budget=%.2f, priority=%s", budget, priority));
+
+ StringBuilder result = new StringBuilder();
+ result.append("# Purchase Strategy Report\n\n");
+ result.append(String.format("**Available Budget**: $%.2f\n", budget));
+ result.append(String.format("**Strategy Priority**: %s\n", priority));
+ result.append(String.format("**Report Date**: %s\n\n", java.time.LocalDate.now()));
+
+ result.append("## Current Situation Analysis\n\n");
+ result.append("### Critical Findings\n");
+ result.append("- š“ **Critical Stock-out Risk**: Jeans (8 units, ~1 day left)\n");
+ result.append("- ā ļø **Low Stock Alert**: Winter Coats (15 units, ~2 days left)\n");
+ result.append("- ā ļø **Low Stock Alert**: Shirts (12 units, ~3 days left)\n");
+ result.append("- ā
**Adequate Stock**: Sweaters (45 units, ~4 days left)\n");
+ result.append("- ā
**Good Stock**: Dresses (25 units, ~2 weeks left)\n\n");
+
+ result.append("### Sales Trends\n");
+ result.append("- **Hot Sellers**: Winter Coats (+45%), Sweaters (+35%)\n");
+ result.append("- **Stable**: Jeans, Shirts\n");
+ result.append("- **Declining**: Dresses (-15%)\n\n");
+
+ result.append("## Recommended Purchase Orders\n\n");
+
+ double totalCost = 0;
+ double projectedRevenue = 0;
+
+ result.append("### Priority 1: URGENT - Jeans\n");
+ result.append("- **Supplier SKU**: SUP-JEAN-C01\n");
+ result.append("- **Recommended Quantity**: 70 units\n");
+ result.append("- **Unit Cost**: $45.00 (with 7% bulk discount: $41.85)\n");
+ result.append("- **Total Cost**: $2,929.50\n");
+ result.append("- **Expected Revenue**: $5,600 (70 units Ć $80)\n");
+ result.append("- **Projected Profit**: $2,670.50 (91% ROI)\n");
+ result.append("- **Justification**: Critical stock-out prevention, consistent demand\n");
+ result.append("- **Delivery**: 3-5 business days\n\n");
+ totalCost += 2929.50;
+ projectedRevenue += 5600;
+
+ result.append("### Priority 2: HIGH - Winter Coats\n");
+ result.append("- **Supplier SKU**: SUP-COAT-W01\n");
+ result.append("- **Recommended Quantity**: 50 units\n");
+ result.append("- **Unit Cost**: $75.00 (with 5% bulk discount: $71.25)\n");
+ result.append("- **Total Cost**: $3,562.50\n");
+ result.append("- **Expected Revenue**: $6,000 (50 units Ć $120)\n");
+ result.append("- **Projected Profit**: $2,437.50 (68% ROI)\n");
+ result.append("- **Justification**: High demand (+45%), peak season, low stock\n");
+ result.append("- **Delivery**: 3-5 business days\n\n");
+ totalCost += 3562.50;
+ projectedRevenue += 6000;
+
+ if (budget >= 8000) {
+ result.append("### Priority 3: MEDIUM - Sweaters\n");
+ result.append("- **Supplier SKU**: SUP-SWTR-W01\n");
+ result.append("- **Recommended Quantity**: 100 units\n");
+ result.append("- **Unit Cost**: $38.00 (with 8% bulk discount: $34.96)\n");
+ result.append("- **Total Cost**: $3,496.00\n");
+ result.append("- **Expected Revenue**: $6,500 (100 units Ć $65)\n");
+ result.append("- **Projected Profit**: $3,004.00 (86% ROI)\n");
+ result.append("- **Justification**: Top seller (+35%), stock sufficient for 4 days only\n");
+ result.append("- **Delivery**: 2-4 business days\n\n");
+ totalCost += 3496.00;
+ projectedRevenue += 6500;
+ }
+
+ if (budget >= 11000) {
+ result.append("### Priority 4: MEDIUM - Shirts\n");
+ result.append("- **Supplier SKU**: SUP-SHRT-C01\n");
+ result.append("- **Recommended Quantity**: 40 units\n");
+ result.append("- **Unit Cost**: $25.00\n");
+ result.append("- **Total Cost**: $1,000.00\n");
+ result.append("- **Expected Revenue**: $1,800 (40 units Ć $45)\n");
+ result.append("- **Projected Profit**: $800.00 (80% ROI)\n");
+ result.append("- **Justification**: Low stock, consistent basic item demand\n");
+ result.append("- **Delivery**: 2-3 business days\n\n");
+ totalCost += 1000.00;
+ projectedRevenue += 1800;
+ }
+
+ result.append("## Financial Summary\n\n");
+ result.append(String.format("- **Total Investment**: $%.2f\n", totalCost));
+ result.append(String.format("- **Budget Remaining**: $%.2f\n", budget - totalCost));
+ result.append(String.format("- **Budget Utilization**: %.1f%%\n", (totalCost / budget) * 100));
+ result.append(String.format("- **Projected Revenue**: $%.2f\n", projectedRevenue));
+ result.append(String.format("- **Projected Profit**: $%.2f\n", projectedRevenue - totalCost));
+ result.append(
+ String.format("- **Expected ROI**: %.1f%%\n\n", ((projectedRevenue - totalCost) / totalCost) * 100));
+
+ result.append("## Risk Assessment\n\n");
+ result.append("- **Stock-out Risk**: š“ High (Jeans critical)\n");
+ result.append("- **Over-stock Risk**: ā
Low (all orders based on demand)\n");
+ result.append("- **Weather Risk**: ā ļø Medium (winter items dependent on cold weather)\n");
+ result.append("- **Cash Flow Risk**: ā
Low (Net 30 payment terms)\n\n");
+
+ result.append("## Implementation Plan\n\n");
+ result.append("**Immediate Actions (Today)**:\n");
+ result.append("1. Place order for Jeans (70 units) - URGENT\n");
+ result.append("2. Place order for Winter Coats (50 units) - HIGH PRIORITY\n\n");
+
+ result.append("**This Week**:\n");
+ result.append("3. Monitor Sweater sales velocity\n");
+ result.append("4. Place order for Sweaters (100 units) if budget allows\n\n");
+
+ result.append("**Next Week**:\n");
+ result.append("5. Review shirt inventory after first orders arrive\n");
+ result.append("6. Adjust strategy based on actual sales data\n\n");
+
+ result.append("## Additional Recommendations\n");
+ result.append("- š” **Promotional Opportunity**: Consider 10-15% discount on Dresses to clear inventory\n");
+ result.append("- š **Inventory Target**: Maintain 7-10 days of stock for fast-moving items\n");
+ result.append("- šÆ **Focus**: Winter items are in peak demand - maximize this opportunity\n");
+ result.append("- āļø **Process**: Implement daily inventory checks during peak season\n");
+
+ return result.toString();
+ }
+
+ @Tool(
+ description =
+ "Optimize a specific purchase order for maximum ROI. Parameters: items (comma-separated list of supplier SKUs, e.g., 'SUP-COAT-W01,SUP-JEAN-C01'), quantities (comma-separated quantities matching items, e.g., '50,70'). Returns optimization suggestions including cost efficiency and profit maximization tips.")
+ public String optimizePurchaseOrder(String items, String quantities) {
+ logger.info("optimizePurchaseOrder called with items={}, quantities={}", items, quantities);
+ System.out.println(
+ String.format("[TOOL] optimizePurchaseOrder called with items=%s, quantities=%s", items, quantities));
+
+ StringBuilder result = new StringBuilder();
+ result.append("# Purchase Order Optimization\n\n");
+ result.append(String.format("**Order Date**: %s\n", java.time.LocalDate.now()));
+ result.append(String.format("**Order ID**: PO-%05d\n\n", 12345));
+
+ String[] itemArray = items.split(",");
+ String[] qtyArray = quantities.split(",");
+
+ if (itemArray.length != qtyArray.length) {
+ return "Error: Number of items and quantities must match.";
+ }
+
+ result.append("## Order Analysis\n\n");
+
+ double totalCost = 0;
+ double optimizedCost = 0;
+
+ for (int i = 0; i < itemArray.length; i++) {
+ String sku = itemArray[i].trim();
+ int qty = Integer.parseInt(qtyArray[i].trim());
+
+ result.append(String.format("### Item %d: %s\n", i + 1, sku));
+ result.append(String.format("- **Requested Quantity**: %d units\n", qty));
+
+ double unitCost;
+ int bulkThreshold;
+ double bulkDiscount;
+ int minOrder;
+
+ switch (sku.toUpperCase()) {
+ case "SUP-COAT-W01":
+ unitCost = 75.0;
+ bulkThreshold = 50;
+ bulkDiscount = 0.05;
+ minOrder = 10;
+ break;
+ case "SUP-SWTR-W01":
+ unitCost = 38.0;
+ bulkThreshold = 100;
+ bulkDiscount = 0.08;
+ minOrder = 20;
+ break;
+ case "SUP-JEAN-C01":
+ unitCost = 45.0;
+ bulkThreshold = 50;
+ bulkDiscount = 0.07;
+ minOrder = 15;
+ break;
+ case "SUP-SHRT-C01":
+ unitCost = 25.0;
+ bulkThreshold = 100;
+ bulkDiscount = 0.10;
+ minOrder = 20;
+ break;
+ case "SUP-DRSS-F01":
+ unitCost = 52.0;
+ bulkThreshold = 40;
+ bulkDiscount = 0.06;
+ minOrder = 12;
+ break;
+ default:
+ continue;
+ }
+
+ double itemCost = unitCost * qty;
+ totalCost += itemCost;
+
+ result.append(String.format("- **Unit Cost**: $%.2f\n", unitCost));
+ result.append(String.format("- **Current Total**: $%.2f\n", itemCost));
+
+ if (qty >= bulkThreshold) {
+ double discountedCost = unitCost * (1 - bulkDiscount) * qty;
+ optimizedCost += discountedCost;
+ result.append(String.format("- ā
**Bulk Discount Applied**: %.0f%% off\n", bulkDiscount * 100));
+ result.append(String.format("- **Optimized Total**: $%.2f\n", discountedCost));
+ result.append(String.format("- **Savings**: $%.2f\n\n", itemCost - discountedCost));
+ } else {
+ optimizedCost += itemCost;
+ int neededForDiscount = bulkThreshold - qty;
+ double potentialSavings = unitCost * bulkDiscount * bulkThreshold;
+ result.append(String.format(
+ "- ā ļø **Optimization Opportunity**: Order %d more units to get %.0f%% discount\n",
+ neededForDiscount, bulkDiscount * 100));
+ result.append(String.format("- **Potential Savings**: $%.2f\n\n", potentialSavings));
+ }
+ }
+
+ result.append("## Optimization Summary\n\n");
+ result.append(String.format("- **Original Cost**: $%.2f\n", totalCost));
+ result.append(String.format("- **Optimized Cost**: $%.2f\n", optimizedCost));
+ result.append(String.format("- **Total Savings**: $%.2f\n", totalCost - optimizedCost));
+ result.append(
+ String.format("- **Cost Reduction**: %.1f%%\n\n", ((totalCost - optimizedCost) / totalCost) * 100));
+
+ result.append("## Recommendations\n\n");
+ result.append("1. **Consolidate Orders**: Combine orders to reach bulk discount thresholds\n");
+ result.append("2. **Timing**: Place orders early in the week for faster delivery\n");
+ result.append("3. **Payment**: Use Net 30 terms to preserve cash flow\n");
+ result.append("4. **Shipping**: Orders over $2,000 get free shipping - optimize accordingly\n");
+ result.append("5. **Relationships**: Regular orders may qualify for additional supplier discounts\n\n");
+
+ result.append("## Next Steps\n");
+ result.append("- Review and approve optimized order\n");
+ result.append("- Contact supplier to confirm availability\n");
+ result.append("- Schedule delivery to match expected demand\n");
+
+ return result.toString();
+ }
+}
diff --git a/skill/src/main/java/com/examples/clothing/skills/SupplierSkill.java b/skill/src/main/java/com/examples/clothing/skills/SupplierSkill.java
new file mode 100644
index 0000000..7048242
--- /dev/null
+++ b/skill/src/main/java/com/examples/clothing/skills/SupplierSkill.java
@@ -0,0 +1,278 @@
+/*
+ * Copyright 2026 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.examples.clothing.skills;
+
+import org.springframework.ai.skill.annotation.Skill;
+import org.springframework.ai.skill.annotation.SkillContent;
+import org.springframework.ai.skill.annotation.SkillInit;
+import org.springframework.ai.skill.annotation.SkillTools;
+import java.util.List;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.ai.support.ToolCallbacks;
+import org.springframework.ai.tool.ToolCallback;
+import org.springframework.ai.tool.annotation.Tool;
+
+/**
+ * Supplier Management Skill
+ *
+ * Provides supplier catalog and wholesale cost querying
+ *
+ * @author Semir
+ */
+@Skill(
+ name = "supplier",
+ description = "Supplier catalog system for checking available items and wholesale costs",
+ source = "example",
+ extensions = {"version=1.0.0", "category=retail"})
+public class SupplierSkill {
+
+ private static final Logger logger = LoggerFactory.getLogger(SupplierSkill.class);
+
+ private SupplierSkill() {}
+
+ @SkillInit
+ public static SupplierSkill create() {
+ return new SupplierSkill();
+ }
+
+ @SkillContent
+ public String content() {
+ return """
+ # Supplier Catalog Skill
+
+ Access supplier inventory and wholesale pricing information.
+
+ ## Features
+
+ - Browse supplier catalog
+ - Check wholesale prices
+ - View available quantities
+ - Get delivery information
+
+ ## Available Tools
+
+ - `getSupplierCatalog` - Get supplier catalog for specific categories or all items
+ - `getSupplierQuote` - Get detailed quote including bulk discounts
+
+ ## Usage
+
+ Ask questions like:
+ - "What items are available from the supplier?"
+ - "Get supplier catalog for winter items"
+ - "Get a quote for 50 units of coats"
+ """;
+ }
+
+ @SkillTools
+ public List tools() {
+ return List.of(ToolCallbacks.from(this));
+ }
+
+ @Tool(
+ description =
+ "Get supplier catalog showing available items for purchase. Use category parameter to filter (e.g., 'winter', 'summer', 'formal', 'casual', 'all'). Returns item details, wholesale cost, minimum order quantity, and availability.")
+ public String getSupplierCatalog(String category) {
+ logger.info("getSupplierCatalog called with category={}", category);
+ System.out.println(String.format("[TOOL] getSupplierCatalog called with category=%s", category));
+
+ StringBuilder result = new StringBuilder();
+ result.append("# Supplier Catalog\n\n");
+ result.append(String.format("**Category**: %s\n", category));
+ result.append(String.format("**Catalog Date**: %s\n", java.time.LocalDate.now()));
+ result.append("**Supplier**: Fashion Wholesale Co.\n\n");
+
+ if (category.equalsIgnoreCase("all")
+ || category.toLowerCase().contains("winter")
+ || category.toLowerCase().contains("coat")) {
+ result.append("## Winter Collection\n\n");
+
+ result.append("### Premium Winter Coats\n");
+ result.append("- **Supplier SKU**: SUP-COAT-W01\n");
+ result.append("- **Wholesale Cost**: $75/unit\n");
+ result.append("- **Min Order**: 10 units\n");
+ result.append("- **Available Stock**: 500+ units\n");
+ result.append("- **Sizes**: S, M, L, XL, XXL\n");
+ result.append("- **Colors**: Black, Navy, Gray, Burgundy\n");
+ result.append("- **Delivery**: 3-5 business days\n");
+ result.append("- **Bulk Discount**: 5% off for 50+ units\n\n");
+
+ result.append("### Wool Sweaters\n");
+ result.append("- **Supplier SKU**: SUP-SWTR-W01\n");
+ result.append("- **Wholesale Cost**: $38/unit\n");
+ result.append("- **Min Order**: 20 units\n");
+ result.append("- **Available Stock**: 800+ units\n");
+ result.append("- **Sizes**: S, M, L, XL\n");
+ result.append("- **Colors**: Multiple colors available\n");
+ result.append("- **Delivery**: 2-4 business days\n");
+ result.append("- **Bulk Discount**: 8% off for 100+ units\n\n");
+ }
+
+ if (category.equalsIgnoreCase("all")
+ || category.toLowerCase().contains("casual")
+ || category.toLowerCase().contains("jeans")) {
+ result.append("## Casual Collection\n\n");
+
+ result.append("### Premium Denim Jeans\n");
+ result.append("- **Supplier SKU**: SUP-JEAN-C01\n");
+ result.append("- **Wholesale Cost**: $45/unit\n");
+ result.append("- **Min Order**: 15 units\n");
+ result.append("- **Available Stock**: 600+ units\n");
+ result.append("- **Sizes**: 28, 30, 32, 34, 36, 38\n");
+ result.append("- **Styles**: Slim fit, Regular fit, Relaxed fit\n");
+ result.append("- **Delivery**: 3-5 business days\n");
+ result.append("- **Bulk Discount**: 7% off for 50+ units\n\n");
+
+ result.append("### Cotton Shirts\n");
+ result.append("- **Supplier SKU**: SUP-SHRT-C01\n");
+ result.append("- **Wholesale Cost**: $25/unit\n");
+ result.append("- **Min Order**: 20 units\n");
+ result.append("- **Available Stock**: 1000+ units\n");
+ result.append("- **Sizes**: S, M, L, XL, XXL\n");
+ result.append("- **Colors**: White, Blue, Black, Gray\n");
+ result.append("- **Delivery**: 2-3 business days\n");
+ result.append("- **Bulk Discount**: 10% off for 100+ units\n\n");
+ }
+
+ if (category.equalsIgnoreCase("all")
+ || category.toLowerCase().contains("formal")
+ || category.toLowerCase().contains("dress")) {
+ result.append("## Formal Collection\n\n");
+
+ result.append("### Evening Dresses\n");
+ result.append("- **Supplier SKU**: SUP-DRSS-F01\n");
+ result.append("- **Wholesale Cost**: $52/unit\n");
+ result.append("- **Min Order**: 12 units\n");
+ result.append("- **Available Stock**: 400+ units\n");
+ result.append("- **Sizes**: S, M, L, XL\n");
+ result.append("- **Styles**: A-line, Bodycon, Maxi\n");
+ result.append("- **Delivery**: 4-6 business days\n");
+ result.append("- **Bulk Discount**: 6% off for 40+ units\n\n");
+ }
+
+ result.append("## Payment & Delivery Terms\n");
+ result.append("- **Payment**: Net 30 days for established customers\n");
+ result.append("- **Shipping**: Free shipping for orders over $2,000\n");
+ result.append("- **Returns**: 14-day return policy on unused items\n");
+ result.append("- **Express Delivery**: Available for urgent orders (+$50)\n");
+
+ return result.toString();
+ }
+
+ @Tool(
+ description =
+ "Get detailed quote for a specific supplier SKU with quantity. Parameters: supplierSku (e.g., 'SUP-COAT-W01'), quantity (number of units). Returns itemized quote with unit cost, bulk discounts, total cost, and delivery estimate.")
+ public String getSupplierQuote(String supplierSku, int quantity) {
+ logger.info("getSupplierQuote called with supplierSku={}, quantity={}", supplierSku, quantity);
+ System.out.println(String.format(
+ "[TOOL] getSupplierQuote called with supplierSku=%s, quantity=%d", supplierSku, quantity));
+
+ StringBuilder result = new StringBuilder();
+ result.append("# Supplier Quote\n\n");
+ result.append(String.format("**Quote ID**: QT-%05d\n", 12345));
+ result.append(String.format("**Date**: %s\n", java.time.LocalDate.now()));
+ result.append("**Supplier**: Fashion Wholesale Co.\n\n");
+
+ String itemName;
+ double basePrice;
+ int minOrder;
+ int bulkThreshold;
+ double bulkDiscount;
+
+ switch (supplierSku.toUpperCase()) {
+ case "SUP-COAT-W01":
+ itemName = "Premium Winter Coats";
+ basePrice = 75.0;
+ minOrder = 10;
+ bulkThreshold = 50;
+ bulkDiscount = 0.05;
+ break;
+ case "SUP-SWTR-W01":
+ itemName = "Wool Sweaters";
+ basePrice = 38.0;
+ minOrder = 20;
+ bulkThreshold = 100;
+ bulkDiscount = 0.08;
+ break;
+ case "SUP-JEAN-C01":
+ itemName = "Premium Denim Jeans";
+ basePrice = 45.0;
+ minOrder = 15;
+ bulkThreshold = 50;
+ bulkDiscount = 0.07;
+ break;
+ case "SUP-SHRT-C01":
+ itemName = "Cotton Shirts";
+ basePrice = 25.0;
+ minOrder = 20;
+ bulkThreshold = 100;
+ bulkDiscount = 0.10;
+ break;
+ case "SUP-DRSS-F01":
+ itemName = "Evening Dresses";
+ basePrice = 52.0;
+ minOrder = 12;
+ bulkThreshold = 40;
+ bulkDiscount = 0.06;
+ break;
+ default:
+ return String.format("Error: Supplier SKU '%s' not found in catalog.", supplierSku);
+ }
+
+ result.append(String.format("## %s (%s)\n\n", itemName, supplierSku));
+ result.append(String.format("**Quantity Requested**: %d units\n", quantity));
+
+ if (quantity < minOrder) {
+ result.append(String.format("ā ļø **Warning**: Minimum order quantity is %d units\n\n", minOrder));
+ return result.toString();
+ }
+
+ result.append(String.format("**Unit Price**: $%.2f\n", basePrice));
+
+ double discount = 0;
+ if (quantity >= bulkThreshold) {
+ discount = bulkDiscount;
+ result.append(String.format("**Bulk Discount**: %.0f%% (for %d+ units)\n", discount * 100, bulkThreshold));
+ } else {
+ result.append("**Bulk Discount**: Not applicable\n");
+ }
+
+ double discountedPrice = basePrice * (1 - discount);
+ double subtotal = discountedPrice * quantity;
+ double shipping = subtotal >= 2000 ? 0 : 80;
+ double total = subtotal + shipping;
+
+ result.append(String.format("**Discounted Price**: $%.2f/unit\n\n", discountedPrice));
+
+ result.append("## Cost Breakdown\n");
+ result.append(String.format("- Subtotal: $%.2f (%d units Ć $%.2f)\n", subtotal, quantity, discountedPrice));
+ result.append(
+ String.format("- Shipping: $%.2f %s\n", shipping, shipping == 0 ? "(Free - order over $2,000)" : ""));
+ result.append(String.format("- **Total Cost**: $%.2f\n\n", total));
+
+ result.append("## Delivery Information\n");
+ result.append("- **Estimated Delivery**: 3-5 business days\n");
+ result.append("- **Express Option**: Available (+$50 for next day)\n\n");
+
+ result.append("## Additional Information\n");
+ result.append("- **Payment Terms**: Net 30 days\n");
+ result.append("- **Valid Until**: 7 days from quote date\n");
+ result.append(String.format(
+ "- **Potential Profit**: $%.2f (if sold at retail price)\n", (120 - discountedPrice) * quantity));
+
+ return result.toString();
+ }
+}
diff --git a/skill/src/main/java/com/examples/clothing/skills/TrendSkill.java b/skill/src/main/java/com/examples/clothing/skills/TrendSkill.java
new file mode 100644
index 0000000..cf3ede8
--- /dev/null
+++ b/skill/src/main/java/com/examples/clothing/skills/TrendSkill.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright 2026 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.examples.clothing.skills;
+
+import org.springframework.ai.skill.annotation.Skill;
+import org.springframework.ai.skill.annotation.SkillContent;
+import org.springframework.ai.skill.annotation.SkillInit;
+import org.springframework.ai.skill.annotation.SkillTools;
+import java.util.List;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.ai.support.ToolCallbacks;
+import org.springframework.ai.tool.ToolCallback;
+import org.springframework.ai.tool.annotation.Tool;
+
+/**
+ * Sales Trend Analysis Skill
+ *
+ * Provides hot-selling item trends and sales data analysis
+ *
+ * @author Semir
+ */
+@Skill(
+ name = "trend",
+ description = "Sales trend analysis system for tracking popular items and market demand",
+ source = "example",
+ extensions = {"version=1.0.0", "category=retail"})
+public class TrendSkill {
+
+ private static final Logger logger = LoggerFactory.getLogger(TrendSkill.class);
+
+ private TrendSkill() {}
+
+ @SkillInit
+ public static TrendSkill create() {
+ return new TrendSkill();
+ }
+
+ @SkillContent
+ public String content() {
+ return """
+ # Sales Trend Analysis Skill
+
+ Analyze sales trends and market demand for clothing items.
+
+ ## Features
+
+ - View hot-selling items
+ - Track sales velocity
+ - Analyze seasonal trends
+ - Predict demand patterns
+
+ ## Available Tools
+
+ - `getSalesTrends` - Get current sales trends and popular items
+ - `getPredictedDemand` - Get demand predictions for upcoming period
+
+ ## Usage
+
+ Ask questions like:
+ - "What items are trending this week?"
+ - "Show me sales trends for winter items"
+ - "What's the predicted demand for next month?"
+ """;
+ }
+
+ @SkillTools
+ public List tools() {
+ return List.of(ToolCallbacks.from(this));
+ }
+
+ @Tool(
+ description =
+ "Get sales trends and popular items. Use period parameter to specify timeframe ('week', 'month', 'season'). Returns trending items, sales velocity, and market demand indicators.")
+ public String getSalesTrends(String period) {
+ logger.info("getSalesTrends called with period={}", period);
+ System.out.println(String.format("[TOOL] getSalesTrends called with period=%s", period));
+
+ StringBuilder result = new StringBuilder();
+ result.append("# Sales Trends Report\n\n");
+ result.append(String.format("**Period**: Past %s\n", period));
+ result.append(String.format("**Report Date**: %s\n\n", java.time.LocalDate.now()));
+
+ result.append("## Top Selling Items\n\n");
+
+ result.append("### 1. š„ Wool Sweaters (SWTR-001)\n");
+ result.append("- **Units Sold**: 85 units\n");
+ result.append("- **Sales Velocity**: 12 units/day\n");
+ result.append("- **Revenue**: $5,525\n");
+ result.append("- **Trend**: ā¬ļø +35% vs last period\n");
+ result.append("- **Reason**: Cold weather surge\n\n");
+
+ result.append("### 2. š„ Winter Coats (COAT-001)\n");
+ result.append("- **Units Sold**: 62 units\n");
+ result.append("- **Sales Velocity**: 9 units/day\n");
+ result.append("- **Revenue**: $7,440\n");
+ result.append("- **Trend**: ā¬ļø +45% vs last period\n");
+ result.append("- **Reason**: Winter season peak\n\n");
+
+ result.append("### 3. Jeans (JEAN-001)\n");
+ result.append("- **Units Sold**: 48 units\n");
+ result.append("- **Sales Velocity**: 7 units/day\n");
+ result.append("- **Revenue**: $3,840\n");
+ result.append("- **Trend**: ā”ļø Stable\n");
+ result.append("- **Reason**: Consistent demand\n\n");
+
+ result.append("### 4. Dresses (DRSS-001)\n");
+ result.append("- **Units Sold**: 35 units\n");
+ result.append("- **Sales Velocity**: 5 units/day\n");
+ result.append("- **Revenue**: $3,325\n");
+ result.append("- **Trend**: ā¬ļø -15% vs last period\n");
+ result.append("- **Reason**: Off-season\n\n");
+
+ result.append("### 5. Shirts (SHRT-001)\n");
+ result.append("- **Units Sold**: 28 units\n");
+ result.append("- **Sales Velocity**: 4 units/day\n");
+ result.append("- **Revenue**: $1,260\n");
+ result.append("- **Trend**: ā”ļø Stable\n");
+ result.append("- **Reason**: Basic item\n\n");
+
+ result.append("## Market Insights\n");
+ result.append("- **Hot Categories**: Winter wear (coats, sweaters)\n");
+ result.append("- **Peak Shopping Days**: Weekends and Fridays\n");
+ result.append("- **Average Transaction**: $185\n");
+ result.append("- **Customer Preference**: Quality over quantity\n\n");
+
+ result.append("## Recommendations\n");
+ result.append("- ā ļø **Action Required**: Restock winter coats immediately (high demand)\n");
+ result.append("- ā
**Sweater stock is adequate** but monitor closely\n");
+ result.append("- š **Jeans need urgent restocking** (critical low inventory)\n");
+ result.append("- š” **Consider promotion** on dresses to boost off-season sales\n");
+
+ return result.toString();
+ }
+
+ @Tool(
+ description =
+ "Get demand predictions for the next period. Use category parameter to filter predictions by clothing type (e.g., 'winter', 'casual', 'formal', 'all'). Returns forecasted demand, recommended stock levels, and confidence scores.")
+ public String getPredictedDemand(String category) {
+ logger.info("getPredictedDemand called with category={}", category);
+ System.out.println(String.format("[TOOL] getPredictedDemand called with category=%s", category));
+
+ StringBuilder result = new StringBuilder();
+ result.append("# Demand Prediction Report\n\n");
+ result.append(String.format("**Category**: %s\n", category));
+ result.append("**Forecast Period**: Next 30 days\n");
+ result.append(String.format("**Report Date**: %s\n\n", java.time.LocalDate.now()));
+
+ if (category.equalsIgnoreCase("all")
+ || category.toLowerCase().contains("winter")
+ || category.toLowerCase().contains("coat")) {
+ result.append("## Winter Coats (COAT-001)\n");
+ result.append("- **Predicted Demand**: 90-110 units\n");
+ result.append("- **Current Stock**: 15 units\n");
+ result.append("- **Recommended Order**: 80-100 units\n");
+ result.append("- **Confidence**: 92% (High)\n");
+ result.append("- **Factors**: Peak winter season, historical data\n");
+ result.append("- **Risk**: ā ļø High - Stock-out likely within 2 days\n\n");
+ }
+
+ if (category.equalsIgnoreCase("all")
+ || category.toLowerCase().contains("winter")
+ || category.toLowerCase().contains("sweater")) {
+ result.append("## Sweaters (SWTR-001)\n");
+ result.append("- **Predicted Demand**: 120-140 units\n");
+ result.append("- **Current Stock**: 45 units\n");
+ result.append("- **Recommended Order**: 80-100 units\n");
+ result.append("- **Confidence**: 88% (High)\n");
+ result.append("- **Factors**: Cold weather continuation\n");
+ result.append("- **Risk**: ā ļø Medium - Stock sufficient for 4 days\n\n");
+ }
+
+ if (category.equalsIgnoreCase("all")
+ || category.toLowerCase().contains("casual")
+ || category.toLowerCase().contains("jeans")) {
+ result.append("## Jeans (JEAN-001)\n");
+ result.append("- **Predicted Demand**: 75-85 units\n");
+ result.append("- **Current Stock**: 8 units\n");
+ result.append("- **Recommended Order**: 70-80 units\n");
+ result.append("- **Confidence**: 85% (High)\n");
+ result.append("- **Factors**: Consistent year-round demand\n");
+ result.append("- **Risk**: š“ Critical - Stock-out imminent (1 day)\n\n");
+ }
+
+ if (category.equalsIgnoreCase("all")
+ || category.toLowerCase().contains("formal")
+ || category.toLowerCase().contains("dress")) {
+ result.append("## Dresses (DRSS-001)\n");
+ result.append("- **Predicted Demand**: 40-50 units\n");
+ result.append("- **Current Stock**: 25 units\n");
+ result.append("- **Recommended Order**: 20-30 units\n");
+ result.append("- **Confidence**: 75% (Medium)\n");
+ result.append("- **Factors**: Off-season, special events\n");
+ result.append("- **Risk**: ā
Low - Stock sufficient for 2 weeks\n\n");
+ }
+
+ if (category.equalsIgnoreCase("all")
+ || category.toLowerCase().contains("casual")
+ || category.toLowerCase().contains("shirt")) {
+ result.append("## Shirts (SHRT-001)\n");
+ result.append("- **Predicted Demand**: 50-60 units\n");
+ result.append("- **Current Stock**: 12 units\n");
+ result.append("- **Recommended Order**: 40-50 units\n");
+ result.append("- **Confidence**: 82% (High)\n");
+ result.append("- **Factors**: Basic wardrobe item\n");
+ result.append("- **Risk**: ā ļø Medium - Stock sufficient for 3 days\n\n");
+ }
+
+ result.append("## Overall Forecast Summary\n");
+ result.append("- **Total Predicted Sales**: $32,000-$38,000\n");
+ result.append("- **Recommended Investment**: $18,000-$22,000\n");
+ result.append("- **Expected ROI**: 75-85%\n\n");
+
+ result.append("## Strategic Recommendations\n");
+ result.append("1. **Priority 1 (Urgent)**: Order jeans immediately to avoid stock-out\n");
+ result.append("2. **Priority 2 (High)**: Restock winter coats within 48 hours\n");
+ result.append("3. **Priority 3 (Medium)**: Order sweaters for next week\n");
+ result.append("4. **Priority 4 (Low)**: Monitor shirt sales, order if needed\n");
+ result.append("5. **Opportunity**: Dresses have low demand - consider promotional strategy\n");
+
+ return result.toString();
+ }
+}
diff --git a/skill/src/main/java/com/examples/clothing/skills/WeatherSkill.java b/skill/src/main/java/com/examples/clothing/skills/WeatherSkill.java
new file mode 100644
index 0000000..f33cace
--- /dev/null
+++ b/skill/src/main/java/com/examples/clothing/skills/WeatherSkill.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2026 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.examples.clothing.skills;
+
+import org.springframework.ai.skill.annotation.Skill;
+import org.springframework.ai.skill.annotation.SkillContent;
+import org.springframework.ai.skill.annotation.SkillInit;
+import org.springframework.ai.skill.annotation.SkillTools;
+import java.util.List;
+import java.util.Random;
+import org.springframework.ai.support.ToolCallbacks;
+import org.springframework.ai.tool.ToolCallback;
+import org.springframework.ai.tool.annotation.Tool;
+
+/**
+ * Weather Skill - Annotation-Based Example
+ *
+ * Demonstrates how to implement a Skill using annotation mode:
+ *
+ * - Pure POJO class, no interface implementation required
+ * - Use @Skill to annotate the class
+ * - Use @SkillContent to annotate the content method
+ * - Use @SkillTools to annotate the tools method
+ * - Framework automatically wraps it as SkillProxy
+ *
+ *
+ * Use Cases: General users, standard scenarios, rapid development
+ *
+ *
Notes:
+ *
+ * - Method names can be freely named (doesn't have to be getContent)
+ * - Framework identifies methods through annotations and invokes via reflection
+ * - Slightly slower than interface mode (reflection invocation), but fast enough for most scenarios
+ *
+ *
+ * @author Semir
+ */
+@Skill(
+ name = "weather",
+ description = "Provides weather information for cities around the world",
+ source = "example",
+ extensions = {"version=1.0.0", "author=Semir", "category=information"})
+public class WeatherSkill {
+
+ private final Random random = new Random();
+
+ // Simulated weather conditions
+ private static final String[] WEATHER_CONDITIONS = {
+ "Sunny", "Cloudy", "Rainy", "Snowy", "Windy", "Foggy", "Partly Cloudy"
+ };
+
+ /**
+ * Private constructor
+ */
+ private WeatherSkill() {}
+
+ /**
+ * Skill initialization method - Factory method
+ *
+ * Used for lazy loading to create WeatherSkill instance
+ */
+ @SkillInit
+ public static WeatherSkill create() {
+ return new WeatherSkill();
+ }
+
+ /**
+ * Method that returns Skill content
+ *
+ *
Method name can be freely named, framework identifies it through @SkillContent annotation
+ */
+ @SkillContent
+ public String content() {
+ return """
+ # Weather Skill
+
+ Provides weather information for cities around the world.
+
+ ## Features
+
+ - Get current weather for any city
+ - Temperature in Celsius
+ - Weather conditions (Sunny, Rainy, Cloudy, etc.)
+
+ ## Available Tools
+
+ - `getWeather(city)` - Get current weather for a specific city
+
+ ## Usage
+
+ Ask me "What's the weather in Beijing?" or "Tell me the weather in New York".
+ """;
+ }
+
+ /**
+ * Method that returns the tool list
+ *
+ *
Returns available tool callbacks, using Spring AI's ToolCallbacks utility class
+ */
+ @SkillTools
+ public List tools() {
+ // Use Spring AI's ToolCallbacks.from() to wrap @Tool annotated methods into tools
+ return List.of(ToolCallbacks.from(this));
+ }
+
+ /**
+ * Get weather information for a specified city (simulated data)
+ *
+ * This is the actual tool method called by AI, annotated with @Tool
+ *
+ * @param city City name
+ * @return Weather information as JSON string
+ */
+ @Tool(
+ description =
+ "Get current weather information for a specific city. Returns temperature in Celsius, weather condition, humidity percentage, and wind speed in km/h.")
+ public String getWeather(String city) {
+ if (city == null || city.trim().isEmpty()) {
+ return "{\"error\": \"City name is required\"}";
+ }
+
+ // Generate random temperature (-10 to 40 Celsius)
+ int temperature = random.nextInt(51) - 10;
+
+ // Randomly select weather condition
+ String condition = WEATHER_CONDITIONS[random.nextInt(WEATHER_CONDITIONS.length)];
+
+ // Generate random humidity (30% - 90%)
+ int humidity = random.nextInt(61) + 30;
+
+ // Generate random wind speed (0 - 30 km/h)
+ int windSpeed = random.nextInt(31);
+
+ // Return weather information in JSON format
+ return String.format(
+ """
+ {
+ "city": "%s",
+ "temperature": %d,
+ "unit": "Celsius",
+ "condition": "%s",
+ "humidity": %d,
+ "windSpeed": %d,
+ "windUnit": "km/h",
+ "description": "The weather in %s is %s with a temperature of %d°C, humidity at %d%%, and wind speed of %d km/h."
+ }
+ """,
+ city, temperature, condition, humidity, windSpeed, city, condition, temperature, humidity, windSpeed);
+ }
+}
diff --git a/skill/src/main/resources/logback.xml b/skill/src/main/resources/logback.xml
new file mode 100644
index 0000000..03bad50
--- /dev/null
+++ b/skill/src/main/resources/logback.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+ %d{HH:mm:ss.SSS} %highlight(%-5level) %cyan(%logger{36}) - %msg%n
+ utf-8
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+