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
|
@@ -12,14 +12,11 @@ module Agentf
|
|
|
12
12
|
def self.manifest
|
|
13
13
|
{
|
|
14
14
|
"name" => NAME,
|
|
15
|
-
"description" => "Review and query Redis-stored memories,
|
|
15
|
+
"description" => "Review and query Redis-stored memories, episodes, and learnings.",
|
|
16
16
|
"commands" => [
|
|
17
17
|
{ "name" => "get_recent_memories", "type" => "function" },
|
|
18
|
-
{ "name" => "
|
|
18
|
+
{ "name" => "get_episodes", "type" => "function" },
|
|
19
19
|
{ "name" => "get_lessons", "type" => "function" },
|
|
20
|
-
{ "name" => "get_successes", "type" => "function" },
|
|
21
|
-
{ "name" => "get_all_tags", "type" => "function" },
|
|
22
|
-
{ "name" => "get_by_tag", "type" => "function" },
|
|
23
20
|
{ "name" => "get_by_type", "type" => "function" },
|
|
24
21
|
{ "name" => "get_by_agent", "type" => "function" },
|
|
25
22
|
{ "name" => "search", "type" => "function" },
|
|
@@ -44,10 +41,9 @@ module Agentf
|
|
|
44
41
|
{ "error" => e.message }
|
|
45
42
|
end
|
|
46
43
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
format_memories(pitfalls)
|
|
44
|
+
def get_episodes(limit: 10, outcome: nil)
|
|
45
|
+
episodes = @memory.get_episodes(limit: limit, outcome: outcome)
|
|
46
|
+
format_memories(episodes)
|
|
51
47
|
rescue => e
|
|
52
48
|
{ "error" => e.message }
|
|
53
49
|
end
|
|
@@ -60,14 +56,6 @@ module Agentf
|
|
|
60
56
|
{ "error" => e.message }
|
|
61
57
|
end
|
|
62
58
|
|
|
63
|
-
# Get all successes
|
|
64
|
-
def get_successes(limit: 10)
|
|
65
|
-
successes = @memory.get_memories_by_type(type: "success", limit: limit)
|
|
66
|
-
format_memories(successes)
|
|
67
|
-
rescue => e
|
|
68
|
-
{ "error" => e.message }
|
|
69
|
-
end
|
|
70
|
-
|
|
71
59
|
def get_business_intents(limit: 10)
|
|
72
60
|
intents = @memory.get_intents(kind: "business", limit: limit)
|
|
73
61
|
format_memories(intents)
|
|
@@ -89,28 +77,10 @@ module Agentf
|
|
|
89
77
|
{ "error" => e.message }
|
|
90
78
|
end
|
|
91
79
|
|
|
92
|
-
# Get all unique tags from memories
|
|
93
|
-
def get_all_tags
|
|
94
|
-
tags = @memory.get_all_tags
|
|
95
|
-
{ "tags" => tags.sort, "count" => tags.length }
|
|
96
|
-
rescue => e
|
|
97
|
-
{ "error" => e.message }
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
# Get memories by tag
|
|
101
|
-
def get_by_tag(tag, limit: 10)
|
|
102
|
-
memories = @memory.get_recent_memories(limit: 100)
|
|
103
|
-
filtered = memories.select { |m| m["tags"]&.include?(tag) }
|
|
104
|
-
format_memories(filtered.first(limit))
|
|
105
|
-
rescue => e
|
|
106
|
-
{ "error" => e.message }
|
|
107
|
-
end
|
|
108
|
-
|
|
109
80
|
# Get memories by type (pitfall, lesson, success)
|
|
110
81
|
def get_by_type(type, limit: 10)
|
|
111
|
-
memories = @memory.
|
|
112
|
-
|
|
113
|
-
format_memories(filtered.first(limit))
|
|
82
|
+
memories = @memory.get_memories_by_type(type: type, limit: limit)
|
|
83
|
+
format_memories(memories)
|
|
114
84
|
rescue => e
|
|
115
85
|
{ "error" => e.message }
|
|
116
86
|
end
|
|
@@ -126,14 +96,7 @@ module Agentf
|
|
|
126
96
|
|
|
127
97
|
# Search memories by keyword in title or description
|
|
128
98
|
def search(query, limit: 10)
|
|
129
|
-
|
|
130
|
-
q = query.downcase
|
|
131
|
-
filtered = memories.select do |m|
|
|
132
|
-
m["title"]&.downcase&.include?(q) ||
|
|
133
|
-
m["description"]&.downcase&.include?(q) ||
|
|
134
|
-
m["context"]&.downcase&.include?(q)
|
|
135
|
-
end
|
|
136
|
-
format_memories(filtered.first(limit))
|
|
99
|
+
format_memories(@memory.search_memories(query: query, limit: limit))
|
|
137
100
|
rescue => e
|
|
138
101
|
{ "error" => e.message }
|
|
139
102
|
end
|
|
@@ -141,19 +104,22 @@ module Agentf
|
|
|
141
104
|
# Get summary statistics
|
|
142
105
|
def get_summary
|
|
143
106
|
memories = @memory.get_recent_memories(limit: 100)
|
|
144
|
-
tags = @memory.get_all_tags
|
|
145
107
|
|
|
146
108
|
{
|
|
147
109
|
"total_memories" => memories.length,
|
|
148
110
|
"by_type" => {
|
|
149
|
-
"
|
|
111
|
+
"episode" => memories.count { |m| m["type"] == "episode" },
|
|
150
112
|
"lesson" => memories.count { |m| m["type"] == "lesson" },
|
|
151
|
-
"
|
|
113
|
+
"playbook" => memories.count { |m| m["type"] == "playbook" },
|
|
152
114
|
"business_intent" => memories.count { |m| m["type"] == "business_intent" },
|
|
153
115
|
"feature_intent" => memories.count { |m| m["type"] == "feature_intent" }
|
|
154
116
|
},
|
|
117
|
+
"by_outcome" => {
|
|
118
|
+
"positive" => memories.count { |m| m["outcome"] == "positive" },
|
|
119
|
+
"negative" => memories.count { |m| m["outcome"] == "negative" },
|
|
120
|
+
"neutral" => memories.count { |m| m["outcome"] == "neutral" }
|
|
121
|
+
},
|
|
155
122
|
"by_agent" => memories.each_with_object(Hash.new(0)) { |m, h| h[m["agent"]] += 1 },
|
|
156
|
-
"unique_tags" => tags.length,
|
|
157
123
|
"project" => @project
|
|
158
124
|
}
|
|
159
125
|
rescue => e
|
|
@@ -189,7 +155,7 @@ module Agentf
|
|
|
189
155
|
"description" => m["description"],
|
|
190
156
|
"context" => m["context"],
|
|
191
157
|
"code_snippet" => m["code_snippet"],
|
|
192
|
-
"
|
|
158
|
+
"outcome" => m["outcome"],
|
|
193
159
|
"agent" => m["agent"],
|
|
194
160
|
"metadata" => m["metadata"],
|
|
195
161
|
"entity_ids" => m["entity_ids"],
|
|
@@ -7,8 +7,6 @@ module Agentf
|
|
|
7
7
|
class Metrics
|
|
8
8
|
NAME = "metrics"
|
|
9
9
|
|
|
10
|
-
WORKFLOW_METRICS_TAG = "workflow_metric"
|
|
11
|
-
|
|
12
10
|
def self.manifest
|
|
13
11
|
{
|
|
14
12
|
"name" => NAME,
|
|
@@ -30,12 +28,13 @@ module Agentf
|
|
|
30
28
|
metrics = extract_metrics(workflow_state)
|
|
31
29
|
begin
|
|
32
30
|
@memory.store_episode(
|
|
33
|
-
type: "
|
|
31
|
+
type: "episode",
|
|
34
32
|
title: metric_title(metrics),
|
|
35
33
|
description: metric_description(metrics),
|
|
36
34
|
context: metric_context(metrics),
|
|
37
|
-
tags: metric_tags(metrics),
|
|
38
35
|
agent: Agentf::AgentRoles::ORCHESTRATOR,
|
|
36
|
+
outcome: "positive",
|
|
37
|
+
metadata: { "workflow_metric" => true },
|
|
39
38
|
code_snippet: ""
|
|
40
39
|
)
|
|
41
40
|
{ "status" => "recorded", "metrics" => metrics }
|
|
@@ -171,14 +170,6 @@ module Agentf
|
|
|
171
170
|
}.to_json
|
|
172
171
|
end
|
|
173
172
|
|
|
174
|
-
def metric_tags(metrics)
|
|
175
|
-
[
|
|
176
|
-
WORKFLOW_METRICS_TAG,
|
|
177
|
-
"provider:#{metrics['provider'].to_s.downcase}",
|
|
178
|
-
"workflow:#{metrics['workflow_type']}"
|
|
179
|
-
]
|
|
180
|
-
end
|
|
181
|
-
|
|
182
173
|
def top_contract_violations(records)
|
|
183
174
|
counts = Hash.new(0)
|
|
184
175
|
records.each do |record|
|
|
@@ -191,7 +182,7 @@ module Agentf
|
|
|
191
182
|
memories = @memory.get_recent_memories(limit: limit)
|
|
192
183
|
|
|
193
184
|
memories
|
|
194
|
-
.select { |m|
|
|
185
|
+
.select { |m| m.dig("metadata", "workflow_metric") == true }
|
|
195
186
|
.map do |m|
|
|
196
187
|
context = parse_context_json(m["context"])
|
|
197
188
|
context
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
module Agentf
|
|
4
4
|
class ContextBuilder
|
|
5
|
-
def initialize(memory:)
|
|
5
|
+
def initialize(memory:, embedding_provider: Agentf::EmbeddingProvider.new)
|
|
6
6
|
@memory = memory
|
|
7
|
+
@embedding_provider = embedding_provider
|
|
7
8
|
end
|
|
8
9
|
|
|
9
10
|
def build(agent:, workflow_state:, limit: 8)
|
|
@@ -13,23 +14,12 @@ module Agentf
|
|
|
13
14
|
@memory.get_agent_context(
|
|
14
15
|
agent: agent,
|
|
15
16
|
task_type: task_type,
|
|
16
|
-
|
|
17
|
+
query_text: task,
|
|
18
|
+
query_embedding: @embedding_provider.embed(task),
|
|
17
19
|
limit: limit
|
|
18
20
|
)
|
|
19
21
|
rescue StandardError
|
|
20
22
|
{ "agent" => agent, "intent" => [], "memories" => [], "similar_tasks" => [] }
|
|
21
23
|
end
|
|
22
|
-
|
|
23
|
-
private
|
|
24
|
-
|
|
25
|
-
def simple_embedding(text)
|
|
26
|
-
normalized = text.to_s.downcase
|
|
27
|
-
[
|
|
28
|
-
normalized.include?("fix") || normalized.include?("bug") ? 1.0 : 0.0,
|
|
29
|
-
normalized.include?("feature") || normalized.include?("add") ? 1.0 : 0.0,
|
|
30
|
-
normalized.include?("security") ? 1.0 : 0.0,
|
|
31
|
-
normalized.length.to_f / 100.0
|
|
32
|
-
]
|
|
33
|
-
end
|
|
34
24
|
end
|
|
35
25
|
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "digest"
|
|
4
|
+
|
|
5
|
+
module Agentf
|
|
6
|
+
class EmbeddingProvider
|
|
7
|
+
DIMENSIONS = 64
|
|
8
|
+
|
|
9
|
+
def initialize(dimensions: DIMENSIONS)
|
|
10
|
+
@dimensions = dimensions
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def embed(text)
|
|
14
|
+
tokens = tokenize(text)
|
|
15
|
+
return [] if tokens.empty?
|
|
16
|
+
|
|
17
|
+
vector = Array.new(@dimensions, 0.0)
|
|
18
|
+
tokens.each do |token|
|
|
19
|
+
hash = Digest::SHA256.hexdigest(token)[0, 8].to_i(16)
|
|
20
|
+
vector[hash % @dimensions] += 1.0
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
magnitude = Math.sqrt(vector.sum { |value| value * value })
|
|
24
|
+
return vector if magnitude.zero?
|
|
25
|
+
|
|
26
|
+
vector.map { |value| (value / magnitude).round(8) }
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def tokenize(text)
|
|
32
|
+
text.to_s.downcase.scan(/[a-z0-9_]+/).reject { |token| token.length < 2 }
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
data/lib/agentf/installer.rb
CHANGED
|
@@ -9,12 +9,9 @@ module Agentf
|
|
|
9
9
|
class Installer
|
|
10
10
|
READ_ACTIONS = {
|
|
11
11
|
"get_recent_memories" => { cli: "agentf memory recent -n 10", tool: "agentf-memory-recent" },
|
|
12
|
-
"
|
|
12
|
+
"get_episodes" => { cli: "agentf memory episodes -n 10", tool: "agentf-memory-episodes" },
|
|
13
13
|
"get_lessons" => { cli: "agentf memory lessons -n 10", tool: "agentf-memory-recent" },
|
|
14
|
-
"get_successes" => { cli: "agentf memory successes -n 10", tool: "agentf-memory-recent" },
|
|
15
14
|
"get_intents" => { cli: "agentf memory intents", tool: "agentf-memory-recent" },
|
|
16
|
-
"get_all_tags" => { cli: "agentf memory tags", tool: "agentf-memory-recent" },
|
|
17
|
-
"get_by_tag" => { cli: "agentf memory by-tag <tag> -n 10", tool: "agentf-memory-search" },
|
|
18
15
|
"get_by_type" => { cli: "agentf memory by-type <type> -n 10", tool: "agentf-memory-search" },
|
|
19
16
|
"get_by_agent" => { cli: "agentf memory by-agent <agent> -n 10", tool: "agentf-memory-search" },
|
|
20
17
|
"search" => { cli: "agentf memory search \"<query>\" -n 10", tool: "agentf-memory-search" },
|
|
@@ -22,10 +19,10 @@ module Agentf
|
|
|
22
19
|
}.freeze
|
|
23
20
|
|
|
24
21
|
WRITE_ACTIONS = {
|
|
25
|
-
"store_lesson" => { cli: "agentf memory add-lesson \"<title>\" \"<description>\" --agent=<AGENT>
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"store_business_intent" => { cli: "agentf memory add-business-intent \"<title>\" \"<description>\"
|
|
22
|
+
"store_lesson" => { cli: "agentf memory add-lesson \"<title>\" \"<description>\" --agent=<AGENT>", tool: "agentf-memory-add-lesson" },
|
|
23
|
+
"store_episode" => { cli: "agentf memory add-episode \"<title>\" \"<description>\" --outcome=positive --agent=<AGENT>", tool: "agentf-memory-episodes" },
|
|
24
|
+
"store_playbook" => { cli: "agentf memory add-playbook \"<title>\" \"<description>\" --steps=\"<step1>;<step2>\"", tool: "agentf-memory-add-playbook" },
|
|
25
|
+
"store_business_intent" => { cli: "agentf memory add-business-intent \"<title>\" \"<description>\"", tool: "agentf-memory-add-business-intent" },
|
|
29
26
|
"store_feature_intent" => { cli: "agentf memory add-feature-intent \"<title>\" \"<description>\" --acceptance=\"<criteria>\"", tool: "agentf-memory-add-feature-intent" }
|
|
30
27
|
}.freeze
|
|
31
28
|
|
|
@@ -84,6 +81,7 @@ module Agentf
|
|
|
84
81
|
writes.concat(write_agents(root: root, layout: layout, provider: provider, only_agents: only_agents))
|
|
85
82
|
writes.concat(write_commands(root: root, layout: layout, provider: provider, only_commands: only_commands))
|
|
86
83
|
writes.concat(write_opencode_helpers(root: root)) if provider.to_s == "opencode"
|
|
84
|
+
writes.concat(write_copilot_helpers(root: root)) if provider.to_s == "copilot"
|
|
87
85
|
end
|
|
88
86
|
|
|
89
87
|
# Optionally install dependencies for opencode helper package.json
|
|
@@ -195,6 +193,12 @@ module Agentf
|
|
|
195
193
|
writes
|
|
196
194
|
end
|
|
197
195
|
|
|
196
|
+
def write_copilot_helpers(root:)
|
|
197
|
+
return [] unless root == @local_root
|
|
198
|
+
|
|
199
|
+
[write_copilot_mcp_json(root)]
|
|
200
|
+
end
|
|
201
|
+
|
|
198
202
|
def opencode_plugin_runtime?
|
|
199
203
|
@opencode_runtime == "plugin"
|
|
200
204
|
end
|
|
@@ -351,8 +355,8 @@ module Agentf
|
|
|
351
355
|
Copilot should call the local `agentf` MCP server tools for runtime actions.
|
|
352
356
|
|
|
353
357
|
- Code discovery tools: `agentf-code-glob`, `agentf-code-grep`, `agentf-code-tree`, `agentf-code-related-files`
|
|
354
|
-
- Memory read tools: `agentf-memory-recent`, `agentf-memory-search`
|
|
355
|
-
- Memory write tools (if enabled): `agentf-memory-add-lesson`, `agentf-memory-add-
|
|
358
|
+
- Memory read tools: `agentf-memory-recent`, `agentf-memory-search`, `agentf-memory-episodes`
|
|
359
|
+
- Memory write tools (if enabled): `agentf-memory-add-lesson`, `agentf-memory-add-playbook`
|
|
356
360
|
|
|
357
361
|
MCP server is started via `agentf mcp-server` and runs locally over stdio.
|
|
358
362
|
MARKDOWN
|
|
@@ -365,8 +369,8 @@ module Agentf
|
|
|
365
369
|
recommended_tools = case command_name
|
|
366
370
|
when "explorer"
|
|
367
371
|
"`agentf-code-glob`, `agentf-code-grep`, `agentf-code-tree`, `agentf-code-related-files`"
|
|
368
|
-
|
|
369
|
-
|
|
372
|
+
when "memory"
|
|
373
|
+
"`agentf-memory-recent`, `agentf-memory-search`, `agentf-memory-episodes`, `agentf-memory-add-lesson`, `agentf-memory-add-playbook`"
|
|
370
374
|
else
|
|
371
375
|
"`agentf-code-glob`, `agentf-code-grep`, `agentf-memory-recent`, `agentf-memory-search`"
|
|
372
376
|
end
|
|
@@ -401,7 +405,7 @@ module Agentf
|
|
|
401
405
|
1. Build plan from provider adapter (`Agentf::Service::Providers::OpenCode` or `Agentf::Service::Providers::Copilot`)
|
|
402
406
|
2. Enrich each agent step with brain context from Redis memory
|
|
403
407
|
3. Persist feature intent at workflow start
|
|
404
|
-
4. Persist lessons
|
|
408
|
+
4. Persist lessons and negative episodes from each agent execution
|
|
405
409
|
5. Return full workflow state for manual review and future autonomous control
|
|
406
410
|
6. Enforce workflow contract stages (`spec`, `plan`, `execute`, `review`, `finalize`) when enabled
|
|
407
411
|
|
|
@@ -691,17 +695,6 @@ module Agentf
|
|
|
691
695
|
return runAgentfCli(context.directory, "memory", "search", [_args.query, "-n", String(limit)]);
|
|
692
696
|
},
|
|
693
697
|
}),
|
|
694
|
-
"agentf-memory-by-tag": tool({
|
|
695
|
-
description: "Get Agentf memories by tag.",
|
|
696
|
-
args: {
|
|
697
|
-
tag: tool.schema.string().describe("Tag to filter by"),
|
|
698
|
-
limit: tool.schema.number().int().min(1).max(100).optional().describe("How many results to return"),
|
|
699
|
-
},
|
|
700
|
-
async execute(_args: any, context: any) {
|
|
701
|
-
const limit = _args.limit ?? 10;
|
|
702
|
-
return runAgentfCli(context.directory, "memory", "by-tag", [_args.tag, "-n", String(limit)]);
|
|
703
|
-
},
|
|
704
|
-
}),
|
|
705
698
|
"agentf-memory-by-agent": tool({
|
|
706
699
|
description: "Get Agentf memories by agent.",
|
|
707
700
|
args: {
|
|
@@ -716,7 +709,7 @@ module Agentf
|
|
|
716
709
|
"agentf-memory-by-type": tool({
|
|
717
710
|
description: "Get Agentf memories by type.",
|
|
718
711
|
args: {
|
|
719
|
-
type: tool.schema.string().describe("Memory type (
|
|
712
|
+
type: tool.schema.string().describe("Memory type (episode|lesson|playbook|business_intent|feature_intent|incident)"),
|
|
720
713
|
limit: tool.schema.number().int().min(1).max(100).optional().describe("How many results to return"),
|
|
721
714
|
},
|
|
722
715
|
async execute(_args: any, context: any) {
|
|
@@ -724,19 +717,17 @@ module Agentf
|
|
|
724
717
|
return runAgentfCli(context.directory, "memory", "by-type", [_args.type, "-n", String(limit)]);
|
|
725
718
|
},
|
|
726
719
|
}),
|
|
727
|
-
"agentf-memory-
|
|
728
|
-
description: "List
|
|
729
|
-
args: {
|
|
730
|
-
|
|
731
|
-
|
|
720
|
+
"agentf-memory-episodes": tool({
|
|
721
|
+
description: "List episode memories.",
|
|
722
|
+
args: {
|
|
723
|
+
outcome: tool.schema.string().optional().describe("Optional outcome filter (positive|negative|neutral)"),
|
|
724
|
+
limit: tool.schema.number().int().min(1).max(100).optional(),
|
|
732
725
|
},
|
|
733
|
-
}),
|
|
734
|
-
"agentf-memory-pitfalls": tool({
|
|
735
|
-
description: "List pitfall memories.",
|
|
736
|
-
args: { limit: tool.schema.number().int().min(1).max(100).optional() },
|
|
737
726
|
async execute(_args: any, context: any) {
|
|
738
727
|
const limit = _args.limit ?? 10;
|
|
739
|
-
|
|
728
|
+
const commandArgs = ["-n", String(limit)];
|
|
729
|
+
if (_args.outcome) commandArgs.push(`--outcome=${_args.outcome}`);
|
|
730
|
+
return runAgentfCli(context.directory, "memory", "episodes", commandArgs);
|
|
740
731
|
},
|
|
741
732
|
}),
|
|
742
733
|
"agentf-memory-lessons": tool({
|
|
@@ -747,14 +738,6 @@ module Agentf
|
|
|
747
738
|
return runAgentfCli(context.directory, "memory", "lessons", ["-n", String(limit)]);
|
|
748
739
|
},
|
|
749
740
|
}),
|
|
750
|
-
"agentf-memory-successes": tool({
|
|
751
|
-
description: "List success memories.",
|
|
752
|
-
args: { limit: tool.schema.number().int().min(1).max(100).optional() },
|
|
753
|
-
async execute(_args: any, context: any) {
|
|
754
|
-
const limit = _args.limit ?? 10;
|
|
755
|
-
return runAgentfCli(context.directory, "memory", "successes", ["-n", String(limit)]);
|
|
756
|
-
},
|
|
757
|
-
}),
|
|
758
741
|
"agentf-memory-intents": tool({
|
|
759
742
|
description: "List intents (business, feature or both).",
|
|
760
743
|
args: { kind: tool.schema.string().optional(), limit: tool.schema.number().int().min(1).max(100).optional() },
|
|
@@ -786,13 +769,11 @@ module Agentf
|
|
|
786
769
|
args: {
|
|
787
770
|
title: tool.schema.string(),
|
|
788
771
|
description: tool.schema.string(),
|
|
789
|
-
tags: tool.schema.array(tool.schema.string()).optional(),
|
|
790
772
|
constraints: tool.schema.array(tool.schema.string()).optional(),
|
|
791
773
|
priority: tool.schema.number().int().optional(),
|
|
792
774
|
},
|
|
793
775
|
async execute(_args: any, context: any) {
|
|
794
776
|
const commandArgs = [_args.title, _args.description];
|
|
795
|
-
if (_args.tags?.length) commandArgs.push(`--tags=${_args.tags.join(",")}`);
|
|
796
777
|
if (_args.constraints?.length) commandArgs.push(`--constraints=${_args.constraints.join(";")}`);
|
|
797
778
|
if (Number.isInteger(_args.priority)) commandArgs.push(`--priority=${String(_args.priority)}`);
|
|
798
779
|
return runAgentfCli(context.directory, "memory", "add-business-intent", commandArgs);
|
|
@@ -803,14 +784,12 @@ module Agentf
|
|
|
803
784
|
args: {
|
|
804
785
|
title: tool.schema.string(),
|
|
805
786
|
description: tool.schema.string(),
|
|
806
|
-
tags: tool.schema.array(tool.schema.string()).optional(),
|
|
807
787
|
acceptance: tool.schema.array(tool.schema.string()).optional(),
|
|
808
788
|
non_goals: tool.schema.array(tool.schema.string()).optional(),
|
|
809
789
|
related_task_id: tool.schema.string().optional(),
|
|
810
790
|
},
|
|
811
791
|
async execute(_args: any, context: any) {
|
|
812
792
|
const commandArgs = [_args.title, _args.description];
|
|
813
|
-
if (_args.tags?.length) commandArgs.push(`--tags=${_args.tags.join(",")}`);
|
|
814
793
|
if (_args.acceptance?.length) commandArgs.push(`--acceptance=${_args.acceptance.join(";")}`);
|
|
815
794
|
if (_args.non_goals?.length) commandArgs.push(`--non-goals=${_args.non_goals.join(";")}`);
|
|
816
795
|
if (_args.related_task_id) commandArgs.push(`--task=${_args.related_task_id}`);
|
|
@@ -856,52 +835,32 @@ module Agentf
|
|
|
856
835
|
title: tool.schema.string(),
|
|
857
836
|
description: tool.schema.string(),
|
|
858
837
|
agent: tool.schema.string().optional(),
|
|
859
|
-
tags: tool.schema.array(tool.schema.string()).optional(),
|
|
860
838
|
context: tool.schema.string().optional(),
|
|
861
839
|
},
|
|
862
840
|
async execute(_args: any, context: any) {
|
|
863
841
|
const commandArgs = [_args.title, _args.description];
|
|
864
842
|
if (_args.agent) commandArgs.push(`--agent=${_args.agent}`);
|
|
865
|
-
if (_args.tags?.length) commandArgs.push(`--tags=${_args.tags.join(",")}`);
|
|
866
843
|
if (_args.context) commandArgs.push(`--context=${_args.context}`);
|
|
867
844
|
|
|
868
845
|
return runAgentfCli(context.directory, "memory", "add-lesson", commandArgs);
|
|
869
846
|
},
|
|
870
847
|
}),
|
|
871
|
-
"agentf-memory-add-
|
|
872
|
-
description: "Store a
|
|
873
|
-
args: {
|
|
874
|
-
title: tool.schema.string(),
|
|
875
|
-
description: tool.schema.string(),
|
|
876
|
-
agent: tool.schema.string().optional(),
|
|
877
|
-
tags: tool.schema.array(tool.schema.string()).optional(),
|
|
878
|
-
context: tool.schema.string().optional(),
|
|
879
|
-
},
|
|
880
|
-
async execute(_args: any, context: any) {
|
|
881
|
-
const commandArgs = [_args.title, _args.description];
|
|
882
|
-
if (_args.agent) commandArgs.push(`--agent=${_args.agent}`);
|
|
883
|
-
if (_args.tags?.length) commandArgs.push(`--tags=${_args.tags.join(",")}`);
|
|
884
|
-
if (_args.context) commandArgs.push(`--context=${_args.context}`);
|
|
885
|
-
|
|
886
|
-
return runAgentfCli(context.directory, "memory", "add-success", commandArgs);
|
|
887
|
-
},
|
|
888
|
-
}),
|
|
889
|
-
"agentf-memory-add-pitfall": tool({
|
|
890
|
-
description: "Store a pitfall memory in Redis.",
|
|
848
|
+
"agentf-memory-add-playbook": tool({
|
|
849
|
+
description: "Store a playbook memory in Redis.",
|
|
891
850
|
args: {
|
|
892
851
|
title: tool.schema.string(),
|
|
893
852
|
description: tool.schema.string(),
|
|
894
853
|
agent: tool.schema.string().optional(),
|
|
895
|
-
|
|
896
|
-
|
|
854
|
+
steps: tool.schema.array(tool.schema.string()).optional(),
|
|
855
|
+
feature_area: tool.schema.string().optional(),
|
|
897
856
|
},
|
|
898
857
|
async execute(_args: any, context: any) {
|
|
899
858
|
const commandArgs = [_args.title, _args.description];
|
|
900
859
|
if (_args.agent) commandArgs.push(`--agent=${_args.agent}`);
|
|
901
|
-
if (_args.
|
|
902
|
-
if (_args.
|
|
860
|
+
if (_args.steps?.length) commandArgs.push(`--steps=${_args.steps.join(";")}`);
|
|
861
|
+
if (_args.feature_area) commandArgs.push(`--feature-area=${_args.feature_area}`);
|
|
903
862
|
|
|
904
|
-
return runAgentfCli(context.directory, "memory", "add-
|
|
863
|
+
return runAgentfCli(context.directory, "memory", "add-playbook", commandArgs);
|
|
905
864
|
},
|
|
906
865
|
}),
|
|
907
866
|
};
|
|
@@ -961,6 +920,10 @@ module Agentf
|
|
|
961
920
|
JSON.pretty_generate(opencode_json_config(root))
|
|
962
921
|
end
|
|
963
922
|
|
|
923
|
+
def render_copilot_mcp_json(root)
|
|
924
|
+
JSON.pretty_generate(copilot_mcp_config(root))
|
|
925
|
+
end
|
|
926
|
+
|
|
964
927
|
def opencode_json_config(root)
|
|
965
928
|
base = {
|
|
966
929
|
"$schema" => "https://opencode.ai/config.json"
|
|
@@ -1019,6 +982,37 @@ module Agentf
|
|
|
1019
982
|
write_manifest(path, JSON.pretty_generate(merged))
|
|
1020
983
|
end
|
|
1021
984
|
|
|
985
|
+
def copilot_mcp_config(root)
|
|
986
|
+
{
|
|
987
|
+
"servers" => {
|
|
988
|
+
"agentf" => {
|
|
989
|
+
"type" => "stdio",
|
|
990
|
+
"command" => "agentf",
|
|
991
|
+
"args" => ["mcp-server"]
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
end
|
|
996
|
+
|
|
997
|
+
def write_copilot_mcp_json(root)
|
|
998
|
+
path = File.join(root, ".vscode", "mcp.json")
|
|
999
|
+
new_content = JSON.parse(render_copilot_mcp_json(root))
|
|
1000
|
+
|
|
1001
|
+
return write_manifest(path, JSON.pretty_generate(new_content)) unless File.exist?(path)
|
|
1002
|
+
|
|
1003
|
+
begin
|
|
1004
|
+
existing = JSON.parse(File.read(path))
|
|
1005
|
+
rescue StandardError => e
|
|
1006
|
+
warn "Failed to parse existing #{path}: #{e.message}"
|
|
1007
|
+
return write_manifest(path, JSON.pretty_generate(new_content))
|
|
1008
|
+
end
|
|
1009
|
+
|
|
1010
|
+
merged = existing.dup
|
|
1011
|
+
merged["servers"] = (existing["servers"] || {}).merge(new_content.fetch("servers"))
|
|
1012
|
+
|
|
1013
|
+
write_manifest(path, JSON.pretty_generate(merged))
|
|
1014
|
+
end
|
|
1015
|
+
|
|
1022
1016
|
def render_opencode_tsconfig
|
|
1023
1017
|
<<~JSON
|
|
1024
1018
|
{
|
|
@@ -1093,19 +1087,20 @@ module Agentf
|
|
|
1093
1087
|
- `agent`: string
|
|
1094
1088
|
|
|
1095
1089
|
### 2. Episodic Memory (`episodic:*`)
|
|
1096
|
-
Used for
|
|
1090
|
+
Used for episode, lesson, playbook, and intent records.
|
|
1097
1091
|
|
|
1098
1092
|
**Search index**: `episodic:logs`
|
|
1099
1093
|
|
|
1100
1094
|
**Schema fields**:
|
|
1101
1095
|
- `$.id`
|
|
1102
1096
|
- `$.type`
|
|
1097
|
+
- `$.outcome`
|
|
1103
1098
|
- `$.title`
|
|
1104
1099
|
- `$.description`
|
|
1105
1100
|
- `$.project`
|
|
1106
1101
|
- `$.context`
|
|
1107
1102
|
- `$.code_snippet`
|
|
1108
|
-
- `$.
|
|
1103
|
+
- `$.embedding`
|
|
1109
1104
|
- `$.created_at`
|
|
1110
1105
|
- `$.agent`
|
|
1111
1106
|
- `$.related_task_id`
|
|
@@ -1116,9 +1111,9 @@ module Agentf
|
|
|
1116
1111
|
|
|
1117
1112
|
- Read recent: `agentf memory recent -n 10`
|
|
1118
1113
|
- Search: `agentf memory search "query" -n 10`
|
|
1114
|
+
- List episodes: `agentf memory episodes -n 10 --outcome=negative`
|
|
1119
1115
|
- Add lesson: `agentf memory add-lesson "<title>" "<description>" --agent=<AGENT>`
|
|
1120
|
-
- Add
|
|
1121
|
-
- Add pitfall: `agentf memory add-pitfall "<title>" "<description>" --agent=<AGENT>`
|
|
1116
|
+
- Add playbook: `agentf memory add-playbook "<title>" "<description>" --steps="<step1>;<step2>"`
|
|
1122
1117
|
MARKDOWN
|
|
1123
1118
|
end
|
|
1124
1119
|
end
|