agentf 0.5.0 → 0.6.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.
- checksums.yaml +4 -4
- data/lib/agentf/agents/architect.rb +3 -3
- data/lib/agentf/agents/base.rb +2 -2
- data/lib/agentf/agents/debugger.rb +1 -2
- data/lib/agentf/agents/designer.rb +6 -5
- data/lib/agentf/agents/documenter.rb +2 -2
- data/lib/agentf/agents/explorer.rb +1 -2
- data/lib/agentf/agents/reviewer.rb +7 -7
- data/lib/agentf/agents/security.rb +11 -9
- data/lib/agentf/agents/specialist.rb +11 -9
- data/lib/agentf/agents/tester.rb +6 -5
- data/lib/agentf/cli/eval.rb +1 -1
- data/lib/agentf/cli/memory.rb +66 -70
- data/lib/agentf/cli/router.rb +1 -1
- data/lib/agentf/commands/memory_reviewer.rb +16 -50
- data/lib/agentf/commands/metrics.rb +4 -13
- data/lib/agentf/context_builder.rb +4 -14
- data/lib/agentf/embedding_provider.rb +35 -0
- data/lib/agentf/installer.rb +73 -78
- data/lib/agentf/mcp/server.rb +40 -102
- data/lib/agentf/memory.rb +316 -169
- data/lib/agentf/version.rb +1 -1
- data/lib/agentf/workflow_engine.rb +15 -18
- data/lib/agentf.rb +1 -0
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ace5a58ed6bfb8389d1e7a68349d7cc9f8d80b4093131a8cf2013388b001a08d
|
|
4
|
+
data.tar.gz: ba9a86b1c4b9e7e7edf62bed089d5cb3a1dddb9c5b4282c16e9be27438fec088
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 35767581d0b7561c1800464909dbf00524724527148b20f4f1ab911d846301d1a60333e8703d7b3db04e7d3d34e1a977d522fef236f8899692ae8a8c2bac65ad
|
|
7
|
+
data.tar.gz: 8d61e62517723d4bc4d39905dfb87b792d27ba1bfbe2b1eb6c445409b138091d072413ad21bffbe2cd584887d9a75f798df64f79601594ccb1029e9db54439f1
|
|
@@ -9,7 +9,7 @@ module Agentf
|
|
|
9
9
|
DESCRIPTION = "Strategy, task decomposition, and memory retrieval."
|
|
10
10
|
COMMANDS = %w[glob read_file memory].freeze
|
|
11
11
|
MEMORY_CONCEPTS = {
|
|
12
|
-
"reads" => ["get_recent_memories", "
|
|
12
|
+
"reads" => ["get_recent_memories", "get_episodes"],
|
|
13
13
|
"writes" => [],
|
|
14
14
|
"policy" => "Retrieve relevant memories before planning; do not duplicate runtime memory into static markdown."
|
|
15
15
|
}.freeze
|
|
@@ -44,7 +44,7 @@ module Agentf
|
|
|
44
44
|
|
|
45
45
|
def self.policy_boundaries
|
|
46
46
|
{
|
|
47
|
-
"always" => ["Capture constraints before decomposition", "Use recent memories and
|
|
47
|
+
"always" => ["Capture constraints before decomposition", "Use recent memories and negative episodes in planning"],
|
|
48
48
|
"ask_first" => ["Changing architectural style from project defaults"],
|
|
49
49
|
"never" => ["Skip task decomposition for non-trivial workflows"],
|
|
50
50
|
"required_inputs" => [],
|
|
@@ -57,7 +57,7 @@ module Agentf
|
|
|
57
57
|
|
|
58
58
|
# Retrieve relevant memories before planning
|
|
59
59
|
recent = memory.get_recent_memories(limit: 5)
|
|
60
|
-
pitfalls = memory.
|
|
60
|
+
pitfalls = memory.get_episodes(limit: 3, outcome: "negative")
|
|
61
61
|
|
|
62
62
|
context = {
|
|
63
63
|
"task" => task,
|
data/lib/agentf/agents/base.rb
CHANGED
|
@@ -32,8 +32,8 @@ module Agentf
|
|
|
32
32
|
|
|
33
33
|
def self.memory_concepts
|
|
34
34
|
{
|
|
35
|
-
"reads" => ["RedisMemory#get_recent_memories", "RedisMemory#
|
|
36
|
-
"writes" => ["RedisMemory#store_lesson", "RedisMemory#
|
|
35
|
+
"reads" => ["RedisMemory#get_recent_memories", "RedisMemory#get_episodes"],
|
|
36
|
+
"writes" => ["RedisMemory#store_lesson", "RedisMemory#store_episode", "RedisMemory#store_playbook"],
|
|
37
37
|
"policy" => "Memory is runtime state in Redis and should not be embedded as raw data in manifest markdown."
|
|
38
38
|
}
|
|
39
39
|
end
|
|
@@ -66,13 +66,12 @@ module Agentf
|
|
|
66
66
|
|
|
67
67
|
analysis = @commands.parse_error(error)
|
|
68
68
|
|
|
69
|
-
res = safe_memory_write(attempted: { action: "store_lesson", title: "Debugged: #{error[0..50]}...",
|
|
69
|
+
res = safe_memory_write(attempted: { action: "store_lesson", title: "Debugged: #{error[0..50]}...", agent: name }) do
|
|
70
70
|
memory.store_episode(
|
|
71
71
|
type: "lesson",
|
|
72
72
|
title: "Debugged: #{error[0..50]}...",
|
|
73
73
|
description: "Root cause: #{analysis.possible_causes.first}. Fix: #{analysis.suggested_fix}",
|
|
74
74
|
context: context.to_s,
|
|
75
|
-
tags: ["debugging", "error", "fix"],
|
|
76
75
|
agent: name
|
|
77
76
|
)
|
|
78
77
|
end
|
|
@@ -11,7 +11,7 @@ module Agentf
|
|
|
11
11
|
COMMANDS = %w[generate_component validate_design_system].freeze
|
|
12
12
|
MEMORY_CONCEPTS = {
|
|
13
13
|
"reads" => [],
|
|
14
|
-
"writes" => ["
|
|
14
|
+
"writes" => ["store_episode"],
|
|
15
15
|
"policy" => "Capture successful design implementation patterns."
|
|
16
16
|
}.freeze
|
|
17
17
|
|
|
@@ -64,13 +64,14 @@ module Agentf
|
|
|
64
64
|
|
|
65
65
|
spec = @commands.generate_component("GeneratedComponent", design_spec)
|
|
66
66
|
|
|
67
|
-
res = safe_memory_write(attempted: { action: "
|
|
68
|
-
memory.
|
|
67
|
+
res = safe_memory_write(attempted: { action: "store_episode", title: "Implemented design: #{design_spec}", outcome: "positive", agent: name }) do
|
|
68
|
+
memory.store_episode(
|
|
69
|
+
type: "episode",
|
|
69
70
|
title: "Implemented design: #{design_spec}",
|
|
70
71
|
description: "Created #{spec.name} in #{spec.framework}",
|
|
71
72
|
context: "Framework: #{framework}",
|
|
72
|
-
|
|
73
|
-
|
|
73
|
+
agent: name,
|
|
74
|
+
outcome: "positive"
|
|
74
75
|
)
|
|
75
76
|
end
|
|
76
77
|
|
|
@@ -57,8 +57,8 @@ module Agentf
|
|
|
57
57
|
|
|
58
58
|
memories = memory.get_recent_memories(limit: 20)
|
|
59
59
|
|
|
60
|
-
successes = memories.select { |m| m["type"] == "
|
|
61
|
-
pitfalls = memories.select { |m| m["type"] == "
|
|
60
|
+
successes = memories.select { |m| m["type"] == "episode" && m["outcome"] == "positive" }
|
|
61
|
+
pitfalls = memories.select { |m| m["type"] == "episode" && m["outcome"] == "negative" }
|
|
62
62
|
|
|
63
63
|
log "Found #{successes.size} successes"
|
|
64
64
|
log "Found #{pitfalls.size} pitfalls"
|
|
@@ -63,12 +63,11 @@ module Agentf
|
|
|
63
63
|
|
|
64
64
|
files = @commands.glob(query, file_types: nil)
|
|
65
65
|
|
|
66
|
-
res = safe_memory_write(attempted: { action: "store_lesson", title: "Research finding: #{query}",
|
|
66
|
+
res = safe_memory_write(attempted: { action: "store_lesson", title: "Research finding: #{query}", agent: name }) do
|
|
67
67
|
memory.store_lesson(
|
|
68
68
|
title: "Research finding: #{query}",
|
|
69
69
|
description: "Found #{files.size} relevant files during exploration",
|
|
70
70
|
context: "Search pattern: #{file_pattern || 'all files'}",
|
|
71
|
-
tags: ["research", "exploration"],
|
|
72
71
|
agent: name
|
|
73
72
|
)
|
|
74
73
|
end
|
|
@@ -9,9 +9,9 @@ module Agentf
|
|
|
9
9
|
DESCRIPTION = "Quality assurance and regression checking against memory."
|
|
10
10
|
COMMANDS = %w[read_file memory].freeze
|
|
11
11
|
MEMORY_CONCEPTS = {
|
|
12
|
-
"reads" => ["
|
|
12
|
+
"reads" => ["get_episodes", "get_recent_memories"],
|
|
13
13
|
"writes" => [],
|
|
14
|
-
"policy" => "Validate outputs against known
|
|
14
|
+
"policy" => "Validate outputs against known negative episodes before approval."
|
|
15
15
|
}.freeze
|
|
16
16
|
|
|
17
17
|
def self.description
|
|
@@ -56,14 +56,14 @@ module Agentf
|
|
|
56
56
|
execute_with_contract(context: { "execution" => subtask_result }) do
|
|
57
57
|
log "Reviewing subtask #{subtask_result['subtask_id']}"
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
pitfalls = memory.get_episodes(limit: 5, outcome: "negative")
|
|
60
|
+
memories = memory.get_recent_memories(limit: 5)
|
|
61
61
|
|
|
62
62
|
issues = []
|
|
63
63
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
64
|
+
pitfalls.each do |pitfall|
|
|
65
|
+
issues << "Warning: Known negative episode - #{pitfall['title']}" if pitfall["type"] == "episode"
|
|
66
|
+
end
|
|
67
67
|
|
|
68
68
|
approved = issues.empty?
|
|
69
69
|
|
|
@@ -11,7 +11,7 @@ module Agentf
|
|
|
11
11
|
COMMANDS = %w[scan best_practices].freeze
|
|
12
12
|
MEMORY_CONCEPTS = {
|
|
13
13
|
"reads" => [],
|
|
14
|
-
"writes" => ["
|
|
14
|
+
"writes" => ["store_episode"],
|
|
15
15
|
"policy" => "Record findings while redacting sensitive values."
|
|
16
16
|
}.freeze
|
|
17
17
|
|
|
@@ -66,24 +66,26 @@ module Agentf
|
|
|
66
66
|
summary = summarize_findings(findings)
|
|
67
67
|
|
|
68
68
|
if findings["issues"].empty?
|
|
69
|
-
res = safe_memory_write(attempted: { action: "
|
|
70
|
-
memory.
|
|
69
|
+
res = safe_memory_write(attempted: { action: "store_episode", title: "Security review passed", outcome: "positive", agent: name }) do
|
|
70
|
+
memory.store_episode(
|
|
71
|
+
type: "episode",
|
|
71
72
|
title: "Security review passed",
|
|
72
73
|
description: summary,
|
|
73
74
|
context: task,
|
|
74
|
-
|
|
75
|
-
|
|
75
|
+
agent: name,
|
|
76
|
+
outcome: "positive"
|
|
76
77
|
)
|
|
77
78
|
end
|
|
78
79
|
return findings.merge(res) if res.is_a?(Hash) && res["confirmation_required"]
|
|
79
80
|
else
|
|
80
|
-
res = safe_memory_write(attempted: { action: "
|
|
81
|
-
memory.
|
|
81
|
+
res = safe_memory_write(attempted: { action: "store_episode", title: "Security findings detected", outcome: "negative", agent: name }) do
|
|
82
|
+
memory.store_episode(
|
|
83
|
+
type: "episode",
|
|
82
84
|
title: "Security findings detected",
|
|
83
85
|
description: summary,
|
|
84
86
|
context: task,
|
|
85
|
-
|
|
86
|
-
|
|
87
|
+
agent: name,
|
|
88
|
+
outcome: "negative"
|
|
87
89
|
)
|
|
88
90
|
end
|
|
89
91
|
return findings.merge(res) if res.is_a?(Hash) && res["confirmation_required"]
|
|
@@ -10,7 +10,7 @@ module Agentf
|
|
|
10
10
|
COMMANDS = %w[read_file write_file run_command].freeze
|
|
11
11
|
MEMORY_CONCEPTS = {
|
|
12
12
|
"reads" => [],
|
|
13
|
-
"writes" => ["
|
|
13
|
+
"writes" => ["store_episode"],
|
|
14
14
|
"policy" => "Persist execution outcomes as lessons for downstream agents."
|
|
15
15
|
}.freeze
|
|
16
16
|
|
|
@@ -66,13 +66,14 @@ module Agentf
|
|
|
66
66
|
success = normalized_subtask.fetch("success", true)
|
|
67
67
|
|
|
68
68
|
if success
|
|
69
|
-
res = safe_memory_write(attempted: { action: "
|
|
70
|
-
memory.
|
|
69
|
+
res = safe_memory_write(attempted: { action: "store_episode", title: "Completed: #{normalized_subtask['description']}", outcome: "positive", agent: name }) do
|
|
70
|
+
memory.store_episode(
|
|
71
|
+
type: "episode",
|
|
71
72
|
title: "Completed: #{normalized_subtask['description']}",
|
|
72
73
|
description: "Successfully executed subtask #{normalized_subtask['id']}",
|
|
73
74
|
context: "Working on #{normalized_subtask.fetch('task', 'unknown task')}",
|
|
74
|
-
|
|
75
|
-
|
|
75
|
+
agent: name,
|
|
76
|
+
outcome: "positive"
|
|
76
77
|
)
|
|
77
78
|
end
|
|
78
79
|
|
|
@@ -81,13 +82,14 @@ module Agentf
|
|
|
81
82
|
return { "subtask_id" => normalized_subtask["id"], "success" => success, "result" => "Code executed", "confirmation_required" => true, "confirmation_details" => res["confirmation_details"], "attempted" => res["attempted"] }
|
|
82
83
|
end
|
|
83
84
|
else
|
|
84
|
-
res = safe_memory_write(attempted: { action: "
|
|
85
|
-
memory.
|
|
85
|
+
res = safe_memory_write(attempted: { action: "store_episode", title: "Failed: #{normalized_subtask['description']}", outcome: "negative", agent: name }) do
|
|
86
|
+
memory.store_episode(
|
|
87
|
+
type: "episode",
|
|
86
88
|
title: "Failed: #{normalized_subtask['description']}",
|
|
87
89
|
description: "Subtask #{normalized_subtask['id']} failed",
|
|
88
90
|
context: "Working on #{normalized_subtask.fetch('task', 'unknown task')}",
|
|
89
|
-
|
|
90
|
-
|
|
91
|
+
agent: name,
|
|
92
|
+
outcome: "negative"
|
|
91
93
|
)
|
|
92
94
|
end
|
|
93
95
|
|
data/lib/agentf/agents/tester.rb
CHANGED
|
@@ -11,7 +11,7 @@ module Agentf
|
|
|
11
11
|
COMMANDS = %w[detect_framework generate_unit_tests run_tests].freeze
|
|
12
12
|
MEMORY_CONCEPTS = {
|
|
13
13
|
"reads" => [],
|
|
14
|
-
"writes" => ["
|
|
14
|
+
"writes" => ["store_episode"],
|
|
15
15
|
"policy" => "Persist test generation outcomes for future reuse."
|
|
16
16
|
}.freeze
|
|
17
17
|
|
|
@@ -63,13 +63,14 @@ module Agentf
|
|
|
63
63
|
|
|
64
64
|
template = @commands.generate_unit_tests(code_file)
|
|
65
65
|
|
|
66
|
-
res = safe_memory_write(attempted: { action: "
|
|
67
|
-
memory.
|
|
66
|
+
res = safe_memory_write(attempted: { action: "store_episode", title: "Generated #{test_type} tests for #{code_file}", outcome: "positive", agent: name }) do
|
|
67
|
+
memory.store_episode(
|
|
68
|
+
type: "episode",
|
|
68
69
|
title: "Generated #{test_type} tests for #{code_file}",
|
|
69
70
|
description: "Created #{template.test_file} with #{test_type} tests",
|
|
70
71
|
context: "Test framework: #{template.framework}",
|
|
71
|
-
|
|
72
|
-
|
|
72
|
+
agent: name,
|
|
73
|
+
outcome: "positive"
|
|
73
74
|
)
|
|
74
75
|
end
|
|
75
76
|
|
data/lib/agentf/cli/eval.rb
CHANGED
data/lib/agentf/cli/memory.rb
CHANGED
|
@@ -13,7 +13,7 @@ module Agentf
|
|
|
13
13
|
class Memory
|
|
14
14
|
include ArgParser
|
|
15
15
|
|
|
16
|
-
VALID_EPISODE_TYPES = %w[
|
|
16
|
+
VALID_EPISODE_TYPES = %w[episode lesson playbook business_intent feature_intent incident].freeze
|
|
17
17
|
|
|
18
18
|
def initialize(reviewer: nil, memory: nil)
|
|
19
19
|
@reviewer = reviewer || Commands::MemoryReviewer.new
|
|
@@ -28,12 +28,10 @@ module Agentf
|
|
|
28
28
|
case command
|
|
29
29
|
when "recent", "list"
|
|
30
30
|
list_memories(args)
|
|
31
|
-
when "
|
|
32
|
-
|
|
31
|
+
when "episodes"
|
|
32
|
+
list_episodes(args)
|
|
33
33
|
when "lessons"
|
|
34
34
|
list_lessons(args)
|
|
35
|
-
when "successes"
|
|
36
|
-
list_successes(args)
|
|
37
35
|
when "intents"
|
|
38
36
|
list_intents(args)
|
|
39
37
|
when "business-intents"
|
|
@@ -44,14 +42,10 @@ module Agentf
|
|
|
44
42
|
add_business_intent(args)
|
|
45
43
|
when "add-feature-intent"
|
|
46
44
|
add_feature_intent(args)
|
|
45
|
+
when "add-playbook"
|
|
46
|
+
add_playbook(args)
|
|
47
47
|
when "add-lesson"
|
|
48
48
|
add_episode("lesson", args)
|
|
49
|
-
when "add-success"
|
|
50
|
-
add_episode("success", args)
|
|
51
|
-
when "add-pitfall"
|
|
52
|
-
add_episode("pitfall", args)
|
|
53
|
-
when "tags"
|
|
54
|
-
list_tags
|
|
55
49
|
when "search"
|
|
56
50
|
search_memories(args)
|
|
57
51
|
when "delete"
|
|
@@ -62,8 +56,6 @@ module Agentf
|
|
|
62
56
|
subgraph(args)
|
|
63
57
|
when "summary", "stats"
|
|
64
58
|
show_summary
|
|
65
|
-
when "by-tag"
|
|
66
|
-
by_tag(args)
|
|
67
59
|
when "by-agent"
|
|
68
60
|
by_agent(args)
|
|
69
61
|
when "by-type"
|
|
@@ -86,9 +78,10 @@ module Agentf
|
|
|
86
78
|
output(result)
|
|
87
79
|
end
|
|
88
80
|
|
|
89
|
-
def
|
|
81
|
+
def list_episodes(args)
|
|
90
82
|
limit = extract_limit(args)
|
|
91
|
-
|
|
83
|
+
outcome = parse_single_option(args, "--outcome=")
|
|
84
|
+
result = @reviewer.get_episodes(limit: limit, outcome: outcome)
|
|
92
85
|
output(result)
|
|
93
86
|
end
|
|
94
87
|
|
|
@@ -98,12 +91,6 @@ module Agentf
|
|
|
98
91
|
output(result)
|
|
99
92
|
end
|
|
100
93
|
|
|
101
|
-
def list_successes(args)
|
|
102
|
-
limit = extract_limit(args)
|
|
103
|
-
result = @reviewer.get_successes(limit: limit)
|
|
104
|
-
output(result)
|
|
105
|
-
end
|
|
106
|
-
|
|
107
94
|
def list_intents(args)
|
|
108
95
|
limit = extract_limit(args)
|
|
109
96
|
kind = args.shift
|
|
@@ -141,16 +128,14 @@ module Agentf
|
|
|
141
128
|
exit 1
|
|
142
129
|
end
|
|
143
130
|
|
|
144
|
-
tags = parse_list_option(args, "--tags=")
|
|
145
131
|
constraints = parse_list_option(args, "--constraints=")
|
|
146
132
|
priority = parse_integer_option(args, "--priority=", default: 1)
|
|
147
133
|
|
|
148
134
|
id = nil
|
|
149
|
-
res = safe_cli_memory_write(@memory, attempted: { command: "add-business-intent", args: { title: title, description: description,
|
|
135
|
+
res = safe_cli_memory_write(@memory, attempted: { command: "add-business-intent", args: { title: title, description: description, constraints: constraints, priority: priority } }) do
|
|
150
136
|
id = @memory.store_business_intent(
|
|
151
137
|
title: title,
|
|
152
138
|
description: description,
|
|
153
|
-
tags: tags,
|
|
154
139
|
constraints: constraints,
|
|
155
140
|
priority: priority
|
|
156
141
|
)
|
|
@@ -181,17 +166,15 @@ module Agentf
|
|
|
181
166
|
exit 1
|
|
182
167
|
end
|
|
183
168
|
|
|
184
|
-
tags = parse_list_option(args, "--tags=")
|
|
185
169
|
acceptance_criteria = parse_list_option(args, "--acceptance=")
|
|
186
170
|
non_goals = parse_list_option(args, "--non-goals=")
|
|
187
171
|
related_task_id = parse_single_option(args, "--task=")
|
|
188
172
|
|
|
189
173
|
id = nil
|
|
190
|
-
res = safe_cli_memory_write(@memory, attempted: { command: "add-feature-intent", args: { title: title, description: description,
|
|
174
|
+
res = safe_cli_memory_write(@memory, attempted: { command: "add-feature-intent", args: { title: title, description: description, acceptance: acceptance_criteria, non_goals: non_goals, related_task_id: related_task_id } }) do
|
|
191
175
|
id = @memory.store_feature_intent(
|
|
192
176
|
title: title,
|
|
193
177
|
description: description,
|
|
194
|
-
tags: tags,
|
|
195
178
|
acceptance_criteria: acceptance_criteria,
|
|
196
179
|
non_goals: non_goals,
|
|
197
180
|
related_task_id: related_task_id
|
|
@@ -214,6 +197,46 @@ module Agentf
|
|
|
214
197
|
end
|
|
215
198
|
end
|
|
216
199
|
|
|
200
|
+
def add_playbook(args)
|
|
201
|
+
title = args.shift
|
|
202
|
+
description = args.shift
|
|
203
|
+
|
|
204
|
+
if title.to_s.empty? || description.to_s.empty?
|
|
205
|
+
$stderr.puts "Error: add-playbook requires <title> <description>"
|
|
206
|
+
exit 1
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
steps = parse_list_option(args, "--steps=")
|
|
210
|
+
feature_area = parse_single_option(args, "--feature-area=")
|
|
211
|
+
agent = parse_single_option(args, "--agent=") || Agentf::AgentRoles::PLANNER
|
|
212
|
+
|
|
213
|
+
id = nil
|
|
214
|
+
res = safe_cli_memory_write(@memory, attempted: { command: "add-playbook", args: { title: title, description: description, steps: steps, feature_area: feature_area, agent: agent } }) do
|
|
215
|
+
id = @memory.store_playbook(
|
|
216
|
+
title: title,
|
|
217
|
+
description: description,
|
|
218
|
+
steps: steps,
|
|
219
|
+
feature_area: feature_area,
|
|
220
|
+
agent: agent
|
|
221
|
+
)
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
if res.is_a?(Hash) && res["confirmation_required"]
|
|
225
|
+
if @json_output
|
|
226
|
+
puts JSON.generate(res)
|
|
227
|
+
else
|
|
228
|
+
$stderr.puts "Confirmation required to store playbook: #{res['confirmation_details'].inspect}"
|
|
229
|
+
end
|
|
230
|
+
return
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
if @json_output
|
|
234
|
+
puts JSON.generate({ "id" => id, "type" => "playbook", "status" => "stored" })
|
|
235
|
+
else
|
|
236
|
+
puts "Stored playbook: #{id}"
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
|
|
217
240
|
def add_episode(type, args)
|
|
218
241
|
title = args.shift
|
|
219
242
|
description = args.shift
|
|
@@ -223,21 +246,21 @@ module Agentf
|
|
|
223
246
|
exit 1
|
|
224
247
|
end
|
|
225
248
|
|
|
226
|
-
tags = parse_list_option(args, "--tags=")
|
|
227
249
|
context = parse_single_option(args, "--context=").to_s
|
|
228
250
|
agent = parse_single_option(args, "--agent=") || Agentf::AgentRoles::ENGINEER
|
|
229
251
|
code_snippet = parse_single_option(args, "--code=").to_s
|
|
252
|
+
outcome = parse_single_option(args, "--outcome=")
|
|
230
253
|
|
|
231
254
|
id = nil
|
|
232
|
-
res = safe_cli_memory_write(@memory, attempted: { command: "add-#{type}", args: { title: title, description: description,
|
|
255
|
+
res = safe_cli_memory_write(@memory, attempted: { command: "add-#{type}", args: { title: title, description: description, context: context, agent: agent, code: code_snippet, outcome: outcome } }) do
|
|
233
256
|
id = @memory.store_episode(
|
|
234
257
|
type: type,
|
|
235
258
|
title: title,
|
|
236
259
|
description: description,
|
|
237
260
|
context: context,
|
|
238
|
-
tags: tags,
|
|
239
261
|
agent: agent,
|
|
240
|
-
code_snippet: code_snippet
|
|
262
|
+
code_snippet: code_snippet,
|
|
263
|
+
outcome: outcome
|
|
241
264
|
)
|
|
242
265
|
end
|
|
243
266
|
|
|
@@ -273,21 +296,6 @@ module Agentf
|
|
|
273
296
|
end
|
|
274
297
|
end
|
|
275
298
|
|
|
276
|
-
def list_tags
|
|
277
|
-
result = @reviewer.get_all_tags
|
|
278
|
-
if @json_output
|
|
279
|
-
puts JSON.generate(result)
|
|
280
|
-
return
|
|
281
|
-
end
|
|
282
|
-
|
|
283
|
-
if result["tags"].empty?
|
|
284
|
-
puts "No tags found."
|
|
285
|
-
else
|
|
286
|
-
puts "Tags (#{result["count"]}):"
|
|
287
|
-
result["tags"].each { |tag| puts " - #{tag}" }
|
|
288
|
-
end
|
|
289
|
-
end
|
|
290
|
-
|
|
291
299
|
def search_memories(args)
|
|
292
300
|
# Extract limit BEFORE joining remaining args as query (fixes finding #7)
|
|
293
301
|
limit = extract_limit(args)
|
|
@@ -318,19 +326,12 @@ module Agentf
|
|
|
318
326
|
puts ""
|
|
319
327
|
puts "By agent:"
|
|
320
328
|
result["by_agent"].each { |agent, count| puts " #{agent}: #{count}" }
|
|
321
|
-
puts ""
|
|
322
|
-
puts "Unique tags: #{result["unique_tags"]}"
|
|
323
|
-
end
|
|
324
329
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
exit 1
|
|
330
|
+
if result["by_outcome"].is_a?(Hash)
|
|
331
|
+
puts ""
|
|
332
|
+
puts "By outcome:"
|
|
333
|
+
result["by_outcome"].each { |outcome, count| puts " #{outcome}: #{count}" }
|
|
330
334
|
end
|
|
331
|
-
limit = extract_limit(args)
|
|
332
|
-
result = @reviewer.get_by_tag(tag, limit: limit)
|
|
333
|
-
output(result)
|
|
334
335
|
end
|
|
335
336
|
|
|
336
337
|
def by_agent(args)
|
|
@@ -540,8 +541,8 @@ module Agentf
|
|
|
540
541
|
[#{mem["type"]&.upcase}] #{mem["title"]}
|
|
541
542
|
#{mem["created_at"]} by #{mem["agent"]}
|
|
542
543
|
#{mem["description"]}
|
|
544
|
+
#{"Outcome: #{mem['outcome']}" unless mem["outcome"].to_s.empty?}
|
|
543
545
|
#{format_code(mem["code_snippet"]) unless mem["code_snippet"].to_s.empty?}
|
|
544
|
-
Tags: #{mem["tags"]&.join(", ") || "none"}
|
|
545
546
|
OUTPUT
|
|
546
547
|
end
|
|
547
548
|
|
|
@@ -557,26 +558,22 @@ module Agentf
|
|
|
557
558
|
|
|
558
559
|
Commands:
|
|
559
560
|
recent, list List recent memories (default: 10)
|
|
560
|
-
|
|
561
|
+
episodes List episode memories
|
|
561
562
|
lessons List lessons learned
|
|
562
|
-
successes List successes
|
|
563
563
|
intents [kind] List intents (kind: business|feature)
|
|
564
564
|
business-intents List business intents
|
|
565
565
|
feature-intents List feature intents
|
|
566
566
|
add-business-intent Store business intent
|
|
567
567
|
add-feature-intent Store feature intent
|
|
568
|
+
add-playbook Store playbook memory
|
|
568
569
|
add-lesson Store lesson memory
|
|
569
|
-
|
|
570
|
-
add-pitfall Store pitfall memory
|
|
571
|
-
tags List all unique tags
|
|
572
|
-
search <query> Search memories by keyword
|
|
570
|
+
search <query> Search memories semantically
|
|
573
571
|
delete id <memory_id> Delete one memory and related edges
|
|
574
572
|
delete last -n <count> Delete most recent memories
|
|
575
573
|
delete all Delete memories and graph/task keys
|
|
576
574
|
neighbors <id> Traverse graph edges from a memory id
|
|
577
575
|
subgraph <ids> Build graph from comma-separated seed ids
|
|
578
576
|
summary, stats Show summary statistics
|
|
579
|
-
by-tag <tag> Get memories with specific tag
|
|
580
577
|
by-agent <agent> Get memories from specific agent
|
|
581
578
|
by-type <type> Get memories by type (#{VALID_EPISODE_TYPES.join("|")})
|
|
582
579
|
|
|
@@ -586,18 +583,17 @@ module Agentf
|
|
|
586
583
|
|
|
587
584
|
Examples:
|
|
588
585
|
agentf memory recent -n 5
|
|
589
|
-
agentf memory
|
|
586
|
+
agentf memory episodes --outcome=negative
|
|
590
587
|
agentf memory intents business -n 5
|
|
591
|
-
agentf memory add-business-intent "Reliability" "Prioritize uptime" --
|
|
588
|
+
agentf memory add-business-intent "Reliability" "Prioritize uptime" --constraints="No downtime;No vendor lock-in"
|
|
592
589
|
agentf memory add-feature-intent "Agent handoff" "Improve orchestrator continuity" --acceptance="Keeps context;Preserves task state"
|
|
593
|
-
agentf memory add-
|
|
594
|
-
agentf memory add-
|
|
590
|
+
agentf memory add-playbook "Release rollout" "Safe deploy sequence" --steps="deploy canary;monitor;promote"
|
|
591
|
+
agentf memory add-lesson "Refactor strategy" "Extracted adapter seam" --agent=PLANNER
|
|
595
592
|
agentf memory search "react"
|
|
596
593
|
agentf memory delete id episode_abcd
|
|
597
594
|
agentf memory delete last -n 10 --scope=project
|
|
598
595
|
agentf memory delete all --scope=all --yes
|
|
599
596
|
agentf memory neighbors episode_abcd --depth=2
|
|
600
|
-
agentf memory by-tag "performance"
|
|
601
597
|
agentf memory summary
|
|
602
598
|
HELP
|
|
603
599
|
end
|
data/lib/agentf/cli/router.rb
CHANGED
|
@@ -75,7 +75,7 @@ module Agentf
|
|
|
75
75
|
Usage: agentf <command> [subcommand] [options]
|
|
76
76
|
|
|
77
77
|
Commands:
|
|
78
|
-
memory Manage agent memory (
|
|
78
|
+
memory Manage agent memory (episodes, lessons, playbooks, intents)
|
|
79
79
|
code Explore codebase (glob, grep, tree, related files)
|
|
80
80
|
metrics Show workflow success and provider parity metrics
|
|
81
81
|
architecture Analyze architecture layers and violations
|