agentf 0.3.0 → 0.4.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/agent_roles.rb +29 -0
- data/lib/agentf/agents/architect.rb +16 -0
- data/lib/agentf/agents/base.rb +12 -0
- data/lib/agentf/agents/debugger.rb +16 -0
- data/lib/agentf/agents/designer.rb +16 -0
- data/lib/agentf/agents/documenter.rb +16 -0
- data/lib/agentf/agents/explorer.rb +16 -0
- data/lib/agentf/agents/reviewer.rb +16 -0
- data/lib/agentf/agents/security.rb +16 -0
- data/lib/agentf/agents/specialist.rb +16 -0
- data/lib/agentf/agents/tester.rb +16 -0
- data/lib/agentf/cli/memory.rb +60 -3
- data/lib/agentf/cli/router.rb +1 -1
- data/lib/agentf/cli/update.rb +2 -2
- data/lib/agentf/commands/memory_reviewer.rb +18 -1
- data/lib/agentf/commands/metrics.rb +5 -6
- data/lib/agentf/installer.rb +73 -45
- data/lib/agentf/mcp/server.rb +79 -37
- data/lib/agentf/mcp/stub.rb +81 -0
- data/lib/agentf/memory.rb +345 -20
- data/lib/agentf/packs.rb +15 -15
- data/lib/agentf/service/providers.rb +42 -42
- data/lib/agentf/version.rb +1 -1
- data/lib/agentf/workflow_engine.rb +23 -23
- data/lib/agentf.rb +1 -0
- metadata +10 -6
data/lib/agentf/installer.rb
CHANGED
|
@@ -6,25 +6,25 @@ require "yaml"
|
|
|
6
6
|
module Agentf
|
|
7
7
|
class Installer
|
|
8
8
|
READ_ACTIONS = {
|
|
9
|
-
"get_recent_memories" => { cli: "agentf memory recent -n 10", tool: "
|
|
10
|
-
"get_pitfalls" => { cli: "agentf memory pitfalls -n 10", tool: "
|
|
11
|
-
"get_lessons" => { cli: "agentf memory lessons -n 10", tool: "
|
|
12
|
-
"get_successes" => { cli: "agentf memory successes -n 10", tool: "
|
|
13
|
-
"get_intents" => { cli: "agentf memory intents", tool: "
|
|
14
|
-
"get_all_tags" => { cli: "agentf memory tags", tool: "
|
|
15
|
-
"get_by_tag" => { cli: "agentf memory by-tag <tag> -n 10", tool: "
|
|
16
|
-
"get_by_type" => { cli: "agentf memory by-type <type> -n 10", tool: "
|
|
17
|
-
"get_by_agent" => { cli: "agentf memory by-agent <agent> -n 10", tool: "
|
|
18
|
-
"search" => { cli: "agentf memory search \"<query>\" -n 10", tool: "
|
|
19
|
-
"get_summary" => { cli: "agentf memory summary", tool: "
|
|
9
|
+
"get_recent_memories" => { cli: "agentf memory recent -n 10", tool: "agentf-memory-recent" },
|
|
10
|
+
"get_pitfalls" => { cli: "agentf memory pitfalls -n 10", tool: "agentf-memory-recent" },
|
|
11
|
+
"get_lessons" => { cli: "agentf memory lessons -n 10", tool: "agentf-memory-recent" },
|
|
12
|
+
"get_successes" => { cli: "agentf memory successes -n 10", tool: "agentf-memory-recent" },
|
|
13
|
+
"get_intents" => { cli: "agentf memory intents", tool: "agentf-memory-recent" },
|
|
14
|
+
"get_all_tags" => { cli: "agentf memory tags", tool: "agentf-memory-recent" },
|
|
15
|
+
"get_by_tag" => { cli: "agentf memory by-tag <tag> -n 10", tool: "agentf-memory-search" },
|
|
16
|
+
"get_by_type" => { cli: "agentf memory by-type <type> -n 10", tool: "agentf-memory-search" },
|
|
17
|
+
"get_by_agent" => { cli: "agentf memory by-agent <agent> -n 10", tool: "agentf-memory-search" },
|
|
18
|
+
"search" => { cli: "agentf memory search \"<query>\" -n 10", tool: "agentf-memory-search" },
|
|
19
|
+
"get_summary" => { cli: "agentf memory summary", tool: "agentf-memory-recent" }
|
|
20
20
|
}.freeze
|
|
21
21
|
|
|
22
22
|
WRITE_ACTIONS = {
|
|
23
|
-
"store_lesson" => { cli: "agentf memory add-lesson \"<title>\" \"<description>\" --agent=<AGENT> --tags=learning", tool: "
|
|
24
|
-
"store_success" => { cli: "agentf memory add-success \"<title>\" \"<description>\" --agent=<AGENT> --tags=success", tool: "
|
|
25
|
-
"store_pitfall" => { cli: "agentf memory add-pitfall \"<title>\" \"<description>\" --agent=<AGENT> --tags=pitfall", tool: "
|
|
26
|
-
"store_business_intent" => { cli: "agentf memory add-business-intent \"<title>\" \"<description>\" --tags=strategy", tool: "
|
|
27
|
-
"store_feature_intent" => { cli: "agentf memory add-feature-intent \"<title>\" \"<description>\" --acceptance=\"<criteria>\"", tool: "
|
|
23
|
+
"store_lesson" => { cli: "agentf memory add-lesson \"<title>\" \"<description>\" --agent=<AGENT> --tags=learning", tool: "agentf-memory-add-lesson" },
|
|
24
|
+
"store_success" => { cli: "agentf memory add-success \"<title>\" \"<description>\" --agent=<AGENT> --tags=success", tool: "agentf-memory-add-success" },
|
|
25
|
+
"store_pitfall" => { cli: "agentf memory add-pitfall \"<title>\" \"<description>\" --agent=<AGENT> --tags=pitfall", tool: "agentf-memory-add-pitfall" },
|
|
26
|
+
"store_business_intent" => { cli: "agentf memory add-business-intent \"<title>\" \"<description>\" --tags=strategy", tool: "agentf-memory-add-lesson" },
|
|
27
|
+
"store_feature_intent" => { cli: "agentf memory add-feature-intent \"<title>\" \"<description>\" --acceptance=\"<criteria>\"", tool: "agentf-memory-add-lesson" }
|
|
28
28
|
}.freeze
|
|
29
29
|
|
|
30
30
|
PROVIDER_LAYOUTS = {
|
|
@@ -116,7 +116,7 @@ module Agentf
|
|
|
116
116
|
def write_opencode_helpers(root:)
|
|
117
117
|
writes = []
|
|
118
118
|
writes << write_manifest(
|
|
119
|
-
File.join(root, ".opencode/agents/agentf-
|
|
119
|
+
File.join(root, ".opencode/agents/agentf-orchestrator.md"),
|
|
120
120
|
render_workflow_engine_manifest
|
|
121
121
|
)
|
|
122
122
|
writes << write_manifest(
|
|
@@ -160,7 +160,7 @@ module Agentf
|
|
|
160
160
|
|
|
161
161
|
def render_agent_manifest(klass, provider:)
|
|
162
162
|
meta = {
|
|
163
|
-
"name" => klass
|
|
163
|
+
"name" => agent_identifier(klass),
|
|
164
164
|
"description" => klass.description,
|
|
165
165
|
"commands" => klass.commands,
|
|
166
166
|
"memory" => klass.memory_concepts,
|
|
@@ -171,6 +171,18 @@ module Agentf
|
|
|
171
171
|
#{meta.to_yaml}---
|
|
172
172
|
#{klass.prompt}
|
|
173
173
|
|
|
174
|
+
## Core Mission
|
|
175
|
+
#{klass.description}
|
|
176
|
+
|
|
177
|
+
## When To Use
|
|
178
|
+
#{klass.when_to_use}
|
|
179
|
+
|
|
180
|
+
## Deliverables
|
|
181
|
+
#{Array(klass.deliverables).map { |item| "- #{item}" }.join("\n")}
|
|
182
|
+
|
|
183
|
+
## Working Style
|
|
184
|
+
#{klass.working_style}
|
|
185
|
+
|
|
174
186
|
## Memory Integration
|
|
175
187
|
- Reads: #{Array(klass.memory_concepts["reads"]).join(", ")}
|
|
176
188
|
- Writes: #{Array(klass.memory_concepts["writes"]).join(", ")}
|
|
@@ -211,10 +223,10 @@ module Agentf
|
|
|
211
223
|
end
|
|
212
224
|
|
|
213
225
|
if actions.none? { |a| a.start_with?("- Read:") }
|
|
214
|
-
actions << "- Read: Use `
|
|
226
|
+
actions << "- Read: Use `agentf-memory-recent` tool"
|
|
215
227
|
end
|
|
216
228
|
if actions.none? { |a| a.start_with?("- Write:") }
|
|
217
|
-
actions << "- Write: Use `
|
|
229
|
+
actions << "- Write: Use `agentf-memory-add-lesson` tool"
|
|
218
230
|
end
|
|
219
231
|
|
|
220
232
|
actions
|
|
@@ -234,10 +246,18 @@ module Agentf
|
|
|
234
246
|
end
|
|
235
247
|
end
|
|
236
248
|
|
|
249
|
+
def agent_identifier(klass)
|
|
250
|
+
"agentf-#{klass.typed_name.downcase}"
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
def command_identifier(name)
|
|
254
|
+
"agentf-#{name.to_s.downcase}"
|
|
255
|
+
end
|
|
256
|
+
|
|
237
257
|
def render_command_manifest(manifest, provider:)
|
|
238
258
|
commands = Array(manifest.fetch("commands"))
|
|
239
259
|
frontmatter = {
|
|
240
|
-
"name" => manifest.fetch("name"),
|
|
260
|
+
"name" => command_identifier(manifest.fetch("name")),
|
|
241
261
|
"description" => manifest.fetch("description"),
|
|
242
262
|
"commands" => commands
|
|
243
263
|
}
|
|
@@ -260,9 +280,9 @@ module Agentf
|
|
|
260
280
|
|
|
261
281
|
Copilot should call the local `agentf` MCP server tools for runtime actions.
|
|
262
282
|
|
|
263
|
-
- Code discovery tools: `
|
|
264
|
-
- Memory read tools: `
|
|
265
|
-
- Memory write tools (if enabled): `
|
|
283
|
+
- Code discovery tools: `agentf-code-glob`, `agentf-code-grep`, `agentf-code-tree`, `agentf-code-related-files`
|
|
284
|
+
- Memory read tools: `agentf-memory-recent`, `agentf-memory-search`
|
|
285
|
+
- Memory write tools (if enabled): `agentf-memory-add-lesson`, `agentf-memory-add-success`, `agentf-memory-add-pitfall`
|
|
266
286
|
|
|
267
287
|
MCP server is started via `agentf mcp-server` and runs locally over stdio.
|
|
268
288
|
MARKDOWN
|
|
@@ -273,12 +293,12 @@ module Agentf
|
|
|
273
293
|
|
|
274
294
|
command_name = manifest.fetch("name")
|
|
275
295
|
recommended_tools = case command_name
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
296
|
+
when "explorer"
|
|
297
|
+
"`agentf-code-glob`, `agentf-code-grep`, `agentf-code-tree`, `agentf-code-related-files`"
|
|
298
|
+
when "memory"
|
|
299
|
+
"`agentf-memory-recent`, `agentf-memory-search`, `agentf-memory-add-lesson`, `agentf-memory-add-success`, `agentf-memory-add-pitfall`"
|
|
300
|
+
else
|
|
301
|
+
"`agentf-code-glob`, `agentf-code-grep`, `agentf-memory-recent`, `agentf-memory-search`"
|
|
282
302
|
end
|
|
283
303
|
|
|
284
304
|
<<~MARKDOWN
|
|
@@ -294,9 +314,15 @@ module Agentf
|
|
|
294
314
|
<<~MARKDOWN
|
|
295
315
|
# AGENTF-WORKFLOW-ENGINE Agent
|
|
296
316
|
|
|
317
|
+
## Identity
|
|
318
|
+
|
|
319
|
+
- Role: ORCHESTRATOR
|
|
320
|
+
- Division: strategy
|
|
321
|
+
- Specialty: orchestration
|
|
322
|
+
|
|
297
323
|
## Role
|
|
298
324
|
|
|
299
|
-
The
|
|
325
|
+
The ORCHESTRATOR coordinates end-to-end workflows by selecting a provider adapter (`opencode` or `copilot`), creating an execution plan, and running agents in sequence.
|
|
300
326
|
|
|
301
327
|
Implemented in `lib/agentf/workflow_engine.rb`.
|
|
302
328
|
|
|
@@ -311,11 +337,11 @@ module Agentf
|
|
|
311
337
|
|
|
312
338
|
## Execution Flow
|
|
313
339
|
|
|
314
|
-
1.
|
|
315
|
-
2.
|
|
316
|
-
3.
|
|
340
|
+
1. ORCHESTRATOR → Requests provider plan
|
|
341
|
+
2. ORCHESTRATOR → Captures feature intent in memory
|
|
342
|
+
3. ORCHESTRATOR → Executes planned agents sequentially
|
|
317
343
|
4. Each agent → Reads relevant context + writes lessons
|
|
318
|
-
5.
|
|
344
|
+
5. ORCHESTRATOR → Summarizes status and returns results
|
|
319
345
|
|
|
320
346
|
## Notes
|
|
321
347
|
|
|
@@ -384,8 +410,8 @@ module Agentf
|
|
|
384
410
|
|
|
385
411
|
export const agentfPlugin: Plugin = async () => {
|
|
386
412
|
return {
|
|
387
|
-
|
|
388
|
-
|
|
413
|
+
tools: {
|
|
414
|
+
"agentf-code-glob": tool({
|
|
389
415
|
description: "Find files using project glob patterns via Agentf code CLI.",
|
|
390
416
|
args: {
|
|
391
417
|
pattern: tool.schema.string().describe("Glob pattern, example: lib/**/*.rb"),
|
|
@@ -400,7 +426,7 @@ module Agentf
|
|
|
400
426
|
return runAgentfCli(context.directory, "code", "glob", [args.pattern, ...commandArgs]);
|
|
401
427
|
},
|
|
402
428
|
}),
|
|
403
|
-
|
|
429
|
+
"agentf-code-grep": tool({
|
|
404
430
|
description: "Search file contents via Agentf code CLI.",
|
|
405
431
|
args: {
|
|
406
432
|
pattern: tool.schema.string().describe("Regex/text to search"),
|
|
@@ -415,7 +441,7 @@ module Agentf
|
|
|
415
441
|
return runAgentfCli(context.directory, "code", "grep", [args.pattern, ...commandArgs]);
|
|
416
442
|
},
|
|
417
443
|
}),
|
|
418
|
-
|
|
444
|
+
"agentf-code-tree": tool({
|
|
419
445
|
description: "Get directory tree data via Agentf code CLI.",
|
|
420
446
|
args: {
|
|
421
447
|
depth: tool.schema.number().int().min(1).max(10).optional().describe("Max traversal depth"),
|
|
@@ -425,7 +451,7 @@ module Agentf
|
|
|
425
451
|
return runAgentfCli(context.directory, "code", "tree", [`--depth=${depth}`]);
|
|
426
452
|
},
|
|
427
453
|
}),
|
|
428
|
-
|
|
454
|
+
"agentf-code-related-files": tool({
|
|
429
455
|
description: "Find import and related file hints for a target file.",
|
|
430
456
|
args: {
|
|
431
457
|
targetFile: tool.schema.string().describe("Workspace-relative file path"),
|
|
@@ -434,7 +460,7 @@ module Agentf
|
|
|
434
460
|
return runAgentfCli(context.directory, "code", "related", [args.targetFile]);
|
|
435
461
|
},
|
|
436
462
|
}),
|
|
437
|
-
|
|
463
|
+
"agentf-memory-recent": tool({
|
|
438
464
|
description: "Get recent Agentf memories from Redis.",
|
|
439
465
|
args: {
|
|
440
466
|
limit: tool.schema.number().int().min(1).max(100).optional().describe("How many memories to return"),
|
|
@@ -444,7 +470,7 @@ module Agentf
|
|
|
444
470
|
return runAgentfCli(context.directory, "memory", "recent", ["-n", String(limit)]);
|
|
445
471
|
},
|
|
446
472
|
}),
|
|
447
|
-
|
|
473
|
+
"agentf-memory-search": tool({
|
|
448
474
|
description: "Search Agentf memories by keyword.",
|
|
449
475
|
args: {
|
|
450
476
|
query: tool.schema.string().describe("Search query"),
|
|
@@ -455,7 +481,7 @@ module Agentf
|
|
|
455
481
|
return runAgentfCli(context.directory, "memory", "search", [args.query, "-n", String(limit)]);
|
|
456
482
|
},
|
|
457
483
|
}),
|
|
458
|
-
|
|
484
|
+
"agentf-memory-add-lesson": tool({
|
|
459
485
|
description: "Store a lesson memory in Redis.",
|
|
460
486
|
args: {
|
|
461
487
|
title: tool.schema.string(),
|
|
@@ -473,7 +499,7 @@ module Agentf
|
|
|
473
499
|
return runAgentfCli(context.directory, "memory", "add-lesson", commandArgs);
|
|
474
500
|
},
|
|
475
501
|
}),
|
|
476
|
-
|
|
502
|
+
"agentf-memory-add-success": tool({
|
|
477
503
|
description: "Store a success memory in Redis.",
|
|
478
504
|
args: {
|
|
479
505
|
title: tool.schema.string(),
|
|
@@ -491,7 +517,7 @@ module Agentf
|
|
|
491
517
|
return runAgentfCli(context.directory, "memory", "add-success", commandArgs);
|
|
492
518
|
},
|
|
493
519
|
}),
|
|
494
|
-
|
|
520
|
+
"agentf-memory-add-pitfall": tool({
|
|
495
521
|
description: "Store a pitfall memory in Redis.",
|
|
496
522
|
args: {
|
|
497
523
|
title: tool.schema.string(),
|
|
@@ -512,6 +538,8 @@ module Agentf
|
|
|
512
538
|
},
|
|
513
539
|
};
|
|
514
540
|
};
|
|
541
|
+
|
|
542
|
+
export default agentfPlugin;
|
|
515
543
|
TYPESCRIPT
|
|
516
544
|
end
|
|
517
545
|
|
data/lib/agentf/mcp/server.rb
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
begin
|
|
4
|
+
require "mcp"
|
|
5
|
+
rescue LoadError
|
|
6
|
+
require_relative "stub"
|
|
7
|
+
end
|
|
4
8
|
require "json"
|
|
5
9
|
|
|
6
10
|
module Agentf
|
|
@@ -17,22 +21,24 @@ module Agentf
|
|
|
17
21
|
# AGENTF_MCP_MAX_ARG_LENGTH - max length per string argument
|
|
18
22
|
class Server
|
|
19
23
|
KNOWN_TOOLS = %w[
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
agentf-code-glob
|
|
25
|
+
agentf-code-grep
|
|
26
|
+
agentf-code-tree
|
|
27
|
+
agentf-code-related-files
|
|
28
|
+
agentf-architecture-analyze-layers
|
|
29
|
+
agentf-memory-recent
|
|
30
|
+
agentf-memory-search
|
|
31
|
+
agentf-memory-neighbors
|
|
32
|
+
agentf-memory-subgraph
|
|
33
|
+
agentf-memory-add-lesson
|
|
34
|
+
agentf-memory-add-success
|
|
35
|
+
agentf-memory-add-pitfall
|
|
30
36
|
].freeze
|
|
31
37
|
|
|
32
38
|
WRITE_TOOLS = Set.new(%w[
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
39
|
+
agentf-memory-add-lesson
|
|
40
|
+
agentf-memory-add-success
|
|
41
|
+
agentf-memory-add-pitfall
|
|
36
42
|
]).freeze
|
|
37
43
|
|
|
38
44
|
attr_reader :server, :guardrails
|
|
@@ -132,25 +138,25 @@ module Agentf
|
|
|
132
138
|
explorer = @explorer
|
|
133
139
|
mcp_server = self
|
|
134
140
|
|
|
135
|
-
s.tool("
|
|
141
|
+
s.tool("agentf-code-glob") do
|
|
136
142
|
description "Find files using project glob patterns."
|
|
137
143
|
argument :pattern, String, required: true, description: "Glob pattern, e.g. lib/**/*.rb"
|
|
138
144
|
argument :types, Array, required: false, items: String, description: "File extensions to filter, e.g. [\"rb\",\"py\"]"
|
|
139
145
|
call do |args|
|
|
140
|
-
mcp_server.send(:guard!, "
|
|
146
|
+
mcp_server.send(:guard!, "agentf-code-glob", **args)
|
|
141
147
|
file_types = args[:types]&.empty? ? nil : args[:types]
|
|
142
148
|
results = explorer.glob(args[:pattern], file_types: file_types)
|
|
143
149
|
JSON.generate(pattern: args[:pattern], matches: results, count: results.length)
|
|
144
150
|
end
|
|
145
151
|
end
|
|
146
152
|
|
|
147
|
-
s.tool("
|
|
153
|
+
s.tool("agentf-code-grep") do
|
|
148
154
|
description "Search file contents with regex."
|
|
149
155
|
argument :pattern, String, required: true, description: "Regex or text to search"
|
|
150
156
|
argument :file_pattern, String, required: false, description: "Include pattern, e.g. *.rb"
|
|
151
157
|
argument :context_lines, Integer, required: false, description: "Context lines (0-20)"
|
|
152
158
|
call do |args|
|
|
153
|
-
mcp_server.send(:guard!, "
|
|
159
|
+
mcp_server.send(:guard!, "agentf-code-grep", **args)
|
|
154
160
|
ctx = args[:context_lines] || 2
|
|
155
161
|
matches = explorer.grep(args[:pattern], file_pattern: args[:file_pattern], context_lines: ctx)
|
|
156
162
|
serialized = matches.map { |m| m.respond_to?(:to_h) ? m.to_h : m }
|
|
@@ -158,22 +164,22 @@ module Agentf
|
|
|
158
164
|
end
|
|
159
165
|
end
|
|
160
166
|
|
|
161
|
-
s.tool("
|
|
167
|
+
s.tool("agentf-code-tree") do
|
|
162
168
|
description "Get directory tree structure."
|
|
163
169
|
argument :depth, Integer, required: false, description: "Max traversal depth (1-10)"
|
|
164
170
|
call do |args|
|
|
165
|
-
mcp_server.send(:guard!, "
|
|
171
|
+
mcp_server.send(:guard!, "agentf-code-tree", **args)
|
|
166
172
|
max_depth = args[:depth] || 3
|
|
167
173
|
tree = explorer.get_file_tree(max_depth: max_depth)
|
|
168
174
|
JSON.generate(max_depth: max_depth, tree: tree)
|
|
169
175
|
end
|
|
170
176
|
end
|
|
171
177
|
|
|
172
|
-
s.tool("
|
|
178
|
+
s.tool("agentf-code-related-files") do
|
|
173
179
|
description "Find imports and related files for a target file."
|
|
174
180
|
argument :target_file, String, required: true, description: "Workspace-relative file path"
|
|
175
181
|
call do |args|
|
|
176
|
-
mcp_server.send(:guard!, "
|
|
182
|
+
mcp_server.send(:guard!, "agentf-code-related-files", **args)
|
|
177
183
|
related = explorer.find_related_files(args[:target_file])
|
|
178
184
|
JSON.generate(target_file: args[:target_file], related: related)
|
|
179
185
|
end
|
|
@@ -187,28 +193,64 @@ module Agentf
|
|
|
187
193
|
memory = @memory
|
|
188
194
|
mcp_server = self
|
|
189
195
|
|
|
190
|
-
s.tool("
|
|
196
|
+
s.tool("agentf-memory-recent") do
|
|
191
197
|
description "Get recent memories from Redis."
|
|
192
198
|
argument :limit, Integer, required: false, description: "How many memories to return (1-100)"
|
|
193
199
|
call do |args|
|
|
194
|
-
mcp_server.send(:guard!, "
|
|
200
|
+
mcp_server.send(:guard!, "agentf-memory-recent", **args)
|
|
195
201
|
result = reviewer.get_recent_memories(limit: args[:limit] || 10)
|
|
196
202
|
JSON.generate(result)
|
|
197
203
|
end
|
|
198
204
|
end
|
|
199
205
|
|
|
200
|
-
s.tool("
|
|
206
|
+
s.tool("agentf-memory-search") do
|
|
201
207
|
description "Search memories by keyword."
|
|
202
208
|
argument :query, String, required: true, description: "Search query"
|
|
203
209
|
argument :limit, Integer, required: false, description: "How many results to return (1-100)"
|
|
204
210
|
call do |args|
|
|
205
|
-
mcp_server.send(:guard!, "
|
|
211
|
+
mcp_server.send(:guard!, "agentf-memory-search", **args)
|
|
206
212
|
result = reviewer.search(args[:query], limit: args[:limit] || 10)
|
|
207
213
|
JSON.generate(result)
|
|
208
214
|
end
|
|
209
215
|
end
|
|
210
216
|
|
|
211
|
-
s.tool("
|
|
217
|
+
s.tool("agentf-memory-neighbors") do
|
|
218
|
+
description "Get neighboring memory nodes by edge traversal."
|
|
219
|
+
argument :node_id, String, required: true, description: "Starting node id"
|
|
220
|
+
argument :relation, String, required: false, description: "Optional relation filter"
|
|
221
|
+
argument :depth, Integer, required: false, description: "Traversal depth"
|
|
222
|
+
argument :limit, Integer, required: false, description: "Maximum edges"
|
|
223
|
+
call do |args|
|
|
224
|
+
mcp_server.send(:guard!, "agentf-memory-neighbors", **args)
|
|
225
|
+
result = reviewer.neighbors(
|
|
226
|
+
args[:node_id],
|
|
227
|
+
relation: args[:relation],
|
|
228
|
+
depth: args[:depth] || 1,
|
|
229
|
+
limit: args[:limit] || 50
|
|
230
|
+
)
|
|
231
|
+
JSON.generate(result)
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
s.tool("agentf-memory-subgraph") do
|
|
236
|
+
description "Build a subgraph from seed ids."
|
|
237
|
+
argument :seed_ids, Array, required: true, items: String, description: "Seed node ids"
|
|
238
|
+
argument :relation_filters, Array, required: false, items: String, description: "Optional relations"
|
|
239
|
+
argument :depth, Integer, required: false, description: "Traversal depth"
|
|
240
|
+
argument :limit, Integer, required: false, description: "Maximum edges"
|
|
241
|
+
call do |args|
|
|
242
|
+
mcp_server.send(:guard!, "agentf-memory-subgraph", **args)
|
|
243
|
+
result = reviewer.subgraph(
|
|
244
|
+
seed_ids: args[:seed_ids] || [],
|
|
245
|
+
relation_filters: args[:relation_filters],
|
|
246
|
+
depth: args[:depth] || 2,
|
|
247
|
+
limit: args[:limit] || 200
|
|
248
|
+
)
|
|
249
|
+
JSON.generate(result)
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
s.tool("agentf-memory-add-lesson") do
|
|
212
254
|
description "Store a lesson memory in Redis."
|
|
213
255
|
argument :title, String, required: true, description: "Lesson title"
|
|
214
256
|
argument :description, String, required: true, description: "Lesson description"
|
|
@@ -216,12 +258,12 @@ module Agentf
|
|
|
216
258
|
argument :tags, Array, required: false, items: String, description: "Tags"
|
|
217
259
|
argument :context, String, required: false, description: "Context"
|
|
218
260
|
call do |args|
|
|
219
|
-
mcp_server.send(:guard!, "
|
|
261
|
+
mcp_server.send(:guard!, "agentf-memory-add-lesson", **args)
|
|
220
262
|
id = memory.store_episode(
|
|
221
263
|
type: "lesson",
|
|
222
264
|
title: args[:title],
|
|
223
265
|
description: args[:description],
|
|
224
|
-
agent: args[:agent] ||
|
|
266
|
+
agent: args[:agent] || Agentf::AgentRoles::ENGINEER,
|
|
225
267
|
tags: args[:tags] || [],
|
|
226
268
|
context: args[:context].to_s,
|
|
227
269
|
code_snippet: ""
|
|
@@ -230,7 +272,7 @@ module Agentf
|
|
|
230
272
|
end
|
|
231
273
|
end
|
|
232
274
|
|
|
233
|
-
s.tool("
|
|
275
|
+
s.tool("agentf-memory-add-success") do
|
|
234
276
|
description "Store a success memory in Redis."
|
|
235
277
|
argument :title, String, required: true, description: "Success title"
|
|
236
278
|
argument :description, String, required: true, description: "Success description"
|
|
@@ -238,12 +280,12 @@ module Agentf
|
|
|
238
280
|
argument :tags, Array, required: false, items: String, description: "Tags"
|
|
239
281
|
argument :context, String, required: false, description: "Context"
|
|
240
282
|
call do |args|
|
|
241
|
-
mcp_server.send(:guard!, "
|
|
283
|
+
mcp_server.send(:guard!, "agentf-memory-add-success", **args)
|
|
242
284
|
id = memory.store_episode(
|
|
243
285
|
type: "success",
|
|
244
286
|
title: args[:title],
|
|
245
287
|
description: args[:description],
|
|
246
|
-
agent: args[:agent] ||
|
|
288
|
+
agent: args[:agent] || Agentf::AgentRoles::ENGINEER,
|
|
247
289
|
tags: args[:tags] || [],
|
|
248
290
|
context: args[:context].to_s,
|
|
249
291
|
code_snippet: ""
|
|
@@ -252,7 +294,7 @@ module Agentf
|
|
|
252
294
|
end
|
|
253
295
|
end
|
|
254
296
|
|
|
255
|
-
s.tool("
|
|
297
|
+
s.tool("agentf-memory-add-pitfall") do
|
|
256
298
|
description "Store a pitfall memory in Redis."
|
|
257
299
|
argument :title, String, required: true, description: "Pitfall title"
|
|
258
300
|
argument :description, String, required: true, description: "Pitfall description"
|
|
@@ -260,12 +302,12 @@ module Agentf
|
|
|
260
302
|
argument :tags, Array, required: false, items: String, description: "Tags"
|
|
261
303
|
argument :context, String, required: false, description: "Context"
|
|
262
304
|
call do |args|
|
|
263
|
-
mcp_server.send(:guard!, "
|
|
305
|
+
mcp_server.send(:guard!, "agentf-memory-add-pitfall", **args)
|
|
264
306
|
id = memory.store_episode(
|
|
265
307
|
type: "pitfall",
|
|
266
308
|
title: args[:title],
|
|
267
309
|
description: args[:description],
|
|
268
|
-
agent: args[:agent] ||
|
|
310
|
+
agent: args[:agent] || Agentf::AgentRoles::ENGINEER,
|
|
269
311
|
tags: args[:tags] || [],
|
|
270
312
|
context: args[:context].to_s,
|
|
271
313
|
code_snippet: ""
|
|
@@ -279,13 +321,13 @@ module Agentf
|
|
|
279
321
|
architecture = @architecture
|
|
280
322
|
mcp_server = self
|
|
281
323
|
|
|
282
|
-
s.tool("
|
|
324
|
+
s.tool("agentf-architecture-analyze-layers") do
|
|
283
325
|
description "Analyze architecture layers, review violations, or create gradual adoption plans."
|
|
284
326
|
argument :mode, String, required: false, description: "analyze|review|gradual"
|
|
285
327
|
argument :limit, Integer, required: false, description: "Maximum violations to return for review mode"
|
|
286
328
|
argument :goal, String, required: false, description: "Adoption goal for gradual mode"
|
|
287
329
|
call do |args|
|
|
288
|
-
mcp_server.send(:guard!, "
|
|
330
|
+
mcp_server.send(:guard!, "agentf-architecture-analyze-layers", **args)
|
|
289
331
|
case (args[:mode] || "analyze").to_s
|
|
290
332
|
when "review"
|
|
291
333
|
JSON.generate(architecture.review_layer_violations(limit: args[:limit] || 20))
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MCP
|
|
4
|
+
# Minimal stub of the MCP::Server DSL so specs can run without the
|
|
5
|
+
# official MCP gem. Provides just enough behavior for tool
|
|
6
|
+
# registration, listing, and invocation.
|
|
7
|
+
class Server
|
|
8
|
+
Tool = Struct.new(:name, :description, :arguments, :handler, keyword_init: true)
|
|
9
|
+
|
|
10
|
+
def initialize(name:, version:)
|
|
11
|
+
@name = name
|
|
12
|
+
@version = version
|
|
13
|
+
@tools = {}
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def tool(name, &block)
|
|
17
|
+
builder = ToolBuilder.new(name)
|
|
18
|
+
builder.instance_eval(&block)
|
|
19
|
+
@tools[name] = Tool.new(
|
|
20
|
+
name: name,
|
|
21
|
+
description: builder.description,
|
|
22
|
+
arguments: builder.arguments,
|
|
23
|
+
handler: builder.handler
|
|
24
|
+
)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def list_tools
|
|
28
|
+
@tools.values.map do |tool|
|
|
29
|
+
{
|
|
30
|
+
name: tool.name,
|
|
31
|
+
description: tool.description.to_s,
|
|
32
|
+
inputSchema: {
|
|
33
|
+
type: "object",
|
|
34
|
+
properties: tool.arguments.transform_values { |arg| arg[:schema] },
|
|
35
|
+
required: tool.arguments.select { |_k, arg| arg[:required] }.keys.map(&:to_s)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def call_tool(name, **args)
|
|
42
|
+
tool = @tools[name]
|
|
43
|
+
raise "Unknown tool: #{name}" unless tool
|
|
44
|
+
|
|
45
|
+
tool.handler.call(args)
|
|
46
|
+
rescue StandardError => e
|
|
47
|
+
e.message
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def run
|
|
51
|
+
raise "Stub MCP::Server cannot run"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
class ToolBuilder
|
|
55
|
+
attr_reader :description, :arguments, :handler
|
|
56
|
+
|
|
57
|
+
def initialize(name)
|
|
58
|
+
@name = name
|
|
59
|
+
@arguments = {}
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def description(value = nil)
|
|
63
|
+
@description = value unless value.nil?
|
|
64
|
+
@description
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def argument(name, _type, required: false, description:, **_opts)
|
|
68
|
+
@arguments[name] = {
|
|
69
|
+
required: required,
|
|
70
|
+
schema: {
|
|
71
|
+
description: description
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def call(&block)
|
|
77
|
+
@handler = block
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|