agentf 0.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.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/bin/agentf +8 -0
  3. data/lib/agentf/agent_policy.rb +54 -0
  4. data/lib/agentf/agents/architect.rb +67 -0
  5. data/lib/agentf/agents/base.rb +53 -0
  6. data/lib/agentf/agents/debugger.rb +75 -0
  7. data/lib/agentf/agents/designer.rb +69 -0
  8. data/lib/agentf/agents/documenter.rb +58 -0
  9. data/lib/agentf/agents/explorer.rb +65 -0
  10. data/lib/agentf/agents/reviewer.rb +64 -0
  11. data/lib/agentf/agents/security.rb +84 -0
  12. data/lib/agentf/agents/specialist.rb +68 -0
  13. data/lib/agentf/agents/tester.rb +79 -0
  14. data/lib/agentf/agents.rb +19 -0
  15. data/lib/agentf/cli/architecture.rb +83 -0
  16. data/lib/agentf/cli/arg_parser.rb +50 -0
  17. data/lib/agentf/cli/code.rb +165 -0
  18. data/lib/agentf/cli/install.rb +112 -0
  19. data/lib/agentf/cli/memory.rb +393 -0
  20. data/lib/agentf/cli/metrics.rb +103 -0
  21. data/lib/agentf/cli/router.rb +111 -0
  22. data/lib/agentf/cli/update.rb +204 -0
  23. data/lib/agentf/commands/architecture.rb +183 -0
  24. data/lib/agentf/commands/debugger.rb +238 -0
  25. data/lib/agentf/commands/designer.rb +179 -0
  26. data/lib/agentf/commands/explorer.rb +208 -0
  27. data/lib/agentf/commands/memory_reviewer.rb +186 -0
  28. data/lib/agentf/commands/metrics.rb +272 -0
  29. data/lib/agentf/commands/security_scanner.rb +98 -0
  30. data/lib/agentf/commands/tester.rb +232 -0
  31. data/lib/agentf/commands.rb +17 -0
  32. data/lib/agentf/context_builder.rb +35 -0
  33. data/lib/agentf/installer.rb +580 -0
  34. data/lib/agentf/mcp/server.rb +310 -0
  35. data/lib/agentf/memory.rb +530 -0
  36. data/lib/agentf/packs.rb +74 -0
  37. data/lib/agentf/service/providers.rb +158 -0
  38. data/lib/agentf/tools/component_spec.rb +28 -0
  39. data/lib/agentf/tools/error_analysis.rb +19 -0
  40. data/lib/agentf/tools/file_match.rb +21 -0
  41. data/lib/agentf/tools/test_template.rb +17 -0
  42. data/lib/agentf/tools.rb +12 -0
  43. data/lib/agentf/version.rb +5 -0
  44. data/lib/agentf/workflow_contract.rb +158 -0
  45. data/lib/agentf/workflow_engine.rb +424 -0
  46. data/lib/agentf.rb +87 -0
  47. metadata +164 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: dc86ebb30ccffc8b338dd6e728947f87886c302046e81c01e10d739aac78095f
4
+ data.tar.gz: dda17a3643259253dac2b299e8b45c4f016f4e01f381e6b81956f54633eebcd3
5
+ SHA512:
6
+ metadata.gz: ff8dd589ee31f74de1a35b0fc8122292b7b78747eb3d45338cc4f9fdcff4f8956f69ad0935aa0cc9b3d7bc3395b607b98d5143e1563c786f83eae44902153bb3
7
+ data.tar.gz: 4334dabaf36eabfdfbfeac1b7ff4bda60f1f2b17361df549ef641a85479c2b80b82806a5c18ffacfcba1ee0f7d618c13d55e0ffef8d7e66d0164aade58298a86
data/bin/agentf ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ $LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
5
+ require "agentf"
6
+ require "agentf/cli/router"
7
+
8
+ Agentf::CLI::Router.new.run(ARGV.dup)
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Agentf
4
+ class AgentPolicy
5
+ REQUIRED_KEYS = %w[always ask_first never].freeze
6
+
7
+ def validate(agent_name:, boundaries:, context: {}, result: nil)
8
+ errors = []
9
+ boundaries = normalize(boundaries)
10
+
11
+ required_inputs = Array(boundaries["required_inputs"])
12
+ missing_inputs = required_inputs.reject { |key| context.key?(key) }
13
+ unless missing_inputs.empty?
14
+ errors << violation(
15
+ code: "missing_required_inputs",
16
+ severity: "error",
17
+ message: "#{agent_name} missing required inputs: #{missing_inputs.join(', ')}",
18
+ agent: agent_name
19
+ )
20
+ end
21
+
22
+ if result.is_a?(Hash) && result["error"]
23
+ errors << violation(
24
+ code: "agent_result_error",
25
+ severity: "warn",
26
+ message: "#{agent_name} returned an error: #{result['error']}",
27
+ agent: agent_name
28
+ )
29
+ end
30
+
31
+ errors
32
+ end
33
+
34
+ def normalize(boundaries)
35
+ payload = (boundaries || {}).transform_keys(&:to_s)
36
+ REQUIRED_KEYS.each { |key| payload[key] = Array(payload[key]) }
37
+ payload["required_inputs"] = Array(payload["required_inputs"])
38
+ payload["required_outputs"] = Array(payload["required_outputs"])
39
+ payload
40
+ end
41
+
42
+ private
43
+
44
+ def violation(code:, severity:, message:, agent:)
45
+ {
46
+ "code" => code,
47
+ "severity" => severity,
48
+ "message" => message,
49
+ "agent" => agent,
50
+ "type" => "agent_policy"
51
+ }
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+
5
+ module Agentf
6
+ module Agents
7
+ # Architect Agent - Strategy, task decomposition
8
+ class Architect < Base
9
+ DESCRIPTION = "Strategy, task decomposition, and memory retrieval."
10
+ COMMANDS = %w[glob read_file memory].freeze
11
+ MEMORY_CONCEPTS = {
12
+ "reads" => ["get_recent_memories", "get_pitfalls"],
13
+ "writes" => [],
14
+ "policy" => "Retrieve relevant memories before planning; do not duplicate runtime memory into static markdown."
15
+ }.freeze
16
+
17
+ def self.description
18
+ DESCRIPTION
19
+ end
20
+
21
+ def self.commands
22
+ COMMANDS
23
+ end
24
+
25
+ def self.memory_concepts
26
+ MEMORY_CONCEPTS
27
+ end
28
+
29
+ def self.policy_boundaries
30
+ {
31
+ "always" => ["Capture constraints before decomposition", "Use recent memories and pitfalls in planning"],
32
+ "ask_first" => ["Changing architectural style from project defaults"],
33
+ "never" => ["Skip task decomposition for non-trivial workflows"],
34
+ "required_inputs" => [],
35
+ "required_outputs" => ["subtasks", "context"]
36
+ }
37
+ end
38
+
39
+ def plan_task(task)
40
+ log "Planning: #{task}"
41
+
42
+ # Retrieve relevant memories before planning
43
+ recent = memory.get_recent_memories(limit: 5)
44
+ pitfalls = memory.get_pitfalls(limit: 3)
45
+
46
+ context = {
47
+ "task" => task,
48
+ "relevant_memories" => recent,
49
+ "pitfalls_to_avoid" => pitfalls
50
+ }
51
+
52
+ # Decompose into subtasks
53
+ subtasks = [
54
+ { "id" => 1, "description" => "Research and gather requirements" },
55
+ { "id" => 2, "description" => "Implement the solution" },
56
+ { "id" => 3, "description" => "Review and test" }
57
+ ]
58
+
59
+ log "Found #{recent.size} relevant memories"
60
+ log "Avoiding #{pitfalls.size} known pitfalls"
61
+ log "Created #{subtasks.size} subtasks"
62
+
63
+ { "subtasks" => subtasks, "context" => context }
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Agentf
4
+ module Agents
5
+ # Base agent class
6
+ class Base
7
+ attr_reader :memory, :name
8
+
9
+ def self.typed_name
10
+ name.split("::").last.upcase
11
+ end
12
+
13
+ def self.description
14
+ "Agent for #{typed_name.downcase}"
15
+ end
16
+
17
+ def self.commands
18
+ []
19
+ end
20
+
21
+ def self.memory_concepts
22
+ {
23
+ "reads" => ["RedisMemory#get_recent_memories", "RedisMemory#get_pitfalls"],
24
+ "writes" => ["RedisMemory#store_lesson", "RedisMemory#store_success", "RedisMemory#store_pitfall"],
25
+ "policy" => "Memory is runtime state in Redis and should not be embedded as raw data in manifest markdown."
26
+ }
27
+ end
28
+
29
+ def self.prompt
30
+ "You are the #{typed_name} agent."
31
+ end
32
+
33
+ def self.policy_boundaries
34
+ {
35
+ "always" => [],
36
+ "ask_first" => [],
37
+ "never" => [],
38
+ "required_inputs" => [],
39
+ "required_outputs" => []
40
+ }
41
+ end
42
+
43
+ def initialize(memory)
44
+ @memory = memory
45
+ @name = self.class.typed_name
46
+ end
47
+
48
+ def log(message)
49
+ puts "\n[#{@name}] #{message}"
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+ require_relative "../commands"
5
+
6
+ module Agentf
7
+ module Agents
8
+ # Debugger Agent - Error analysis and diagnosis
9
+ class Debugger < Base
10
+ DESCRIPTION = "Error analysis, diagnosis, and remediation guidance."
11
+ COMMANDS = %w[parse_error analyze_logs suggest_fix].freeze
12
+ MEMORY_CONCEPTS = {
13
+ "reads" => [],
14
+ "writes" => ["store_episode"],
15
+ "policy" => "Persist debugging lessons with root cause and proposed fixes."
16
+ }.freeze
17
+
18
+ def self.description
19
+ DESCRIPTION
20
+ end
21
+
22
+ def self.commands
23
+ COMMANDS
24
+ end
25
+
26
+ def self.memory_concepts
27
+ MEMORY_CONCEPTS
28
+ end
29
+
30
+ def self.policy_boundaries
31
+ {
32
+ "always" => ["Return analysis with root causes and suggested fix", "Persist debugging lesson"],
33
+ "ask_first" => ["Applying speculative fixes without reproducible error"],
34
+ "never" => ["Discard stack trace context when available"],
35
+ "required_inputs" => [],
36
+ "required_outputs" => ["analysis"]
37
+ }
38
+ end
39
+
40
+ def initialize(memory, commands: nil)
41
+ super(memory)
42
+ @commands = commands || Agentf::Commands::Debugger.new
43
+ end
44
+
45
+ def diagnose(error, context: nil)
46
+ log "Diagnosing error"
47
+ log " Error: #{error[0..100]}..."
48
+
49
+ analysis = @commands.parse_error(error)
50
+
51
+ memory.store_episode(
52
+ type: "lesson",
53
+ title: "Debugged: #{error[0..50]}...",
54
+ description: "Root cause: #{analysis.possible_causes.first}. Fix: #{analysis.suggested_fix}",
55
+ context: context.to_s,
56
+ tags: ["debugging", "error", "fix"],
57
+ agent: name
58
+ )
59
+
60
+ log "Root cause: #{analysis.possible_causes.first}"
61
+ log "Suggested fix: #{analysis.suggested_fix}"
62
+
63
+ {
64
+ "error" => error,
65
+ "analysis" => {
66
+ "error_type" => analysis.error_type,
67
+ "possible_causes" => analysis.possible_causes,
68
+ "suggested_fix" => analysis.suggested_fix,
69
+ "stack_trace" => analysis.stack_trace
70
+ }
71
+ }
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+ require_relative "../commands"
5
+
6
+ module Agentf
7
+ module Agents
8
+ # Designer Agent - Design specs to implementation
9
+ class Designer < Base
10
+ DESCRIPTION = "UI/UX implementation from design specs."
11
+ COMMANDS = %w[generate_component validate_design_system].freeze
12
+ MEMORY_CONCEPTS = {
13
+ "reads" => [],
14
+ "writes" => ["store_success"],
15
+ "policy" => "Capture successful design implementation patterns."
16
+ }.freeze
17
+
18
+ def self.description
19
+ DESCRIPTION
20
+ end
21
+
22
+ def self.commands
23
+ COMMANDS
24
+ end
25
+
26
+ def self.memory_concepts
27
+ MEMORY_CONCEPTS
28
+ end
29
+
30
+ def self.policy_boundaries
31
+ {
32
+ "always" => ["Return generated component details", "Persist successful implementation pattern"],
33
+ "ask_first" => ["Changing primary UI framework"],
34
+ "never" => ["Return empty generated code for successful design task"],
35
+ "required_inputs" => [],
36
+ "required_outputs" => ["component", "generated_code"]
37
+ }
38
+ end
39
+
40
+ def initialize(memory, commands: nil)
41
+ super(memory)
42
+ @commands = commands || Agentf::Commands::Designer.new
43
+ end
44
+
45
+ def implement_design(design_spec, framework: "react")
46
+ log "Implementing design: #{design_spec}"
47
+
48
+ spec = @commands.generate_component("GeneratedComponent", design_spec)
49
+
50
+ memory.store_success(
51
+ title: "Implemented design: #{design_spec}",
52
+ description: "Created #{spec.name} in #{spec.framework}",
53
+ context: "Framework: #{framework}",
54
+ tags: ["design", "ui", framework],
55
+ agent: name
56
+ )
57
+
58
+ log "Created component: #{spec.name}"
59
+
60
+ {
61
+ "design_spec" => design_spec,
62
+ "component" => spec.name,
63
+ "framework" => framework,
64
+ "generated_code" => spec.code
65
+ }
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+
5
+ module Agentf
6
+ module Agents
7
+ # Documenter Agent - Sync Redis memory with local Markdown docs
8
+ class Documenter < Base
9
+ DESCRIPTION = "Syncs Redis memory with local Markdown summaries."
10
+ COMMANDS = %w[read_file write_file memory].freeze
11
+ MEMORY_CONCEPTS = {
12
+ "reads" => ["get_recent_memories"],
13
+ "writes" => [],
14
+ "policy" => "Summarize memory trends into docs without storing raw secrets."
15
+ }.freeze
16
+
17
+ def self.description
18
+ DESCRIPTION
19
+ end
20
+
21
+ def self.commands
22
+ COMMANDS
23
+ end
24
+
25
+ def self.memory_concepts
26
+ MEMORY_CONCEPTS
27
+ end
28
+
29
+ def self.policy_boundaries
30
+ {
31
+ "always" => ["Summarize recent successes and pitfalls"],
32
+ "ask_first" => ["Publishing docs to external destinations"],
33
+ "never" => ["Leak sensitive context in summaries"],
34
+ "required_inputs" => [],
35
+ "required_outputs" => ["successes", "pitfalls", "total_memories"]
36
+ }
37
+ end
38
+
39
+ def sync_docs(project_name)
40
+ log "Syncing documentation"
41
+
42
+ memories = memory.get_recent_memories(limit: 20)
43
+
44
+ successes = memories.select { |m| m["type"] == "success" }
45
+ pitfalls = memories.select { |m| m["type"] == "pitfall" }
46
+
47
+ log "Found #{successes.size} successes"
48
+ log "Found #{pitfalls.size} pitfalls"
49
+
50
+ {
51
+ "successes" => successes,
52
+ "pitfalls" => pitfalls,
53
+ "total_memories" => memories.size
54
+ }
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+ require_relative "../commands"
5
+
6
+ module Agentf
7
+ module Agents
8
+ # Explorer Agent - Codebase exploration
9
+ class Explorer < Base
10
+ DESCRIPTION = "Rapid codebase exploration and context gathering."
11
+ COMMANDS = %w[glob grep read_file].freeze
12
+ MEMORY_CONCEPTS = {
13
+ "reads" => [],
14
+ "writes" => ["store_episode"],
15
+ "policy" => "Store exploration breadcrumbs as episodic memories."
16
+ }.freeze
17
+
18
+ def self.description
19
+ DESCRIPTION
20
+ end
21
+
22
+ def self.commands
23
+ COMMANDS
24
+ end
25
+
26
+ def self.memory_concepts
27
+ MEMORY_CONCEPTS
28
+ end
29
+
30
+ def self.policy_boundaries
31
+ {
32
+ "always" => ["Return concrete file evidence", "Persist exploration breadcrumbs"],
33
+ "ask_first" => ["Scanning outside configured base path"],
34
+ "never" => ["Mutate project files during exploration"],
35
+ "required_inputs" => [],
36
+ "required_outputs" => ["files", "context_gathered"]
37
+ }
38
+ end
39
+
40
+ def initialize(memory, commands: nil)
41
+ super(memory)
42
+ @commands = commands || Agentf::Commands::Explorer.new
43
+ end
44
+
45
+ def explore(query, file_pattern: nil)
46
+ log "Exploring: #{query}"
47
+
48
+ files = @commands.glob(query, file_types: nil)
49
+
50
+ memory.store_episode(
51
+ type: "exploration",
52
+ title: "Explored: #{query}",
53
+ description: "Found #{files.size} relevant files",
54
+ context: "Search pattern: #{file_pattern || 'all files'}",
55
+ tags: ["exploration", "context"],
56
+ agent: name
57
+ )
58
+
59
+ log "Found #{files.size} files"
60
+
61
+ { "query" => query, "files" => files, "context_gathered" => true }
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+
5
+ module Agentf
6
+ module Agents
7
+ # Reviewer Agent - Quality assurance
8
+ class Reviewer < Base
9
+ DESCRIPTION = "Quality assurance and regression checking against memory."
10
+ COMMANDS = %w[read_file memory].freeze
11
+ MEMORY_CONCEPTS = {
12
+ "reads" => ["get_pitfalls", "get_recent_memories"],
13
+ "writes" => [],
14
+ "policy" => "Validate outputs against known pitfalls before approval."
15
+ }.freeze
16
+
17
+ def self.description
18
+ DESCRIPTION
19
+ end
20
+
21
+ def self.commands
22
+ COMMANDS
23
+ end
24
+
25
+ def self.memory_concepts
26
+ MEMORY_CONCEPTS
27
+ end
28
+
29
+ def self.policy_boundaries
30
+ {
31
+ "always" => ["Report approval decision", "Highlight known pitfalls in review findings"],
32
+ "ask_first" => ["Approving with unresolved critical security issues"],
33
+ "never" => ["Approve without any review evidence"],
34
+ "required_inputs" => [],
35
+ "required_outputs" => ["approved", "issues"]
36
+ }
37
+ end
38
+
39
+ def review(subtask_result)
40
+ log "Reviewing subtask #{subtask_result['subtask_id']}"
41
+
42
+ pitfalls = memory.get_pitfalls(limit: 5)
43
+ memories = memory.get_recent_memories(limit: 5)
44
+
45
+ issues = []
46
+
47
+ pitfalls.each do |pitfall|
48
+ issues << "Warning: Known pitfall - #{pitfall['title']}" if pitfall["type"] == "pitfall"
49
+ end
50
+
51
+ approved = issues.empty?
52
+
53
+ if approved
54
+ log "Approved (no issues found)"
55
+ else
56
+ log "Issues found: #{issues.size}"
57
+ issues.each { |issue| log " - #{issue}" }
58
+ end
59
+
60
+ { "approved" => approved, "issues" => issues }
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+ require_relative "../commands"
5
+
6
+ module Agentf
7
+ module Agents
8
+ # Security Agent - Performs lightweight security assessments during workflows
9
+ class Security < Base
10
+ DESCRIPTION = "Security scanning for secret leaks and prompt injection."
11
+ COMMANDS = %w[scan best_practices].freeze
12
+ MEMORY_CONCEPTS = {
13
+ "reads" => [],
14
+ "writes" => ["store_success", "store_pitfall"],
15
+ "policy" => "Record findings while redacting sensitive values."
16
+ }.freeze
17
+
18
+ def self.description
19
+ DESCRIPTION
20
+ end
21
+
22
+ def self.commands
23
+ COMMANDS
24
+ end
25
+
26
+ def self.memory_concepts
27
+ MEMORY_CONCEPTS
28
+ end
29
+
30
+ def self.policy_boundaries
31
+ {
32
+ "always" => ["Return issue list and best practices", "Persist outcome as success or pitfall"],
33
+ "ask_first" => ["Allowing known secret patterns in context"],
34
+ "never" => ["Echo raw secrets in output"],
35
+ "required_inputs" => [],
36
+ "required_outputs" => ["issues", "best_practices"]
37
+ }
38
+ end
39
+
40
+ def initialize(memory, commands: nil)
41
+ super(memory)
42
+ @commands = commands || Agentf::Commands::SecurityScanner.new
43
+ end
44
+
45
+ def assess(task:, context: {})
46
+ log "Running security assessment"
47
+
48
+ findings = @commands.scan(task: task, context: context)
49
+ summary = summarize_findings(findings)
50
+
51
+ if findings["issues"].empty?
52
+ memory.store_success(
53
+ title: "Security review passed",
54
+ description: summary,
55
+ context: task,
56
+ tags: ["security", "pass"],
57
+ agent: name
58
+ )
59
+ else
60
+ memory.store_pitfall(
61
+ title: "Security findings detected",
62
+ description: summary,
63
+ context: task,
64
+ tags: ["security", "warning"],
65
+ agent: name
66
+ )
67
+ end
68
+
69
+ findings.merge("best_practices" => @commands.best_practices)
70
+ end
71
+
72
+ private
73
+
74
+ def summarize_findings(findings)
75
+ if findings["issues"].empty?
76
+ "No potential secrets or prompt-injection attempts detected."
77
+ else
78
+ issues = findings["issues"].map { |issue| "- #{issue['issue']}: #{issue['detail']}" }
79
+ "Identified #{findings['issues'].size} potential issue(s):\n#{issues.join('\n')}"
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "base"
4
+
5
+ module Agentf
6
+ module Agents
7
+ # Specialist Agent - Code execution
8
+ class Specialist < Base
9
+ DESCRIPTION = "Code execution and lesson-learning persistence."
10
+ COMMANDS = %w[read_file write_file run_command].freeze
11
+ MEMORY_CONCEPTS = {
12
+ "reads" => [],
13
+ "writes" => ["store_success", "store_pitfall"],
14
+ "policy" => "Persist execution outcomes as lessons for downstream agents."
15
+ }.freeze
16
+
17
+ def self.description
18
+ DESCRIPTION
19
+ end
20
+
21
+ def self.commands
22
+ COMMANDS
23
+ end
24
+
25
+ def self.memory_concepts
26
+ MEMORY_CONCEPTS
27
+ end
28
+
29
+ def self.policy_boundaries
30
+ {
31
+ "always" => ["Persist execution outcome", "Return deterministic success boolean"],
32
+ "ask_first" => ["Applying architecture style changes across unrelated modules"],
33
+ "never" => ["Claim implementation complete without execution result"],
34
+ "required_inputs" => [],
35
+ "required_outputs" => ["subtask_id", "success"]
36
+ }
37
+ end
38
+
39
+ def execute(subtask)
40
+ log "Executing: #{subtask['description']}"
41
+
42
+ success = subtask.fetch("success", true)
43
+
44
+ if success
45
+ memory.store_success(
46
+ title: "Completed: #{subtask['description']}",
47
+ description: "Successfully executed subtask #{subtask['id']}",
48
+ context: "Working on #{subtask.fetch('task', 'unknown task')}",
49
+ tags: ["implementation", subtask.fetch("language", "general")],
50
+ agent: name
51
+ )
52
+ log "Stored success memory"
53
+ else
54
+ memory.store_pitfall(
55
+ title: "Failed: #{subtask['description']}",
56
+ description: "Subtask #{subtask['id']} failed",
57
+ context: "Working on #{subtask.fetch('task', 'unknown task')}",
58
+ tags: ["failure", "implementation"],
59
+ agent: name
60
+ )
61
+ log "Stored pitfall memory"
62
+ end
63
+
64
+ { "subtask_id" => subtask["id"], "success" => success, "result" => "Code executed" }
65
+ end
66
+ end
67
+ end
68
+ end