agentf 0.5.0 → 0.7.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 +8 -23
- data/lib/agentf/agents/debugger.rb +1 -2
- data/lib/agentf/agents/designer.rb +22 -7
- 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 +28 -12
- data/lib/agentf/agents/tester.rb +22 -7
- data/lib/agentf/cli/eval.rb +1 -1
- data/lib/agentf/cli/memory.rb +95 -92
- data/lib/agentf/cli/router.rb +1 -1
- data/lib/agentf/commands/memory_reviewer.rb +21 -55
- 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 +162 -82
- data/lib/agentf/mcp/server.rb +123 -177
- data/lib/agentf/memory/confirmation_handler.rb +24 -0
- data/lib/agentf/memory.rb +322 -169
- data/lib/agentf/version.rb +1 -1
- data/lib/agentf/workflow_engine.rb +15 -18
- data/lib/agentf.rb +2 -0
- metadata +4 -2
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
|
|
@@ -152,7 +150,7 @@ module Agentf
|
|
|
152
150
|
|
|
153
151
|
classes.map do |klass|
|
|
154
152
|
target = File.join(root, layout.fetch("agents_dir"), layout.fetch("agent_filename").call(klass))
|
|
155
|
-
write_manifest(target, render_agent_manifest(klass
|
|
153
|
+
write_manifest(target, render_agent_manifest(klass))
|
|
156
154
|
end
|
|
157
155
|
end
|
|
158
156
|
|
|
@@ -162,7 +160,7 @@ module Agentf
|
|
|
162
160
|
|
|
163
161
|
manifests.map do |manifest|
|
|
164
162
|
target = File.join(root, layout.fetch("commands_dir"), layout.fetch("command_filename").call(manifest))
|
|
165
|
-
write_manifest(target, render_command_manifest(manifest
|
|
163
|
+
write_manifest(target, render_command_manifest(manifest))
|
|
166
164
|
end
|
|
167
165
|
end
|
|
168
166
|
|
|
@@ -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
|
|
@@ -233,7 +237,7 @@ module Agentf
|
|
|
233
237
|
end
|
|
234
238
|
end
|
|
235
239
|
|
|
236
|
-
def render_agent_manifest(klass
|
|
240
|
+
def render_agent_manifest(klass)
|
|
237
241
|
# Emit a minimal, stable manifest that acts as a pointer to the runtime
|
|
238
242
|
# tool implemented by the plugin/CLI. Keep filename and `name` stable so
|
|
239
243
|
# upgrades remain compatible with existing installs.
|
|
@@ -253,6 +257,9 @@ module Agentf
|
|
|
253
257
|
|
|
254
258
|
description = klass.respond_to?(:description) ? klass.description.to_s.strip : ""
|
|
255
259
|
|
|
260
|
+
tdd_section = klass.respond_to?(:writes_code?) && klass.writes_code? ? tdd_requirement_section : ""
|
|
261
|
+
fallback = cli_fallback_section(klass)
|
|
262
|
+
|
|
256
263
|
<<~MARKDOWN
|
|
257
264
|
---
|
|
258
265
|
name: #{tool_name}
|
|
@@ -269,7 +276,50 @@ module Agentf
|
|
|
269
276
|
do not retry the write.
|
|
270
277
|
|
|
271
278
|
Policy Summary: #{policy_summary}
|
|
279
|
+
#{tdd_section}#{fallback}
|
|
280
|
+
MARKDOWN
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
def tdd_requirement_section
|
|
284
|
+
<<~MARKDOWN
|
|
285
|
+
|
|
286
|
+
## TDD Requirement
|
|
287
|
+
|
|
288
|
+
This agent writes code. Every implementation MUST follow red/green discipline:
|
|
289
|
+
|
|
290
|
+
1. **Write the spec first** — create a failing test before any implementation code
|
|
291
|
+
2. **Run tests to confirm red** — verify the spec fails (`bundle exec rspec <spec_file>`)
|
|
292
|
+
3. **Implement the code** — write only enough to make the spec pass
|
|
293
|
+
4. **Run tests to confirm green** — verify all specs pass before reporting done
|
|
294
|
+
5. **Never skip** — do not create a class, method, or module without a corresponding spec file
|
|
272
295
|
|
|
296
|
+
Showing test output (red then green) is mandatory evidence of completion.
|
|
297
|
+
MARKDOWN
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
def cli_fallback_section(klass)
|
|
301
|
+
agent_name = klass.typed_name.downcase
|
|
302
|
+
read_cmds = READ_ACTIONS.values_at("get_recent_memories", "search").map { |a| "- `#{a[:cli]}`" }.join("\n")
|
|
303
|
+
|
|
304
|
+
write_actions = Array(klass.respond_to?(:memory_concepts) ? klass.memory_concepts["writes"] : [])
|
|
305
|
+
.map { |item| item.to_s.split("#").last }
|
|
306
|
+
.filter_map { |key| WRITE_ACTIONS[key] }
|
|
307
|
+
.map { |a| "- `#{a[:cli].gsub("<AGENT>", agent_name.upcase)}`" }
|
|
308
|
+
.join("\n")
|
|
309
|
+
|
|
310
|
+
write_section = write_actions.empty? ? "" : "\n**Memory writes**:\n#{write_actions}\n"
|
|
311
|
+
|
|
312
|
+
<<~MARKDOWN
|
|
313
|
+
|
|
314
|
+
## CLI Fallback
|
|
315
|
+
|
|
316
|
+
If the `agentf` MCP server is unavailable, run equivalent commands directly in the terminal:
|
|
317
|
+
|
|
318
|
+
**Run this agent**: `agentf agent #{agent_name} "<input>"`
|
|
319
|
+
|
|
320
|
+
**Memory reads**:
|
|
321
|
+
#{read_cmds}
|
|
322
|
+
#{write_section}
|
|
273
323
|
MARKDOWN
|
|
274
324
|
end
|
|
275
325
|
|
|
@@ -325,9 +375,10 @@ module Agentf
|
|
|
325
375
|
"agentf-#{name.to_s.downcase}"
|
|
326
376
|
end
|
|
327
377
|
|
|
328
|
-
def render_command_manifest(manifest
|
|
378
|
+
def render_command_manifest(manifest)
|
|
329
379
|
cmd_name = command_identifier(manifest.fetch("name"))
|
|
330
380
|
desc = manifest.fetch("description", "").to_s.strip
|
|
381
|
+
fallback = command_cli_fallback_section(manifest)
|
|
331
382
|
|
|
332
383
|
<<~MARKDOWN
|
|
333
384
|
---
|
|
@@ -338,7 +389,45 @@ module Agentf
|
|
|
338
389
|
|
|
339
390
|
IMPORTANT: Do not embed runtime logic here. Invoke the `#{cmd_name}` tool to perform
|
|
340
391
|
any codebase or memory operations.
|
|
392
|
+
#{fallback}
|
|
393
|
+
MARKDOWN
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
def command_cli_fallback_section(manifest)
|
|
397
|
+
name = manifest.fetch("name")
|
|
398
|
+
cli_lines = case name
|
|
399
|
+
when "explorer"
|
|
400
|
+
[
|
|
401
|
+
"`agentf code glob \"<pattern>\"`",
|
|
402
|
+
"`agentf code grep \"<pattern>\"`",
|
|
403
|
+
"`agentf code tree --depth=3`",
|
|
404
|
+
"`agentf code related <file>`"
|
|
405
|
+
]
|
|
406
|
+
when "memory"
|
|
407
|
+
[
|
|
408
|
+
"`#{READ_ACTIONS.fetch('get_recent_memories')[:cli]}`",
|
|
409
|
+
"`#{READ_ACTIONS.fetch('search')[:cli]}`",
|
|
410
|
+
"`#{READ_ACTIONS.fetch('get_episodes')[:cli]}`",
|
|
411
|
+
"`#{WRITE_ACTIONS.fetch('store_lesson')[:cli]}`",
|
|
412
|
+
"`#{WRITE_ACTIONS.fetch('store_episode')[:cli]}`"
|
|
413
|
+
]
|
|
414
|
+
else
|
|
415
|
+
[
|
|
416
|
+
"`agentf code glob \"<pattern>\"`",
|
|
417
|
+
"`#{READ_ACTIONS.fetch('get_recent_memories')[:cli]}`",
|
|
418
|
+
"`#{READ_ACTIONS.fetch('search')[:cli]}`"
|
|
419
|
+
]
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
tool_lines = cli_lines.map { |cmd| "- #{cmd}" }.join("\n")
|
|
423
|
+
|
|
424
|
+
<<~MARKDOWN
|
|
425
|
+
|
|
426
|
+
## CLI Fallback
|
|
427
|
+
|
|
428
|
+
If the `agentf` MCP server is unavailable, run equivalent commands directly in the terminal:
|
|
341
429
|
|
|
430
|
+
#{tool_lines}
|
|
342
431
|
MARKDOWN
|
|
343
432
|
end
|
|
344
433
|
|
|
@@ -351,8 +440,8 @@ module Agentf
|
|
|
351
440
|
Copilot should call the local `agentf` MCP server tools for runtime actions.
|
|
352
441
|
|
|
353
442
|
- 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-
|
|
443
|
+
- Memory read tools: `agentf-memory-recent`, `agentf-memory-search`, `agentf-memory-episodes`
|
|
444
|
+
- Memory write tools (if enabled): `agentf-memory-add-lesson`, `agentf-memory-add-playbook`
|
|
356
445
|
|
|
357
446
|
MCP server is started via `agentf mcp-server` and runs locally over stdio.
|
|
358
447
|
MARKDOWN
|
|
@@ -365,8 +454,8 @@ module Agentf
|
|
|
365
454
|
recommended_tools = case command_name
|
|
366
455
|
when "explorer"
|
|
367
456
|
"`agentf-code-glob`, `agentf-code-grep`, `agentf-code-tree`, `agentf-code-related-files`"
|
|
368
|
-
|
|
369
|
-
|
|
457
|
+
when "memory"
|
|
458
|
+
"`agentf-memory-recent`, `agentf-memory-search`, `agentf-memory-episodes`, `agentf-memory-add-lesson`, `agentf-memory-add-playbook`"
|
|
370
459
|
else
|
|
371
460
|
"`agentf-code-glob`, `agentf-code-grep`, `agentf-memory-recent`, `agentf-memory-search`"
|
|
372
461
|
end
|
|
@@ -401,7 +490,7 @@ module Agentf
|
|
|
401
490
|
1. Build plan from provider adapter (`Agentf::Service::Providers::OpenCode` or `Agentf::Service::Providers::Copilot`)
|
|
402
491
|
2. Enrich each agent step with brain context from Redis memory
|
|
403
492
|
3. Persist feature intent at workflow start
|
|
404
|
-
4. Persist lessons
|
|
493
|
+
4. Persist lessons and negative episodes from each agent execution
|
|
405
494
|
5. Return full workflow state for manual review and future autonomous control
|
|
406
495
|
6. Enforce workflow contract stages (`spec`, `plan`, `execute`, `review`, `finalize`) when enabled
|
|
407
496
|
|
|
@@ -691,17 +780,6 @@ module Agentf
|
|
|
691
780
|
return runAgentfCli(context.directory, "memory", "search", [_args.query, "-n", String(limit)]);
|
|
692
781
|
},
|
|
693
782
|
}),
|
|
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
783
|
"agentf-memory-by-agent": tool({
|
|
706
784
|
description: "Get Agentf memories by agent.",
|
|
707
785
|
args: {
|
|
@@ -716,7 +794,7 @@ module Agentf
|
|
|
716
794
|
"agentf-memory-by-type": tool({
|
|
717
795
|
description: "Get Agentf memories by type.",
|
|
718
796
|
args: {
|
|
719
|
-
type: tool.schema.string().describe("Memory type (
|
|
797
|
+
type: tool.schema.string().describe("Memory type (episode|lesson|playbook|business_intent|feature_intent|incident)"),
|
|
720
798
|
limit: tool.schema.number().int().min(1).max(100).optional().describe("How many results to return"),
|
|
721
799
|
},
|
|
722
800
|
async execute(_args: any, context: any) {
|
|
@@ -724,19 +802,17 @@ module Agentf
|
|
|
724
802
|
return runAgentfCli(context.directory, "memory", "by-type", [_args.type, "-n", String(limit)]);
|
|
725
803
|
},
|
|
726
804
|
}),
|
|
727
|
-
"agentf-memory-
|
|
728
|
-
description: "List
|
|
729
|
-
args: {
|
|
730
|
-
|
|
731
|
-
|
|
805
|
+
"agentf-memory-episodes": tool({
|
|
806
|
+
description: "List episode memories.",
|
|
807
|
+
args: {
|
|
808
|
+
outcome: tool.schema.string().optional().describe("Optional outcome filter (positive|negative|neutral)"),
|
|
809
|
+
limit: tool.schema.number().int().min(1).max(100).optional(),
|
|
732
810
|
},
|
|
733
|
-
}),
|
|
734
|
-
"agentf-memory-pitfalls": tool({
|
|
735
|
-
description: "List pitfall memories.",
|
|
736
|
-
args: { limit: tool.schema.number().int().min(1).max(100).optional() },
|
|
737
811
|
async execute(_args: any, context: any) {
|
|
738
812
|
const limit = _args.limit ?? 10;
|
|
739
|
-
|
|
813
|
+
const commandArgs = ["-n", String(limit)];
|
|
814
|
+
if (_args.outcome) commandArgs.push(`--outcome=${_args.outcome}`);
|
|
815
|
+
return runAgentfCli(context.directory, "memory", "episodes", commandArgs);
|
|
740
816
|
},
|
|
741
817
|
}),
|
|
742
818
|
"agentf-memory-lessons": tool({
|
|
@@ -747,14 +823,6 @@ module Agentf
|
|
|
747
823
|
return runAgentfCli(context.directory, "memory", "lessons", ["-n", String(limit)]);
|
|
748
824
|
},
|
|
749
825
|
}),
|
|
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
826
|
"agentf-memory-intents": tool({
|
|
759
827
|
description: "List intents (business, feature or both).",
|
|
760
828
|
args: { kind: tool.schema.string().optional(), limit: tool.schema.number().int().min(1).max(100).optional() },
|
|
@@ -786,13 +854,11 @@ module Agentf
|
|
|
786
854
|
args: {
|
|
787
855
|
title: tool.schema.string(),
|
|
788
856
|
description: tool.schema.string(),
|
|
789
|
-
tags: tool.schema.array(tool.schema.string()).optional(),
|
|
790
857
|
constraints: tool.schema.array(tool.schema.string()).optional(),
|
|
791
858
|
priority: tool.schema.number().int().optional(),
|
|
792
859
|
},
|
|
793
860
|
async execute(_args: any, context: any) {
|
|
794
861
|
const commandArgs = [_args.title, _args.description];
|
|
795
|
-
if (_args.tags?.length) commandArgs.push(`--tags=${_args.tags.join(",")}`);
|
|
796
862
|
if (_args.constraints?.length) commandArgs.push(`--constraints=${_args.constraints.join(";")}`);
|
|
797
863
|
if (Number.isInteger(_args.priority)) commandArgs.push(`--priority=${String(_args.priority)}`);
|
|
798
864
|
return runAgentfCli(context.directory, "memory", "add-business-intent", commandArgs);
|
|
@@ -803,14 +869,12 @@ module Agentf
|
|
|
803
869
|
args: {
|
|
804
870
|
title: tool.schema.string(),
|
|
805
871
|
description: tool.schema.string(),
|
|
806
|
-
tags: tool.schema.array(tool.schema.string()).optional(),
|
|
807
872
|
acceptance: tool.schema.array(tool.schema.string()).optional(),
|
|
808
873
|
non_goals: tool.schema.array(tool.schema.string()).optional(),
|
|
809
874
|
related_task_id: tool.schema.string().optional(),
|
|
810
875
|
},
|
|
811
876
|
async execute(_args: any, context: any) {
|
|
812
877
|
const commandArgs = [_args.title, _args.description];
|
|
813
|
-
if (_args.tags?.length) commandArgs.push(`--tags=${_args.tags.join(",")}`);
|
|
814
878
|
if (_args.acceptance?.length) commandArgs.push(`--acceptance=${_args.acceptance.join(";")}`);
|
|
815
879
|
if (_args.non_goals?.length) commandArgs.push(`--non-goals=${_args.non_goals.join(";")}`);
|
|
816
880
|
if (_args.related_task_id) commandArgs.push(`--task=${_args.related_task_id}`);
|
|
@@ -856,52 +920,32 @@ module Agentf
|
|
|
856
920
|
title: tool.schema.string(),
|
|
857
921
|
description: tool.schema.string(),
|
|
858
922
|
agent: tool.schema.string().optional(),
|
|
859
|
-
tags: tool.schema.array(tool.schema.string()).optional(),
|
|
860
923
|
context: tool.schema.string().optional(),
|
|
861
924
|
},
|
|
862
925
|
async execute(_args: any, context: any) {
|
|
863
926
|
const commandArgs = [_args.title, _args.description];
|
|
864
927
|
if (_args.agent) commandArgs.push(`--agent=${_args.agent}`);
|
|
865
|
-
if (_args.tags?.length) commandArgs.push(`--tags=${_args.tags.join(",")}`);
|
|
866
928
|
if (_args.context) commandArgs.push(`--context=${_args.context}`);
|
|
867
929
|
|
|
868
930
|
return runAgentfCli(context.directory, "memory", "add-lesson", commandArgs);
|
|
869
931
|
},
|
|
870
932
|
}),
|
|
871
|
-
"agentf-memory-add-
|
|
872
|
-
description: "Store a
|
|
933
|
+
"agentf-memory-add-playbook": tool({
|
|
934
|
+
description: "Store a playbook memory in Redis.",
|
|
873
935
|
args: {
|
|
874
936
|
title: tool.schema.string(),
|
|
875
937
|
description: tool.schema.string(),
|
|
876
938
|
agent: tool.schema.string().optional(),
|
|
877
|
-
|
|
878
|
-
|
|
939
|
+
steps: tool.schema.array(tool.schema.string()).optional(),
|
|
940
|
+
feature_area: tool.schema.string().optional(),
|
|
879
941
|
},
|
|
880
942
|
async execute(_args: any, context: any) {
|
|
881
943
|
const commandArgs = [_args.title, _args.description];
|
|
882
944
|
if (_args.agent) commandArgs.push(`--agent=${_args.agent}`);
|
|
883
|
-
if (_args.
|
|
884
|
-
if (_args.
|
|
945
|
+
if (_args.steps?.length) commandArgs.push(`--steps=${_args.steps.join(";")}`);
|
|
946
|
+
if (_args.feature_area) commandArgs.push(`--feature-area=${_args.feature_area}`);
|
|
885
947
|
|
|
886
|
-
return runAgentfCli(context.directory, "memory", "add-
|
|
887
|
-
},
|
|
888
|
-
}),
|
|
889
|
-
"agentf-memory-add-pitfall": tool({
|
|
890
|
-
description: "Store a pitfall memory in Redis.",
|
|
891
|
-
args: {
|
|
892
|
-
title: tool.schema.string(),
|
|
893
|
-
description: tool.schema.string(),
|
|
894
|
-
agent: tool.schema.string().optional(),
|
|
895
|
-
tags: tool.schema.array(tool.schema.string()).optional(),
|
|
896
|
-
context: tool.schema.string().optional(),
|
|
897
|
-
},
|
|
898
|
-
async execute(_args: any, context: any) {
|
|
899
|
-
const commandArgs = [_args.title, _args.description];
|
|
900
|
-
if (_args.agent) commandArgs.push(`--agent=${_args.agent}`);
|
|
901
|
-
if (_args.tags?.length) commandArgs.push(`--tags=${_args.tags.join(",")}`);
|
|
902
|
-
if (_args.context) commandArgs.push(`--context=${_args.context}`);
|
|
903
|
-
|
|
904
|
-
return runAgentfCli(context.directory, "memory", "add-pitfall", commandArgs);
|
|
948
|
+
return runAgentfCli(context.directory, "memory", "add-playbook", commandArgs);
|
|
905
949
|
},
|
|
906
950
|
}),
|
|
907
951
|
};
|
|
@@ -961,6 +1005,10 @@ module Agentf
|
|
|
961
1005
|
JSON.pretty_generate(opencode_json_config(root))
|
|
962
1006
|
end
|
|
963
1007
|
|
|
1008
|
+
def render_copilot_mcp_json(root)
|
|
1009
|
+
JSON.pretty_generate(copilot_mcp_config(root))
|
|
1010
|
+
end
|
|
1011
|
+
|
|
964
1012
|
def opencode_json_config(root)
|
|
965
1013
|
base = {
|
|
966
1014
|
"$schema" => "https://opencode.ai/config.json"
|
|
@@ -1019,6 +1067,37 @@ module Agentf
|
|
|
1019
1067
|
write_manifest(path, JSON.pretty_generate(merged))
|
|
1020
1068
|
end
|
|
1021
1069
|
|
|
1070
|
+
def copilot_mcp_config(root)
|
|
1071
|
+
{
|
|
1072
|
+
"servers" => {
|
|
1073
|
+
"agentf" => {
|
|
1074
|
+
"type" => "stdio",
|
|
1075
|
+
"command" => "agentf",
|
|
1076
|
+
"args" => ["mcp-server"]
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
end
|
|
1081
|
+
|
|
1082
|
+
def write_copilot_mcp_json(root)
|
|
1083
|
+
path = File.join(root, ".vscode", "mcp.json")
|
|
1084
|
+
new_content = JSON.parse(render_copilot_mcp_json(root))
|
|
1085
|
+
|
|
1086
|
+
return write_manifest(path, JSON.pretty_generate(new_content)) unless File.exist?(path)
|
|
1087
|
+
|
|
1088
|
+
begin
|
|
1089
|
+
existing = JSON.parse(File.read(path))
|
|
1090
|
+
rescue StandardError => e
|
|
1091
|
+
warn "Failed to parse existing #{path}: #{e.message}"
|
|
1092
|
+
return write_manifest(path, JSON.pretty_generate(new_content))
|
|
1093
|
+
end
|
|
1094
|
+
|
|
1095
|
+
merged = existing.dup
|
|
1096
|
+
merged["servers"] = (existing["servers"] || {}).merge(new_content.fetch("servers"))
|
|
1097
|
+
|
|
1098
|
+
write_manifest(path, JSON.pretty_generate(merged))
|
|
1099
|
+
end
|
|
1100
|
+
|
|
1022
1101
|
def render_opencode_tsconfig
|
|
1023
1102
|
<<~JSON
|
|
1024
1103
|
{
|
|
@@ -1093,19 +1172,20 @@ module Agentf
|
|
|
1093
1172
|
- `agent`: string
|
|
1094
1173
|
|
|
1095
1174
|
### 2. Episodic Memory (`episodic:*`)
|
|
1096
|
-
Used for
|
|
1175
|
+
Used for episode, lesson, playbook, and intent records.
|
|
1097
1176
|
|
|
1098
1177
|
**Search index**: `episodic:logs`
|
|
1099
1178
|
|
|
1100
1179
|
**Schema fields**:
|
|
1101
1180
|
- `$.id`
|
|
1102
1181
|
- `$.type`
|
|
1182
|
+
- `$.outcome`
|
|
1103
1183
|
- `$.title`
|
|
1104
1184
|
- `$.description`
|
|
1105
1185
|
- `$.project`
|
|
1106
1186
|
- `$.context`
|
|
1107
1187
|
- `$.code_snippet`
|
|
1108
|
-
- `$.
|
|
1188
|
+
- `$.embedding`
|
|
1109
1189
|
- `$.created_at`
|
|
1110
1190
|
- `$.agent`
|
|
1111
1191
|
- `$.related_task_id`
|
|
@@ -1116,9 +1196,9 @@ module Agentf
|
|
|
1116
1196
|
|
|
1117
1197
|
- Read recent: `agentf memory recent -n 10`
|
|
1118
1198
|
- Search: `agentf memory search "query" -n 10`
|
|
1199
|
+
- List episodes: `agentf memory episodes -n 10 --outcome=negative`
|
|
1119
1200
|
- Add lesson: `agentf memory add-lesson "<title>" "<description>" --agent=<AGENT>`
|
|
1120
|
-
- Add
|
|
1121
|
-
- Add pitfall: `agentf memory add-pitfall "<title>" "<description>" --agent=<AGENT>`
|
|
1201
|
+
- Add playbook: `agentf memory add-playbook "<title>" "<description>" --steps="<step1>;<step2>"`
|
|
1122
1202
|
MARKDOWN
|
|
1123
1203
|
end
|
|
1124
1204
|
end
|