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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dc86ebb30ccffc8b338dd6e728947f87886c302046e81c01e10d739aac78095f
4
- data.tar.gz: dda17a3643259253dac2b299e8b45c4f016f4e01f381e6b81956f54633eebcd3
3
+ metadata.gz: 31fbac11988e521fb26969fc26f2da9c434541fb0ada47c1b681a6717c4ee018
4
+ data.tar.gz: 761c50541fc3b7207089b22ac710f07b3fd004ae984a1d46b548e92277290196
5
5
  SHA512:
6
- metadata.gz: ff8dd589ee31f74de1a35b0fc8122292b7b78747eb3d45338cc4f9fdcff4f8956f69ad0935aa0cc9b3d7bc3395b607b98d5143e1563c786f83eae44902153bb3
7
- data.tar.gz: 4334dabaf36eabfdfbfeac1b7ff4bda60f1f2b17361df549ef641a85479c2b80b82806a5c18ffacfcba1ee0f7d618c13d55e0ffef8d7e66d0164aade58298a86
6
+ metadata.gz: 348d7d27eae2dddac25859f79c3b8fd99b5be0ebbd7d1447308c146155bb70908519e5ece270fd67255aaa2c313d5f689ce2b1ca46442789c6c229fc8ef47561
7
+ data.tar.gz: 3064ce1fc1f05c85b4d88e3f415202193427dcf21ad57827571eeda79a7975555390a6c506eca05ed36fce9c00d10fda3d9b357ab97930243f83b9934d1dca15
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Agentf
4
+ module AgentRoles
5
+ ORCHESTRATOR = "ORCHESTRATOR"
6
+ PLANNER = "PLANNER"
7
+ ENGINEER = "ENGINEER"
8
+ REVIEWER = "REVIEWER"
9
+ KNOWLEDGE_MANAGER = "KNOWLEDGE_MANAGER"
10
+ RESEARCHER = "RESEARCHER"
11
+ QA_TESTER = "QA_TESTER"
12
+ INCIDENT_RESPONDER = "INCIDENT_RESPONDER"
13
+ UI_ENGINEER = "UI_ENGINEER"
14
+ SECURITY_REVIEWER = "SECURITY_REVIEWER"
15
+
16
+ ALL = [
17
+ ORCHESTRATOR,
18
+ PLANNER,
19
+ ENGINEER,
20
+ REVIEWER,
21
+ KNOWLEDGE_MANAGER,
22
+ RESEARCHER,
23
+ QA_TESTER,
24
+ INCIDENT_RESPONDER,
25
+ UI_ENGINEER,
26
+ SECURITY_REVIEWER
27
+ ].freeze
28
+ end
29
+ end
@@ -22,6 +22,22 @@ module Agentf
22
22
  COMMANDS
23
23
  end
24
24
 
25
+ def self.typed_name
26
+ Agentf::AgentRoles::PLANNER
27
+ end
28
+
29
+ def self.when_to_use
30
+ "Use for planning, decomposition, and constraints mapping before implementation."
31
+ end
32
+
33
+ def self.deliverables
34
+ ["Execution plan", "Decomposed subtasks", "Risk and pitfall notes"]
35
+ end
36
+
37
+ def self.working_style
38
+ "Strategic and constraint-aware with explicit decomposition."
39
+ end
40
+
25
41
  def self.memory_concepts
26
42
  MEMORY_CONCEPTS
27
43
  end
@@ -14,6 +14,18 @@ module Agentf
14
14
  "Agent for #{typed_name.downcase}"
15
15
  end
16
16
 
17
+ def self.when_to_use
18
+ "Use when the workflow needs #{typed_name.downcase.tr('_', ' ')} expertise."
19
+ end
20
+
21
+ def self.deliverables
22
+ []
23
+ end
24
+
25
+ def self.working_style
26
+ "Structured, evidence-based, and outcome-oriented."
27
+ end
28
+
17
29
  def self.commands
18
30
  []
19
31
  end
@@ -23,6 +23,22 @@ module Agentf
23
23
  COMMANDS
24
24
  end
25
25
 
26
+ def self.typed_name
27
+ Agentf::AgentRoles::INCIDENT_RESPONDER
28
+ end
29
+
30
+ def self.when_to_use
31
+ "Use for incident triage, root-cause analysis, and remediation paths."
32
+ end
33
+
34
+ def self.deliverables
35
+ ["Root-cause analysis", "Fix guidance", "Incident lesson record"]
36
+ end
37
+
38
+ def self.working_style
39
+ "Diagnostic, hypothesis-driven, and remediation-focused."
40
+ end
41
+
26
42
  def self.memory_concepts
27
43
  MEMORY_CONCEPTS
28
44
  end
@@ -23,6 +23,22 @@ module Agentf
23
23
  COMMANDS
24
24
  end
25
25
 
26
+ def self.typed_name
27
+ Agentf::AgentRoles::UI_ENGINEER
28
+ end
29
+
30
+ def self.when_to_use
31
+ "Use for transforming design specs into framework-ready UI components."
32
+ end
33
+
34
+ def self.deliverables
35
+ ["Component implementation", "Generated UI code", "Design-system alignment"]
36
+ end
37
+
38
+ def self.working_style
39
+ "Specification-driven with implementation-grade UI output."
40
+ end
41
+
26
42
  def self.memory_concepts
27
43
  MEMORY_CONCEPTS
28
44
  end
@@ -22,6 +22,22 @@ module Agentf
22
22
  COMMANDS
23
23
  end
24
24
 
25
+ def self.typed_name
26
+ Agentf::AgentRoles::KNOWLEDGE_MANAGER
27
+ end
28
+
29
+ def self.when_to_use
30
+ "Use for memory synthesis, knowledge rollups, and delivery-ready summaries."
31
+ end
32
+
33
+ def self.deliverables
34
+ ["Success summary", "Pitfall summary", "Knowledge digest"]
35
+ end
36
+
37
+ def self.working_style
38
+ "Concise synthesis with attention to sensitive data boundaries."
39
+ end
40
+
25
41
  def self.memory_concepts
26
42
  MEMORY_CONCEPTS
27
43
  end
@@ -23,6 +23,22 @@ module Agentf
23
23
  COMMANDS
24
24
  end
25
25
 
26
+ def self.typed_name
27
+ Agentf::AgentRoles::RESEARCHER
28
+ end
29
+
30
+ def self.when_to_use
31
+ "Use for codebase discovery, evidence gathering, and dependency tracing."
32
+ end
33
+
34
+ def self.deliverables
35
+ ["Relevant file list", "Search evidence", "Context breadcrumbs"]
36
+ end
37
+
38
+ def self.working_style
39
+ "Fast exploration with concrete references and traceable findings."
40
+ end
41
+
26
42
  def self.memory_concepts
27
43
  MEMORY_CONCEPTS
28
44
  end
@@ -22,6 +22,22 @@ module Agentf
22
22
  COMMANDS
23
23
  end
24
24
 
25
+ def self.typed_name
26
+ Agentf::AgentRoles::REVIEWER
27
+ end
28
+
29
+ def self.when_to_use
30
+ "Use for approval decisions, regression checks, and evidence-backed review."
31
+ end
32
+
33
+ def self.deliverables
34
+ ["Approval decision", "Issue list", "Pitfall-aligned feedback"]
35
+ end
36
+
37
+ def self.working_style
38
+ "Evidence-first with explicit approval criteria."
39
+ end
40
+
25
41
  def self.memory_concepts
26
42
  MEMORY_CONCEPTS
27
43
  end
@@ -23,6 +23,22 @@ module Agentf
23
23
  COMMANDS
24
24
  end
25
25
 
26
+ def self.typed_name
27
+ Agentf::AgentRoles::SECURITY_REVIEWER
28
+ end
29
+
30
+ def self.when_to_use
31
+ "Use for security gating, prompt-injection checks, and secret leak detection."
32
+ end
33
+
34
+ def self.deliverables
35
+ ["Security findings", "Best-practice checklist", "Pass/warn outcome"]
36
+ end
37
+
38
+ def self.working_style
39
+ "Risk-focused with redaction-safe reporting."
40
+ end
41
+
26
42
  def self.memory_concepts
27
43
  MEMORY_CONCEPTS
28
44
  end
@@ -22,6 +22,22 @@ module Agentf
22
22
  COMMANDS
23
23
  end
24
24
 
25
+ def self.typed_name
26
+ Agentf::AgentRoles::ENGINEER
27
+ end
28
+
29
+ def self.when_to_use
30
+ "Use for implementation, code edits, and deterministic execution outcomes."
31
+ end
32
+
33
+ def self.deliverables
34
+ ["Implemented code", "Execution status", "Success or pitfall memory"]
35
+ end
36
+
37
+ def self.working_style
38
+ "Execution-focused, deterministic, and evidence-driven."
39
+ end
40
+
25
41
  def self.memory_concepts
26
42
  MEMORY_CONCEPTS
27
43
  end
@@ -23,6 +23,22 @@ module Agentf
23
23
  COMMANDS
24
24
  end
25
25
 
26
+ def self.typed_name
27
+ Agentf::AgentRoles::QA_TESTER
28
+ end
29
+
30
+ def self.when_to_use
31
+ "Use for test generation, red/green validation, and execution verification."
32
+ end
33
+
34
+ def self.deliverables
35
+ ["Generated test artifacts", "Pass/fail evidence", "TDD phase signals"]
36
+ end
37
+
38
+ def self.working_style
39
+ "Quality-gate oriented with explicit pass/fail reporting."
40
+ end
41
+
26
42
  def self.memory_concepts
27
43
  MEMORY_CONCEPTS
28
44
  end
@@ -54,6 +54,10 @@ module Agentf
54
54
  list_tags
55
55
  when "search"
56
56
  search_memories(args)
57
+ when "neighbors"
58
+ neighbors(args)
59
+ when "subgraph"
60
+ subgraph(args)
57
61
  when "summary", "stats"
58
62
  show_summary
59
63
  when "by-tag"
@@ -195,7 +199,7 @@ module Agentf
195
199
 
196
200
  tags = parse_list_option(args, "--tags=")
197
201
  context = parse_single_option(args, "--context=").to_s
198
- agent = parse_single_option(args, "--agent=") || "SPECIALIST"
202
+ agent = parse_single_option(args, "--agent=") || Agentf::AgentRoles::ENGINEER
199
203
  code_snippet = parse_single_option(args, "--code=").to_s
200
204
 
201
205
  intent_id = @memory.store_episode(
@@ -297,6 +301,34 @@ module Agentf
297
301
  output(result)
298
302
  end
299
303
 
304
+ def neighbors(args)
305
+ node_id = args.shift.to_s
306
+ if node_id.empty?
307
+ $stderr.puts "Error: neighbors requires a node id"
308
+ exit 1
309
+ end
310
+
311
+ relation = parse_single_option(args, "--relation=")
312
+ depth = parse_integer_option(args, "--depth=", default: 1)
313
+ limit = extract_limit(args)
314
+ result = @reviewer.neighbors(node_id, relation: relation, depth: depth, limit: limit)
315
+ output_graph(result)
316
+ end
317
+
318
+ def subgraph(args)
319
+ seeds = args.shift.to_s.split(",").map(&:strip).reject(&:empty?)
320
+ if seeds.empty?
321
+ $stderr.puts "Error: subgraph requires comma-separated seed ids"
322
+ exit 1
323
+ end
324
+
325
+ relation_filters = parse_list_option(args, "--relation=")
326
+ depth = parse_integer_option(args, "--depth=", default: 2)
327
+ limit = extract_limit(args, default: 200)
328
+ result = @reviewer.subgraph(seed_ids: seeds, relation_filters: relation_filters, depth: depth, limit: limit)
329
+ output_graph(result)
330
+ end
331
+
300
332
  def merge_memory_results(*results, limit:)
301
333
  entries = results.flat_map { |result| result["memories"] || [] }
302
334
  sorted = entries.sort_by { |entry| -(entry["created_at_unix"] || 0) }
@@ -331,6 +363,28 @@ module Agentf
331
363
  end
332
364
  end
333
365
 
366
+ def output_graph(result)
367
+ if result["error"]
368
+ if @json_output
369
+ puts JSON.generate({ "error" => result["error"] })
370
+ else
371
+ $stderr.puts "Error: #{result['error']}"
372
+ end
373
+ exit 1
374
+ end
375
+
376
+ if @json_output
377
+ puts JSON.generate(result)
378
+ return
379
+ end
380
+
381
+ puts "Graph result: #{result['count']} edges"
382
+ puts "Nodes: #{Array(result['nodes']).length}"
383
+ Array(result["edges"]).each do |edge|
384
+ puts " - #{edge['source_id']} --#{edge['relation']}--> #{edge['target_id']}"
385
+ end
386
+ end
387
+
334
388
  def format_memory(mem)
335
389
  <<~OUTPUT
336
390
  [#{mem["type"]&.upcase}] #{mem["title"]}
@@ -366,6 +420,8 @@ module Agentf
366
420
  add-pitfall Store pitfall memory
367
421
  tags List all unique tags
368
422
  search <query> Search memories by keyword
423
+ neighbors <id> Traverse graph edges from a memory id
424
+ subgraph <ids> Build graph from comma-separated seed ids
369
425
  summary, stats Show summary statistics
370
426
  by-tag <tag> Get memories with specific tag
371
427
  by-agent <agent> Get memories from specific agent
@@ -381,9 +437,10 @@ module Agentf
381
437
  agentf memory intents business -n 5
382
438
  agentf memory add-business-intent "Reliability" "Prioritize uptime" --tags=ops,platform --constraints="No downtime;No vendor lock-in"
383
439
  agentf memory add-feature-intent "Agent handoff" "Improve orchestrator continuity" --acceptance="Keeps context;Preserves task state"
384
- agentf memory add-lesson "Refactor strategy" "Extracted adapter seam" --agent=ARCHITECT --tags=architecture
385
- agentf memory add-success "Provider install works" "Installed copilot + opencode manifests" --agent=SPECIALIST
440
+ agentf memory add-lesson "Refactor strategy" "Extracted adapter seam" --agent=PLANNER --tags=architecture
441
+ agentf memory add-success "Provider install works" "Installed copilot + opencode manifests" --agent=ENGINEER
386
442
  agentf memory search "react"
443
+ agentf memory neighbors episode_abcd --depth=2
387
444
  agentf memory by-tag "performance"
388
445
  agentf memory summary
389
446
  HELP
@@ -90,7 +90,7 @@ module Agentf
90
90
 
91
91
  Examples:
92
92
  agentf memory recent -n 5
93
- agentf memory add-lesson "Title" "Description" --agent=ARCHITECT
93
+ agentf memory add-lesson "Title" "Description" --agent=PLANNER
94
94
  agentf code glob "lib/**/*.rb"
95
95
  agentf code grep "def execute" --file-pattern=*.rb
96
96
  agentf install --provider opencode,copilot --scope local
@@ -138,11 +138,11 @@ module Agentf
138
138
 
139
139
  old_files = [
140
140
  File.join(opencode_dir, "tools", "agentf-tools.ts"),
141
- File.join(opencode_dir, "agents", "WORKFLOW_ENGINE.md"),
141
+ File.join(opencode_dir, "agents", "ORCHESTRATOR.md"),
142
142
  File.join(opencode_dir, "memory", "REDIS_SCHEMA.md")
143
143
  ]
144
144
 
145
- old_agent_names = %w[EXPLORER ARCHITECT DESIGNER DEBUGGER REVIEWER TESTER DOCUMENTER SECURITY SPECIALIST]
145
+ old_agent_names = %w[RESEARCHER PLANNER UI_ENGINEER INCIDENT_RESPONDER REVIEWER QA_TESTER KNOWLEDGE_MANAGER SECURITY_REVIEWER ENGINEER]
146
146
  old_files.concat(old_agent_names.map { |name| File.join(opencode_dir, "agents", "#{name}.md") })
147
147
 
148
148
  old_command_names = %w[explorer tester metrics security_scanner memory_reviewer designer debugger architecture]
@@ -23,7 +23,9 @@ module Agentf
23
23
  { "name" => "get_by_type", "type" => "function" },
24
24
  { "name" => "get_by_agent", "type" => "function" },
25
25
  { "name" => "search", "type" => "function" },
26
- { "name" => "get_summary", "type" => "function" }
26
+ { "name" => "get_summary", "type" => "function" },
27
+ { "name" => "neighbors", "type" => "function" },
28
+ { "name" => "subgraph", "type" => "function" }
27
29
  ]
28
30
  }
29
31
  end
@@ -150,6 +152,18 @@ module Agentf
150
152
  { "error" => e.message }
151
153
  end
152
154
 
155
+ def neighbors(node_id, relation: nil, depth: 1, limit: 50)
156
+ @memory.neighbors(node_id: node_id, relation: relation, depth: depth, limit: limit)
157
+ rescue => e
158
+ { "error" => e.message }
159
+ end
160
+
161
+ def subgraph(seed_ids:, depth: 2, relation_filters: nil, limit: 200)
162
+ @memory.subgraph(seed_ids: seed_ids, depth: depth, relation_filters: relation_filters, limit: limit)
163
+ rescue => e
164
+ { "error" => e.message }
165
+ end
166
+
153
167
  private
154
168
 
155
169
  def format_memories(memories)
@@ -169,6 +183,9 @@ module Agentf
169
183
  "code_snippet" => m["code_snippet"],
170
184
  "tags" => m["tags"],
171
185
  "agent" => m["agent"],
186
+ "metadata" => m["metadata"],
187
+ "entity_ids" => m["entity_ids"],
188
+ "relationships" => m["relationships"],
172
189
  "created_at" => format_time(m["created_at"]),
173
190
  "created_at_unix" => m["created_at"]
174
191
  }
@@ -35,7 +35,7 @@ module Agentf
35
35
  description: metric_description(metrics),
36
36
  context: metric_context(metrics),
37
37
  tags: metric_tags(metrics),
38
- agent: "WORKFLOW_ENGINE",
38
+ agent: Agentf::AgentRoles::ORCHESTRATOR,
39
39
  code_snippet: ""
40
40
  )
41
41
 
@@ -128,12 +128,12 @@ module Agentf
128
128
  end
129
129
 
130
130
  def reviewer_approved?(results)
131
- review = results.find { |entry| entry["agent"] == "REVIEWER" }
131
+ review = results.find { |entry| entry["agent"] == Agentf::AgentRoles::REVIEWER }
132
132
  review&.dig("result", "approved") == true
133
133
  end
134
134
 
135
135
  def security_issue_count(results)
136
- security_result = results.find { |entry| entry["agent"] == "SECURITY" }
136
+ security_result = results.find { |entry| entry["agent"] == Agentf::AgentRoles::SECURITY_REVIEWER }
137
137
  issues = security_result&.dig("result", "issues")
138
138
  Array(issues).length
139
139
  end
@@ -190,12 +190,11 @@ module Agentf
190
190
 
191
191
  memories
192
192
  .select { |m| Array(m["tags"]).include?(WORKFLOW_METRICS_TAG) }
193
- .filter_map do |m|
193
+ .map do |m|
194
194
  context = parse_context_json(m["context"])
195
- next if context.nil?
196
-
197
195
  context
198
196
  end
197
+ .compact
199
198
  end
200
199
 
201
200
  def parse_context_json(value)