lib/clacky/agent/skill_auto_creator.rb



# frozen_string_literal: true

module Clacky
  class Agent
    # Scenario 1: Auto-create new skills from complex task patterns.
    #
    # After completing a complex task (high iteration count, no existing skill used),
    # forks a subagent to analyze if the workflow is reusable and worth capturing
    # as a new skill.
    #
    # If the LLM determines it's valuable, it invokes skill-creator in "quick mode"
    # to generate a new skill automatically.
    module SkillAutoCreator
      # Default minimum iterations to consider auto-creating a skill.
      # This counts iterations within the current task only, not session-cumulative.
      DEFAULT_AUTO_CREATE_THRESHOLD = 12

      # Check if we should prompt the LLM to consider creating a new skill
      # Called from SkillEvolution#run_skill_evolution_hooks
      def maybe_create_skill_from_task
        return unless should_auto_create_skill?

        @ui&.show_info("Analyzing task for skill creation opportunity...")

        # Fork an isolated subagent to evaluate + create — does NOT touch main history
        subagent = fork_subagent
        subagent.run(build_skill_creation_prompt)
      end

      # Determine if this task is a candidate for skill auto-creation
      # @return [Boolean]
      private def should_auto_create_skill?
        threshold = skill_evolution_config[:auto_create_threshold] || DEFAULT_AUTO_CREATE_THRESHOLD

        # Calculate iterations within THIS TASK ONLY (not session-cumulative)
        task_iterations = @iterations - @task_start_iterations

        # Conditions (ALL must be true):
        # 1. Current task was complex enough (high iteration count within this task)
        # 2. No skill was explicitly invoked (not a skill refinement session)
        # 3. Task succeeded (not an error state)

        task_iterations >= threshold &&
          !@skill_execution_context &&
          !skill_invoked_in_history?
      end

      # Check if any skill was invoked during this task
      # Looks for invoke_skill tool calls in the conversation history
      # @return [Boolean]
      private def skill_invoked_in_history?
        @history.to_a.any? { |msg|
          msg[:role] == "assistant" &&
            msg[:tool_calls]&.any? { |tc| tc[:name] == "invoke_skill" }
        }
      end

      # Build the skill auto-creation prompt content
      # @return [String]
      private def build_skill_creation_prompt
        <<~PROMPT
          ═══════════════════════════════════════════════════════════════
          SKILL AUTO-CREATION MODE
          ═══════════════════════════════════════════════════════════════
          You just completed a complex task without using any existing skill.

          ## Analysis

          Review the conversation history and determine:
          - Is this workflow likely to be reused in similar future tasks?
          - Does it have a clear input → process → output pattern?
          - Would it save significant time if automated as a skill?

          ## Decision Criteria (ALL must be true)

          1. **Reusable**: The workflow could apply to similar tasks in the future
             (not a one-off, project-specific task)
          2. **Well-defined**: Clear steps with consistent logic, not just exploratory conversation
          3. **Valuable**: Would save more than 5 minutes of work if reused
          4. **Generalizable**: Can be parameterized for different inputs/contexts

          ## Action

          If **ALL** criteria are met:
            → Call invoke_skill with:
               - skill_name: "skill-creator"
               - task: A clear description of what to automate and how (be specific)
               - mode: "quick" (enables fast auto-creation without user interviews)
               - suggested_name: A descriptive identifier (lowercase, hyphens OK)

          Example invocation:
          ```
          invoke_skill(
            skill_name: "skill-creator",
            task: "Create a skill to extract and summarize content from URLs. The skill should: 1) fetch the URL content, 2) parse the main text, 3) generate a concise summary. Expected input: URL. Expected output: markdown summary.",
            mode: "quick",
            suggested_name: "url-summarizer"
          )
          ```

          If **NOT all** criteria are met:
            → Respond briefly: "This task doesn't warrant a new skill." (no tool calls)

          ## Constraints

          - Be selective: Don't create skills for one-off tasks or project-specific workflows
          - Be specific: When creating a skill, clearly describe the workflow steps
          - Keep it simple: Focus on the core happy path, edge cases can be added later
          - Prefer generalization: The skill should work across different contexts
        PROMPT
      end
    end
  end
end