2026-03-16 11:10:33 +00:00
|
|
|
// SPDX-License-Identifier: EUPL-1.2
|
|
|
|
|
|
|
|
|
|
package brain
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
2026-03-31 06:33:01 +00:00
|
|
|
"net/url"
|
2026-03-16 11:10:33 +00:00
|
|
|
"time"
|
|
|
|
|
|
2026-03-21 11:10:31 +00:00
|
|
|
"dappco.re/go/agent/pkg/agentic"
|
refactor: migrate core/agent to Core primitives — reference implementation
Phase 1: go-io/go-log → core.Fs{}, core.E(), core.Error/Info/Warn
Phase 2: strings/fmt → core.Contains, core.Sprintf, core.Split etc
Phase 3: embed.FS → core.Mount/core.Embed, core.Extract
Phase 4: cmd/main.go → core.Command(), c.Cli().Run(), no cli package
All packages migrated:
- pkg/lib (Codex): core.Mount, core.Extract, Result returns, AX comments
- pkg/setup (Codex): core.Fs, core.E, fixed missing lib helpers
- pkg/brain (Codex): Core primitives, AX comments
- pkg/monitor (Codex): Core string/logging primitives
- pkg/agentic (Codex): 20 files, Core primitives throughout
- cmd/main.go: pure Core CLI, no fmt/log/filepath/strings/cli
Remaining stdlib: path/filepath (Core doesn't wrap OS paths),
fmt.Sscanf/strings.Map (no Core equivalent).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 06:13:41 +00:00
|
|
|
core "dappco.re/go/core"
|
2026-03-29 20:15:58 +00:00
|
|
|
coremcp "forge.lthn.ai/core/mcp/pkg/mcp"
|
2026-03-16 11:10:33 +00:00
|
|
|
"github.com/modelcontextprotocol/go-sdk/mcp"
|
|
|
|
|
)
|
|
|
|
|
|
2026-03-30 22:30:05 +00:00
|
|
|
// subsystem := brain.NewDirect()
|
|
|
|
|
// core.Println(subsystem.Name()) // "brain"
|
2026-03-16 11:10:33 +00:00
|
|
|
type DirectSubsystem struct {
|
2026-04-02 08:40:24 +00:00
|
|
|
*core.ServiceRuntime[DirectOptions]
|
2026-03-16 11:10:33 +00:00
|
|
|
apiURL string
|
|
|
|
|
apiKey string
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-22 06:42:42 +00:00
|
|
|
var _ coremcp.Subsystem = (*DirectSubsystem)(nil)
|
|
|
|
|
|
2026-03-30 22:30:05 +00:00
|
|
|
// subsystem := brain.NewDirect()
|
|
|
|
|
// core.Println(subsystem.Name())
|
2026-03-16 11:10:33 +00:00
|
|
|
func NewDirect() *DirectSubsystem {
|
2026-03-22 13:02:37 +00:00
|
|
|
apiURL := core.Env("CORE_BRAIN_URL")
|
2026-03-16 11:10:33 +00:00
|
|
|
if apiURL == "" {
|
|
|
|
|
apiURL = "https://api.lthn.sh"
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-22 13:02:37 +00:00
|
|
|
apiKey := core.Env("CORE_BRAIN_KEY")
|
refactor: migrate core/agent to Core primitives — reference implementation
Phase 1: go-io/go-log → core.Fs{}, core.E(), core.Error/Info/Warn
Phase 2: strings/fmt → core.Contains, core.Sprintf, core.Split etc
Phase 3: embed.FS → core.Mount/core.Embed, core.Extract
Phase 4: cmd/main.go → core.Command(), c.Cli().Run(), no cli package
All packages migrated:
- pkg/lib (Codex): core.Mount, core.Extract, Result returns, AX comments
- pkg/setup (Codex): core.Fs, core.E, fixed missing lib helpers
- pkg/brain (Codex): Core primitives, AX comments
- pkg/monitor (Codex): Core string/logging primitives
- pkg/agentic (Codex): 20 files, Core primitives throughout
- cmd/main.go: pure Core CLI, no fmt/log/filepath/strings/cli
Remaining stdlib: path/filepath (Core doesn't wrap OS paths),
fmt.Sscanf/strings.Map (no Core equivalent).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 06:13:41 +00:00
|
|
|
keyPath := ""
|
2026-03-16 11:10:33 +00:00
|
|
|
if apiKey == "" {
|
2026-03-30 20:32:17 +00:00
|
|
|
keyPath = brainKeyPath(agentic.HomeDir())
|
refactor: migrate core/agent to Core primitives — reference implementation
Phase 1: go-io/go-log → core.Fs{}, core.E(), core.Error/Info/Warn
Phase 2: strings/fmt → core.Contains, core.Sprintf, core.Split etc
Phase 3: embed.FS → core.Mount/core.Embed, core.Extract
Phase 4: cmd/main.go → core.Command(), c.Cli().Run(), no cli package
All packages migrated:
- pkg/lib (Codex): core.Mount, core.Extract, Result returns, AX comments
- pkg/setup (Codex): core.Fs, core.E, fixed missing lib helpers
- pkg/brain (Codex): Core primitives, AX comments
- pkg/monitor (Codex): Core string/logging primitives
- pkg/agentic (Codex): 20 files, Core primitives throughout
- cmd/main.go: pure Core CLI, no fmt/log/filepath/strings/cli
Remaining stdlib: path/filepath (Core doesn't wrap OS paths),
fmt.Sscanf/strings.Map (no Core equivalent).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 06:13:41 +00:00
|
|
|
if keyPath != "" {
|
2026-03-30 21:11:06 +00:00
|
|
|
if readResult := fs.Read(keyPath); readResult.OK {
|
|
|
|
|
apiKey = core.Trim(readResult.Value.(string))
|
refactor: migrate core/agent to Core primitives — reference implementation
Phase 1: go-io/go-log → core.Fs{}, core.E(), core.Error/Info/Warn
Phase 2: strings/fmt → core.Contains, core.Sprintf, core.Split etc
Phase 3: embed.FS → core.Mount/core.Embed, core.Extract
Phase 4: cmd/main.go → core.Command(), c.Cli().Run(), no cli package
All packages migrated:
- pkg/lib (Codex): core.Mount, core.Extract, Result returns, AX comments
- pkg/setup (Codex): core.Fs, core.E, fixed missing lib helpers
- pkg/brain (Codex): Core primitives, AX comments
- pkg/monitor (Codex): Core string/logging primitives
- pkg/agentic (Codex): 20 files, Core primitives throughout
- cmd/main.go: pure Core CLI, no fmt/log/filepath/strings/cli
Remaining stdlib: path/filepath (Core doesn't wrap OS paths),
fmt.Sscanf/strings.Map (no Core equivalent).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 06:13:41 +00:00
|
|
|
if apiKey != "" {
|
|
|
|
|
core.Info("brain direct subsystem loaded API key from file", "path", keyPath)
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-03-16 11:10:33 +00:00
|
|
|
}
|
|
|
|
|
}
|
refactor: migrate core/agent to Core primitives — reference implementation
Phase 1: go-io/go-log → core.Fs{}, core.E(), core.Error/Info/Warn
Phase 2: strings/fmt → core.Contains, core.Sprintf, core.Split etc
Phase 3: embed.FS → core.Mount/core.Embed, core.Extract
Phase 4: cmd/main.go → core.Command(), c.Cli().Run(), no cli package
All packages migrated:
- pkg/lib (Codex): core.Mount, core.Extract, Result returns, AX comments
- pkg/setup (Codex): core.Fs, core.E, fixed missing lib helpers
- pkg/brain (Codex): Core primitives, AX comments
- pkg/monitor (Codex): Core string/logging primitives
- pkg/agentic (Codex): 20 files, Core primitives throughout
- cmd/main.go: pure Core CLI, no fmt/log/filepath/strings/cli
Remaining stdlib: path/filepath (Core doesn't wrap OS paths),
fmt.Sscanf/strings.Map (no Core equivalent).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 06:13:41 +00:00
|
|
|
if apiKey == "" {
|
|
|
|
|
core.Warn("brain direct subsystem has no API key configured", "path", keyPath)
|
|
|
|
|
}
|
2026-03-16 11:10:33 +00:00
|
|
|
|
|
|
|
|
return &DirectSubsystem{
|
|
|
|
|
apiURL: apiURL,
|
|
|
|
|
apiKey: apiKey,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-30 22:30:05 +00:00
|
|
|
// name := subsystem.Name() // "brain"
|
2026-03-16 11:10:33 +00:00
|
|
|
func (s *DirectSubsystem) Name() string { return "brain" }
|
|
|
|
|
|
2026-03-30 22:30:05 +00:00
|
|
|
// subsystem := brain.NewDirect()
|
|
|
|
|
// subsystem.RegisterTools(server)
|
2026-03-16 11:10:33 +00:00
|
|
|
func (s *DirectSubsystem) RegisterTools(server *mcp.Server) {
|
|
|
|
|
mcp.AddTool(server, &mcp.Tool{
|
|
|
|
|
Name: "brain_remember",
|
|
|
|
|
Description: "Store a memory in OpenBrain. Types: fact, decision, observation, plan, convention, architecture, research, documentation, service, bug, pattern, context, procedure.",
|
|
|
|
|
}, s.remember)
|
|
|
|
|
|
|
|
|
|
mcp.AddTool(server, &mcp.Tool{
|
|
|
|
|
Name: "brain_recall",
|
|
|
|
|
Description: "Semantic search across OpenBrain memories. Returns memories ranked by similarity. Use agent_id 'cladius' for Cladius's memories.",
|
|
|
|
|
}, s.recall)
|
|
|
|
|
|
|
|
|
|
mcp.AddTool(server, &mcp.Tool{
|
|
|
|
|
Name: "brain_forget",
|
|
|
|
|
Description: "Remove a memory from OpenBrain by ID.",
|
|
|
|
|
}, s.forget)
|
2026-03-16 14:03:36 +00:00
|
|
|
|
2026-03-31 06:33:01 +00:00
|
|
|
mcp.AddTool(server, &mcp.Tool{
|
|
|
|
|
Name: "brain_list",
|
|
|
|
|
Description: "List memories in OpenBrain with optional project, type, agent, and limit filters.",
|
|
|
|
|
}, s.list)
|
|
|
|
|
|
2026-03-16 14:03:36 +00:00
|
|
|
s.RegisterMessagingTools(server)
|
2026-03-16 11:10:33 +00:00
|
|
|
}
|
|
|
|
|
|
2026-03-30 22:30:05 +00:00
|
|
|
// _ = subsystem.Shutdown(context.Background())
|
2026-03-16 11:10:33 +00:00
|
|
|
func (s *DirectSubsystem) Shutdown(_ context.Context) error { return nil }
|
|
|
|
|
|
refactor: migrate core/agent to Core primitives — reference implementation
Phase 1: go-io/go-log → core.Fs{}, core.E(), core.Error/Info/Warn
Phase 2: strings/fmt → core.Contains, core.Sprintf, core.Split etc
Phase 3: embed.FS → core.Mount/core.Embed, core.Extract
Phase 4: cmd/main.go → core.Command(), c.Cli().Run(), no cli package
All packages migrated:
- pkg/lib (Codex): core.Mount, core.Extract, Result returns, AX comments
- pkg/setup (Codex): core.Fs, core.E, fixed missing lib helpers
- pkg/brain (Codex): Core primitives, AX comments
- pkg/monitor (Codex): Core string/logging primitives
- pkg/agentic (Codex): 20 files, Core primitives throughout
- cmd/main.go: pure Core CLI, no fmt/log/filepath/strings/cli
Remaining stdlib: path/filepath (Core doesn't wrap OS paths),
fmt.Sscanf/strings.Map (no Core equivalent).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 06:13:41 +00:00
|
|
|
func brainKeyPath(home string) string {
|
|
|
|
|
if home == "" {
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
return core.JoinPath(core.TrimSuffix(home, "/"), ".claude", "brain.key")
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-29 23:45:48 +00:00
|
|
|
func (s *DirectSubsystem) apiCall(ctx context.Context, method, path string, body any) core.Result {
|
2026-03-16 11:10:33 +00:00
|
|
|
if s.apiKey == "" {
|
2026-03-29 23:45:48 +00:00
|
|
|
return core.Result{
|
|
|
|
|
Value: core.E("brain.apiCall", "no API key (set CORE_BRAIN_KEY or create ~/.claude/brain.key)", nil),
|
2026-03-30 15:33:01 +00:00
|
|
|
OK: false,
|
2026-03-29 23:45:48 +00:00
|
|
|
}
|
2026-03-16 11:10:33 +00:00
|
|
|
}
|
|
|
|
|
|
refactor: migrate core/agent to Core primitives — reference implementation
Phase 1: go-io/go-log → core.Fs{}, core.E(), core.Error/Info/Warn
Phase 2: strings/fmt → core.Contains, core.Sprintf, core.Split etc
Phase 3: embed.FS → core.Mount/core.Embed, core.Extract
Phase 4: cmd/main.go → core.Command(), c.Cli().Run(), no cli package
All packages migrated:
- pkg/lib (Codex): core.Mount, core.Extract, Result returns, AX comments
- pkg/setup (Codex): core.Fs, core.E, fixed missing lib helpers
- pkg/brain (Codex): Core primitives, AX comments
- pkg/monitor (Codex): Core string/logging primitives
- pkg/agentic (Codex): 20 files, Core primitives throughout
- cmd/main.go: pure Core CLI, no fmt/log/filepath/strings/cli
Remaining stdlib: path/filepath (Core doesn't wrap OS paths),
fmt.Sscanf/strings.Map (no Core equivalent).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 06:13:41 +00:00
|
|
|
requestURL := core.Concat(s.apiURL, path)
|
feat(v0.8.0): full AX migration — ServiceRuntime, Actions, quality gates, transport
go-process:
- Register factory, Result lifecycle, 5 named Action handlers
- Start/Run/StartWithOptions/RunWithOptions all return core.Result
- core.ID() replaces fmt.Sprintf, core.As replaces errors.As
core/agent:
- PrepSubsystem + monitor.Subsystem + setup.Service embed ServiceRuntime[T]
- 22 named Actions + agent.completion Task pipeline in OnStartup
- ChannelNotifier removed — all IPC via c.ACTION(messages.X{})
- proc.go: all methods via s.Core().Process(), returns core.Result
- status.go: WriteAtomic + JSONMarshalString
- paths.go: Fs.NewUnrestricted() replaces unsafe.Pointer
- transport.go: ONE net/http file — HTTPGet/HTTPPost/HTTPDo/MCP transport
- All disallowed imports eliminated from source files (13 quality gates)
- String concat eliminated — core.Concat() throughout
- 1:1 _test.go + _example_test.go for every source file
- Reference docs synced from core/go v0.8.0
- RFC-025 updated with net/http, net/url, io/fs quality gates
- lib.go: io/fs eliminated via Data.ListNames, Array[T].Deduplicate
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-26 01:27:46 +00:00
|
|
|
var bodyStr string
|
|
|
|
|
if body != nil {
|
|
|
|
|
bodyStr = core.JSONMarshalString(body)
|
2026-03-16 11:10:33 +00:00
|
|
|
}
|
2026-03-30 21:11:06 +00:00
|
|
|
requestResult := agentic.HTTPDo(ctx, method, requestURL, bodyStr, s.apiKey, "Bearer")
|
|
|
|
|
if !requestResult.OK {
|
feat(v0.8.0): full AX migration — ServiceRuntime, Actions, quality gates, transport
go-process:
- Register factory, Result lifecycle, 5 named Action handlers
- Start/Run/StartWithOptions/RunWithOptions all return core.Result
- core.ID() replaces fmt.Sprintf, core.As replaces errors.As
core/agent:
- PrepSubsystem + monitor.Subsystem + setup.Service embed ServiceRuntime[T]
- 22 named Actions + agent.completion Task pipeline in OnStartup
- ChannelNotifier removed — all IPC via c.ACTION(messages.X{})
- proc.go: all methods via s.Core().Process(), returns core.Result
- status.go: WriteAtomic + JSONMarshalString
- paths.go: Fs.NewUnrestricted() replaces unsafe.Pointer
- transport.go: ONE net/http file — HTTPGet/HTTPPost/HTTPDo/MCP transport
- All disallowed imports eliminated from source files (13 quality gates)
- String concat eliminated — core.Concat() throughout
- 1:1 _test.go + _example_test.go for every source file
- Reference docs synced from core/go v0.8.0
- RFC-025 updated with net/http, net/url, io/fs quality gates
- lib.go: io/fs eliminated via Data.ListNames, Array[T].Deduplicate
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-26 01:27:46 +00:00
|
|
|
core.Error("brain API call failed", "method", method, "path", path)
|
2026-03-30 21:11:06 +00:00
|
|
|
if err, ok := requestResult.Value.(error); ok {
|
2026-03-30 15:33:01 +00:00
|
|
|
return core.Result{Value: core.E("brain.apiCall", "API call failed", err), OK: false}
|
|
|
|
|
}
|
2026-03-30 21:11:06 +00:00
|
|
|
if responseBody, ok := requestResult.Value.(string); ok && responseBody != "" {
|
2026-03-30 15:33:01 +00:00
|
|
|
return core.Result{Value: core.E("brain.apiCall", core.Concat("API call failed: ", core.Trim(responseBody)), nil), OK: false}
|
|
|
|
|
}
|
|
|
|
|
return core.Result{Value: core.E("brain.apiCall", "API call failed", nil), OK: false}
|
2026-03-16 11:10:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var result map[string]any
|
2026-03-30 21:11:06 +00:00
|
|
|
if parseResult := core.JSONUnmarshalString(requestResult.Value.(string), &result); !parseResult.OK {
|
feat(v0.8.0): full AX migration — ServiceRuntime, Actions, quality gates, transport
go-process:
- Register factory, Result lifecycle, 5 named Action handlers
- Start/Run/StartWithOptions/RunWithOptions all return core.Result
- core.ID() replaces fmt.Sprintf, core.As replaces errors.As
core/agent:
- PrepSubsystem + monitor.Subsystem + setup.Service embed ServiceRuntime[T]
- 22 named Actions + agent.completion Task pipeline in OnStartup
- ChannelNotifier removed — all IPC via c.ACTION(messages.X{})
- proc.go: all methods via s.Core().Process(), returns core.Result
- status.go: WriteAtomic + JSONMarshalString
- paths.go: Fs.NewUnrestricted() replaces unsafe.Pointer
- transport.go: ONE net/http file — HTTPGet/HTTPPost/HTTPDo/MCP transport
- All disallowed imports eliminated from source files (13 quality gates)
- String concat eliminated — core.Concat() throughout
- 1:1 _test.go + _example_test.go for every source file
- Reference docs synced from core/go v0.8.0
- RFC-025 updated with net/http, net/url, io/fs quality gates
- lib.go: io/fs eliminated via Data.ListNames, Array[T].Deduplicate
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-26 01:27:46 +00:00
|
|
|
core.Error("brain API response parse failed", "method", method, "path", path)
|
2026-03-30 21:11:06 +00:00
|
|
|
err, _ := parseResult.Value.(error)
|
2026-03-30 15:33:01 +00:00
|
|
|
return core.Result{Value: core.E("brain.apiCall", "parse response", err), OK: false}
|
2026-03-16 11:10:33 +00:00
|
|
|
}
|
|
|
|
|
|
2026-03-29 23:45:48 +00:00
|
|
|
return core.Result{Value: result, OK: true}
|
2026-03-16 11:10:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *DirectSubsystem) remember(ctx context.Context, _ *mcp.CallToolRequest, input RememberInput) (*mcp.CallToolResult, RememberOutput, error) {
|
2026-03-29 23:45:48 +00:00
|
|
|
result := s.apiCall(ctx, "POST", "/v1/brain/remember", map[string]any{
|
refactor: migrate core/agent to Core primitives — reference implementation
Phase 1: go-io/go-log → core.Fs{}, core.E(), core.Error/Info/Warn
Phase 2: strings/fmt → core.Contains, core.Sprintf, core.Split etc
Phase 3: embed.FS → core.Mount/core.Embed, core.Extract
Phase 4: cmd/main.go → core.Command(), c.Cli().Run(), no cli package
All packages migrated:
- pkg/lib (Codex): core.Mount, core.Extract, Result returns, AX comments
- pkg/setup (Codex): core.Fs, core.E, fixed missing lib helpers
- pkg/brain (Codex): Core primitives, AX comments
- pkg/monitor (Codex): Core string/logging primitives
- pkg/agentic (Codex): 20 files, Core primitives throughout
- cmd/main.go: pure Core CLI, no fmt/log/filepath/strings/cli
Remaining stdlib: path/filepath (Core doesn't wrap OS paths),
fmt.Sscanf/strings.Map (no Core equivalent).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 06:13:41 +00:00
|
|
|
"content": input.Content,
|
|
|
|
|
"type": input.Type,
|
|
|
|
|
"tags": input.Tags,
|
|
|
|
|
"project": input.Project,
|
|
|
|
|
"confidence": input.Confidence,
|
|
|
|
|
"supersedes": input.Supersedes,
|
|
|
|
|
"expires_in": input.ExpiresIn,
|
|
|
|
|
"agent_id": agentic.AgentName(),
|
2026-03-16 11:10:33 +00:00
|
|
|
})
|
2026-03-29 23:45:48 +00:00
|
|
|
if !result.OK {
|
|
|
|
|
err, _ := result.Value.(error)
|
2026-03-16 11:10:33 +00:00
|
|
|
return nil, RememberOutput{}, err
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-29 23:45:48 +00:00
|
|
|
payload, _ := result.Value.(map[string]any)
|
2026-03-16 11:10:33 +00:00
|
|
|
return nil, RememberOutput{
|
|
|
|
|
Success: true,
|
2026-03-31 11:52:01 +00:00
|
|
|
MemoryID: stringField(payloadMap(payload), "id"),
|
2026-03-16 11:10:33 +00:00
|
|
|
Timestamp: time.Now(),
|
|
|
|
|
}, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *DirectSubsystem) recall(ctx context.Context, _ *mcp.CallToolRequest, input RecallInput) (*mcp.CallToolResult, RecallOutput, error) {
|
|
|
|
|
body := map[string]any{
|
2026-03-16 11:50:20 +00:00
|
|
|
"query": input.Query,
|
|
|
|
|
"top_k": input.TopK,
|
|
|
|
|
}
|
|
|
|
|
if input.Filter.AgentID != "" {
|
|
|
|
|
body["agent_id"] = input.Filter.AgentID
|
2026-03-16 11:10:33 +00:00
|
|
|
}
|
|
|
|
|
if input.Filter.Project != "" {
|
|
|
|
|
body["project"] = input.Filter.Project
|
|
|
|
|
}
|
|
|
|
|
if input.Filter.Type != nil {
|
|
|
|
|
body["type"] = input.Filter.Type
|
|
|
|
|
}
|
refactor: migrate core/agent to Core primitives — reference implementation
Phase 1: go-io/go-log → core.Fs{}, core.E(), core.Error/Info/Warn
Phase 2: strings/fmt → core.Contains, core.Sprintf, core.Split etc
Phase 3: embed.FS → core.Mount/core.Embed, core.Extract
Phase 4: cmd/main.go → core.Command(), c.Cli().Run(), no cli package
All packages migrated:
- pkg/lib (Codex): core.Mount, core.Extract, Result returns, AX comments
- pkg/setup (Codex): core.Fs, core.E, fixed missing lib helpers
- pkg/brain (Codex): Core primitives, AX comments
- pkg/monitor (Codex): Core string/logging primitives
- pkg/agentic (Codex): 20 files, Core primitives throughout
- cmd/main.go: pure Core CLI, no fmt/log/filepath/strings/cli
Remaining stdlib: path/filepath (Core doesn't wrap OS paths),
fmt.Sscanf/strings.Map (no Core equivalent).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 06:13:41 +00:00
|
|
|
if input.Filter.MinConfidence != 0 {
|
|
|
|
|
body["min_confidence"] = input.Filter.MinConfidence
|
|
|
|
|
}
|
2026-03-16 11:10:33 +00:00
|
|
|
if input.TopK == 0 {
|
|
|
|
|
body["top_k"] = 10
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-29 23:45:48 +00:00
|
|
|
result := s.apiCall(ctx, "POST", "/v1/brain/recall", body)
|
|
|
|
|
if !result.OK {
|
|
|
|
|
err, _ := result.Value.(error)
|
2026-03-16 11:10:33 +00:00
|
|
|
return nil, RecallOutput{}, err
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-29 23:45:48 +00:00
|
|
|
payload, _ := result.Value.(map[string]any)
|
2026-03-31 06:33:01 +00:00
|
|
|
memories := memoriesFromPayload(payload)
|
2026-03-16 11:10:33 +00:00
|
|
|
|
|
|
|
|
return nil, RecallOutput{
|
|
|
|
|
Success: true,
|
|
|
|
|
Count: len(memories),
|
|
|
|
|
Memories: memories,
|
|
|
|
|
}, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *DirectSubsystem) forget(ctx context.Context, _ *mcp.CallToolRequest, input ForgetInput) (*mcp.CallToolResult, ForgetOutput, error) {
|
2026-03-29 23:45:48 +00:00
|
|
|
result := s.apiCall(ctx, "DELETE", core.Concat("/v1/brain/forget/", input.ID), nil)
|
|
|
|
|
if !result.OK {
|
|
|
|
|
err, _ := result.Value.(error)
|
2026-03-16 11:10:33 +00:00
|
|
|
return nil, ForgetOutput{}, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil, ForgetOutput{
|
|
|
|
|
Success: true,
|
|
|
|
|
Forgotten: input.ID,
|
|
|
|
|
Timestamp: time.Now(),
|
|
|
|
|
}, nil
|
|
|
|
|
}
|
2026-03-31 06:33:01 +00:00
|
|
|
|
|
|
|
|
func (s *DirectSubsystem) list(ctx context.Context, _ *mcp.CallToolRequest, input ListInput) (*mcp.CallToolResult, ListOutput, error) {
|
|
|
|
|
params := url.Values{}
|
|
|
|
|
if input.Project != "" {
|
|
|
|
|
params.Set("project", input.Project)
|
|
|
|
|
}
|
|
|
|
|
if input.Type != "" {
|
|
|
|
|
params.Set("type", input.Type)
|
|
|
|
|
}
|
|
|
|
|
if input.AgentID != "" {
|
|
|
|
|
params.Set("agent_id", input.AgentID)
|
|
|
|
|
}
|
|
|
|
|
if input.Limit > 0 {
|
|
|
|
|
params.Set("limit", core.Sprint(input.Limit))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
path := "/v1/brain/list"
|
|
|
|
|
if encoded := params.Encode(); encoded != "" {
|
|
|
|
|
path = core.Concat(path, "?", encoded)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result := s.apiCall(ctx, "GET", path, nil)
|
|
|
|
|
if !result.OK {
|
|
|
|
|
err, _ := result.Value.(error)
|
|
|
|
|
return nil, ListOutput{}, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
payload, _ := result.Value.(map[string]any)
|
|
|
|
|
memories := memoriesFromPayload(payload)
|
|
|
|
|
|
|
|
|
|
return nil, ListOutput{
|
|
|
|
|
Success: true,
|
|
|
|
|
Count: len(memories),
|
|
|
|
|
Memories: memories,
|
|
|
|
|
}, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func memoriesFromPayload(payload map[string]any) []Memory {
|
|
|
|
|
var memories []Memory
|
2026-03-31 11:52:01 +00:00
|
|
|
source := payloadMap(payload)
|
|
|
|
|
if mems, ok := source["memories"].([]any); ok {
|
2026-03-31 06:33:01 +00:00
|
|
|
for _, m := range mems {
|
|
|
|
|
memoryMap, ok := m.(map[string]any)
|
|
|
|
|
if !ok {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memory := Memory{
|
2026-04-02 08:26:02 +00:00
|
|
|
Content: stringField(memoryMap, "content"),
|
|
|
|
|
Type: stringField(memoryMap, "type"),
|
|
|
|
|
Project: stringField(memoryMap, "project"),
|
|
|
|
|
WorkspaceID: stringField(memoryMap, "workspace_id"),
|
|
|
|
|
AgentID: stringField(memoryMap, "agent_id"),
|
|
|
|
|
Source: stringField(memoryMap, "source"),
|
|
|
|
|
CreatedAt: stringField(memoryMap, "created_at"),
|
|
|
|
|
UpdatedAt: stringField(memoryMap, "updated_at"),
|
|
|
|
|
ExpiresAt: stringField(memoryMap, "expires_at"),
|
|
|
|
|
DeletedAt: stringField(memoryMap, "deleted_at"),
|
2026-03-31 06:33:01 +00:00
|
|
|
}
|
|
|
|
|
if id, ok := memoryMap["id"].(string); ok {
|
|
|
|
|
memory.ID = id
|
|
|
|
|
}
|
|
|
|
|
if score, ok := memoryMap["score"].(float64); ok {
|
|
|
|
|
memory.Confidence = score
|
|
|
|
|
}
|
|
|
|
|
if confidence, ok := memoryMap["confidence"].(float64); ok && memory.Confidence == 0 {
|
|
|
|
|
memory.Confidence = confidence
|
|
|
|
|
}
|
|
|
|
|
if supersedesID, ok := memoryMap["supersedes_id"].(string); ok {
|
|
|
|
|
memory.SupersedesID = supersedesID
|
|
|
|
|
}
|
2026-04-02 02:39:59 +00:00
|
|
|
if supersedesCount, ok := memoryMap["supersedes_count"].(float64); ok {
|
|
|
|
|
memory.SupersedesCount = int(supersedesCount)
|
|
|
|
|
}
|
|
|
|
|
if supersedesCount, ok := memoryMap["supersedes_count"].(int); ok {
|
|
|
|
|
memory.SupersedesCount = supersedesCount
|
|
|
|
|
}
|
2026-03-31 06:33:01 +00:00
|
|
|
if tags, ok := memoryMap["tags"].([]any); ok {
|
|
|
|
|
for _, tag := range tags {
|
|
|
|
|
memory.Tags = append(memory.Tags, core.Sprint(tag))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if source, ok := memoryMap["source"].(string); ok {
|
2026-04-01 10:36:12 +00:00
|
|
|
if memory.Source == "" {
|
|
|
|
|
memory.Source = source
|
|
|
|
|
}
|
2026-03-31 06:33:01 +00:00
|
|
|
memory.Tags = append(memory.Tags, core.Concat("source:", source))
|
|
|
|
|
}
|
|
|
|
|
memories = append(memories, memory)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return memories
|
|
|
|
|
}
|
2026-03-31 11:52:01 +00:00
|
|
|
|
|
|
|
|
func payloadMap(payload map[string]any) map[string]any {
|
|
|
|
|
if data, ok := payload["data"].(map[string]any); ok && len(data) > 0 {
|
|
|
|
|
return data
|
|
|
|
|
}
|
|
|
|
|
return payload
|
|
|
|
|
}
|