feat(agentic): add brain recall CLI command
Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
b0662c282b
commit
d6a03be140
2 changed files with 169 additions and 0 deletions
|
|
@ -39,6 +39,8 @@ func (s *PrepSubsystem) registerCommands(ctx context.Context) {
|
|||
c.Command("agentic:mirror", core.Command{Description: "Mirror Forge repos to GitHub", Action: s.cmdMirror})
|
||||
c.Command("brain/ingest", core.Command{Description: "Bulk ingest memories into OpenBrain", Action: s.cmdBrainIngest})
|
||||
c.Command("brain:ingest", core.Command{Description: "Bulk ingest memories into OpenBrain", Action: s.cmdBrainIngest})
|
||||
c.Command("brain/recall", core.Command{Description: "Recall memories from OpenBrain", Action: s.cmdBrainRecall})
|
||||
c.Command("brain:recall", core.Command{Description: "Recall memories from OpenBrain", Action: s.cmdBrainRecall})
|
||||
c.Command("brain/seed-memory", core.Command{Description: "Import markdown memories into OpenBrain from a project memory directory", Action: s.cmdBrainSeedMemory})
|
||||
c.Command("brain:seed-memory", core.Command{Description: "Import markdown memories into OpenBrain from a project memory directory", Action: s.cmdBrainSeedMemory})
|
||||
c.Command("brain/list", core.Command{Description: "List memories in OpenBrain", Action: s.cmdBrainList})
|
||||
|
|
@ -463,6 +465,59 @@ func (s *PrepSubsystem) cmdBrainList(options core.Options) core.Result {
|
|||
return core.Result{Value: output, OK: true}
|
||||
}
|
||||
|
||||
// result := c.Command("brain/recall").Run(ctx, core.NewOptions(
|
||||
//
|
||||
// core.Option{Key: "query", Value: "workspace handoff context"},
|
||||
//
|
||||
// ))
|
||||
func (s *PrepSubsystem) cmdBrainRecall(options core.Options) core.Result {
|
||||
query := optionStringValue(options, "query", "_arg")
|
||||
if query == "" {
|
||||
core.Print(nil, "usage: core-agent brain recall <query> [--top-k=10] [--project=agent] [--type=architecture] [--agent=virgil] [--min-confidence=0.7]")
|
||||
return core.Result{Value: core.E("agentic.cmdBrainRecall", "query is required", nil), OK: false}
|
||||
}
|
||||
|
||||
result := s.Core().Action("brain.recall").Run(s.commandContext(), core.NewOptions(
|
||||
core.Option{Key: "query", Value: query},
|
||||
core.Option{Key: "top_k", Value: optionIntValue(options, "top_k", "top-k")},
|
||||
core.Option{Key: "project", Value: optionStringValue(options, "project")},
|
||||
core.Option{Key: "type", Value: optionStringValue(options, "type")},
|
||||
core.Option{Key: "agent_id", Value: optionStringValue(options, "agent_id", "agent")},
|
||||
core.Option{Key: "min_confidence", Value: optionStringValue(options, "min_confidence", "min-confidence")},
|
||||
))
|
||||
if !result.OK {
|
||||
err := commandResultError("agentic.cmdBrainRecall", result)
|
||||
core.Print(nil, "error: %v", err)
|
||||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
|
||||
output, ok := brainRecallOutputFromResult(result.Value)
|
||||
if !ok {
|
||||
err := core.E("agentic.cmdBrainRecall", "invalid brain recall output", nil)
|
||||
core.Print(nil, "error: %v", err)
|
||||
return core.Result{Value: err, OK: false}
|
||||
}
|
||||
|
||||
core.Print(nil, "count: %d", output.Count)
|
||||
if len(output.Memories) == 0 {
|
||||
core.Print(nil, "no memories")
|
||||
return core.Result{Value: output, OK: true}
|
||||
}
|
||||
|
||||
for _, memory := range output.Memories {
|
||||
if memory.Project != "" || memory.AgentID != "" || memory.Confidence != 0 {
|
||||
core.Print(nil, " %s %-12s %s %s %.2f", memory.ID, memory.Type, memory.Project, memory.AgentID, memory.Confidence)
|
||||
} else {
|
||||
core.Print(nil, " %s %-12s", memory.ID, memory.Type)
|
||||
}
|
||||
if memory.Content != "" {
|
||||
core.Print(nil, " %s", memory.Content)
|
||||
}
|
||||
}
|
||||
|
||||
return core.Result{Value: output, OK: true}
|
||||
}
|
||||
|
||||
// result := c.Command("brain/forget").Run(ctx, core.NewOptions(core.Option{Key: "_arg", Value: "mem-1"}))
|
||||
func (s *PrepSubsystem) cmdBrainForget(options core.Options) core.Result {
|
||||
id := optionStringValue(options, "id", "_arg")
|
||||
|
|
@ -488,6 +543,43 @@ func (s *PrepSubsystem) cmdBrainForget(options core.Options) core.Result {
|
|||
return core.Result{Value: result.Value, OK: true}
|
||||
}
|
||||
|
||||
type brainRecallOutput struct {
|
||||
Count int `json:"count"`
|
||||
Memories []brainRecallMemory `json:"memories"`
|
||||
}
|
||||
|
||||
type brainRecallMemory struct {
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Content string `json:"content"`
|
||||
Project string `json:"project"`
|
||||
AgentID string `json:"agent_id"`
|
||||
Confidence float64 `json:"confidence"`
|
||||
Tags []string `json:"tags"`
|
||||
}
|
||||
|
||||
func brainRecallOutputFromResult(value any) (brainRecallOutput, bool) {
|
||||
switch typed := value.(type) {
|
||||
case brainRecallOutput:
|
||||
return typed, true
|
||||
case *brainRecallOutput:
|
||||
if typed == nil {
|
||||
return brainRecallOutput{}, false
|
||||
}
|
||||
return *typed, true
|
||||
default:
|
||||
jsonResult := core.JSONMarshalString(value)
|
||||
if jsonResult == "" {
|
||||
return brainRecallOutput{}, false
|
||||
}
|
||||
var output brainRecallOutput
|
||||
if parseResult := core.JSONUnmarshalString(jsonResult, &output); !parseResult.OK {
|
||||
return brainRecallOutput{}, false
|
||||
}
|
||||
return output, true
|
||||
}
|
||||
}
|
||||
|
||||
func (s *PrepSubsystem) cmdStatus(options core.Options) core.Result {
|
||||
workspaceRoot := WorkspaceRoot()
|
||||
filesystem := s.Core().Fs()
|
||||
|
|
|
|||
|
|
@ -225,6 +225,15 @@ func TestCommandsforge_CmdIssueCreate_Good_WithLabelsAndMilestone(t *testing.T)
|
|||
assert.True(t, r.OK)
|
||||
}
|
||||
|
||||
func TestCommands_RegisterCommands_Good_BrainRecall(t *testing.T) {
|
||||
s, c := testPrepWithCore(t, nil)
|
||||
|
||||
s.registerCommands(context.Background())
|
||||
|
||||
assert.Contains(t, c.Commands(), "brain/recall")
|
||||
assert.Contains(t, c.Commands(), "brain:recall")
|
||||
}
|
||||
|
||||
func TestCommands_CmdBrainList_Good(t *testing.T) {
|
||||
s, c := testPrepWithCore(t, nil)
|
||||
c.Action("brain.list", func(_ context.Context, options core.Options) core.Result {
|
||||
|
|
@ -287,6 +296,74 @@ func TestCommands_CmdBrainList_Ugly_InvalidOutput(t *testing.T) {
|
|||
assert.Contains(t, err.Error(), "invalid brain list output")
|
||||
}
|
||||
|
||||
func TestCommands_CmdBrainRecall_Good(t *testing.T) {
|
||||
s, c := testPrepWithCore(t, nil)
|
||||
c.Action("brain.recall", func(_ context.Context, options core.Options) core.Result {
|
||||
assert.Equal(t, "workspace handoff context", options.String("query"))
|
||||
assert.Equal(t, 3, options.Int("top_k"))
|
||||
assert.Equal(t, "agent", options.String("project"))
|
||||
assert.Equal(t, "architecture", options.String("type"))
|
||||
assert.Equal(t, "virgil", options.String("agent_id"))
|
||||
assert.Equal(t, "0.75", options.String("min_confidence"))
|
||||
return core.Result{Value: map[string]any{
|
||||
"success": true,
|
||||
"count": 1,
|
||||
"memories": []any{
|
||||
map[string]any{
|
||||
"id": "mem-1",
|
||||
"type": "architecture",
|
||||
"content": "Use named actions.",
|
||||
"project": "agent",
|
||||
"agent_id": "virgil",
|
||||
"confidence": 0.75,
|
||||
"tags": []any{"architecture", "convention"},
|
||||
},
|
||||
},
|
||||
}, OK: true}
|
||||
})
|
||||
|
||||
output := captureStdout(t, func() {
|
||||
result := s.cmdBrainRecall(core.NewOptions(
|
||||
core.Option{Key: "_arg", Value: "workspace handoff context"},
|
||||
core.Option{Key: "top_k", Value: 3},
|
||||
core.Option{Key: "project", Value: "agent"},
|
||||
core.Option{Key: "type", Value: "architecture"},
|
||||
core.Option{Key: "agent", Value: "virgil"},
|
||||
core.Option{Key: "min_confidence", Value: "0.75"},
|
||||
))
|
||||
require.True(t, result.OK)
|
||||
})
|
||||
|
||||
assert.Contains(t, output, "count: 1")
|
||||
assert.Contains(t, output, "mem-1 architecture")
|
||||
assert.Contains(t, output, "Use named actions.")
|
||||
}
|
||||
|
||||
func TestCommands_CmdBrainRecall_Bad_MissingQuery(t *testing.T) {
|
||||
s, _ := testPrepWithCore(t, nil)
|
||||
|
||||
result := s.cmdBrainRecall(core.NewOptions())
|
||||
|
||||
require.False(t, result.OK)
|
||||
err, ok := result.Value.(error)
|
||||
require.True(t, ok)
|
||||
assert.Contains(t, err.Error(), "query is required")
|
||||
}
|
||||
|
||||
func TestCommands_CmdBrainRecall_Ugly_InvalidOutput(t *testing.T) {
|
||||
s, c := testPrepWithCore(t, nil)
|
||||
c.Action("brain.recall", func(_ context.Context, _ core.Options) core.Result {
|
||||
return core.Result{Value: 123, OK: true}
|
||||
})
|
||||
|
||||
result := s.cmdBrainRecall(core.NewOptions(core.Option{Key: "_arg", Value: "workspace handoff context"}))
|
||||
|
||||
require.False(t, result.OK)
|
||||
err, ok := result.Value.(error)
|
||||
require.True(t, ok)
|
||||
assert.Contains(t, err.Error(), "invalid brain recall output")
|
||||
}
|
||||
|
||||
func TestCommands_CmdBrainForget_Good(t *testing.T) {
|
||||
s, c := testPrepWithCore(t, nil)
|
||||
c.Action("brain.forget", func(_ context.Context, options core.Options) core.Result {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue