mirror of
https://github.com/syntrex-lab/gomcp.git
synced 2026-07-02 15:51:00 +02:00
initial: Syntrex extraction from sentinel-community (615 files)
This commit is contained in:
commit
2c50c993b1
175 changed files with 32396 additions and 0 deletions
64
internal/application/resources/provider.go
Normal file
64
internal/application/resources/provider.go
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
// Package resources provides MCP resource implementations.
|
||||
package resources
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/sentinel-community/gomcp/internal/domain/memory"
|
||||
"github.com/sentinel-community/gomcp/internal/domain/session"
|
||||
)
|
||||
|
||||
// Provider serves MCP resources (rlm://state, rlm://facts, rlm://stats).
|
||||
type Provider struct {
|
||||
factStore memory.FactStore
|
||||
stateStore session.StateStore
|
||||
}
|
||||
|
||||
// NewProvider creates a new resource Provider.
|
||||
func NewProvider(factStore memory.FactStore, stateStore session.StateStore) *Provider {
|
||||
return &Provider{
|
||||
factStore: factStore,
|
||||
stateStore: stateStore,
|
||||
}
|
||||
}
|
||||
|
||||
// GetState returns the current cognitive state for a session as JSON.
|
||||
func (p *Provider) GetState(ctx context.Context, sessionID string) (string, error) {
|
||||
state, _, err := p.stateStore.Load(ctx, sessionID, nil)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("load state: %w", err)
|
||||
}
|
||||
data, err := json.MarshalIndent(state, "", " ")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("marshal state: %w", err)
|
||||
}
|
||||
return string(data), nil
|
||||
}
|
||||
|
||||
// GetFacts returns L0 facts as JSON.
|
||||
func (p *Provider) GetFacts(ctx context.Context) (string, error) {
|
||||
facts, err := p.factStore.ListByLevel(ctx, memory.LevelProject)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("list L0 facts: %w", err)
|
||||
}
|
||||
data, err := json.MarshalIndent(facts, "", " ")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("marshal facts: %w", err)
|
||||
}
|
||||
return string(data), nil
|
||||
}
|
||||
|
||||
// GetStats returns fact store statistics as JSON.
|
||||
func (p *Provider) GetStats(ctx context.Context) (string, error) {
|
||||
stats, err := p.factStore.Stats(ctx)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("get stats: %w", err)
|
||||
}
|
||||
data, err := json.MarshalIndent(stats, "", " ")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("marshal stats: %w", err)
|
||||
}
|
||||
return string(data), nil
|
||||
}
|
||||
150
internal/application/resources/provider_test.go
Normal file
150
internal/application/resources/provider_test.go
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
package resources
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/sentinel-community/gomcp/internal/domain/memory"
|
||||
"github.com/sentinel-community/gomcp/internal/domain/session"
|
||||
"github.com/sentinel-community/gomcp/internal/infrastructure/sqlite"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func newTestProvider(t *testing.T) (*Provider, *sqlite.DB, *sqlite.DB) {
|
||||
t.Helper()
|
||||
|
||||
factDB, err := sqlite.OpenMemory()
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() { factDB.Close() })
|
||||
|
||||
stateDB, err := sqlite.OpenMemory()
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() { stateDB.Close() })
|
||||
|
||||
factRepo, err := sqlite.NewFactRepo(factDB)
|
||||
require.NoError(t, err)
|
||||
|
||||
stateRepo, err := sqlite.NewStateRepo(stateDB)
|
||||
require.NoError(t, err)
|
||||
|
||||
return NewProvider(factRepo, stateRepo), factDB, stateDB
|
||||
}
|
||||
|
||||
func TestNewProvider(t *testing.T) {
|
||||
p, _, _ := newTestProvider(t)
|
||||
require.NotNil(t, p)
|
||||
assert.NotNil(t, p.factStore)
|
||||
assert.NotNil(t, p.stateStore)
|
||||
}
|
||||
|
||||
func TestProvider_GetFacts_Empty(t *testing.T) {
|
||||
p, _, _ := newTestProvider(t)
|
||||
ctx := context.Background()
|
||||
|
||||
result, err := p.GetFacts(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
var facts []interface{}
|
||||
require.NoError(t, json.Unmarshal([]byte(result), &facts))
|
||||
assert.Empty(t, facts)
|
||||
}
|
||||
|
||||
func TestProvider_GetFacts_WithData(t *testing.T) {
|
||||
p, _, _ := newTestProvider(t)
|
||||
ctx := context.Background()
|
||||
|
||||
// Add L0 facts directly via factStore.
|
||||
f1 := memory.NewFact("Project uses Go", memory.LevelProject, "core", "")
|
||||
f2 := memory.NewFact("Domain fact", memory.LevelDomain, "backend", "")
|
||||
require.NoError(t, p.factStore.Add(ctx, f1))
|
||||
require.NoError(t, p.factStore.Add(ctx, f2))
|
||||
|
||||
result, err := p.GetFacts(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Should only return L0 facts.
|
||||
assert.Contains(t, result, "Project uses Go")
|
||||
assert.NotContains(t, result, "Domain fact")
|
||||
}
|
||||
|
||||
func TestProvider_GetStats(t *testing.T) {
|
||||
p, _, _ := newTestProvider(t)
|
||||
ctx := context.Background()
|
||||
|
||||
// Add some facts.
|
||||
f1 := memory.NewFact("fact1", memory.LevelProject, "core", "")
|
||||
f2 := memory.NewFact("fact2", memory.LevelDomain, "core", "")
|
||||
require.NoError(t, p.factStore.Add(ctx, f1))
|
||||
require.NoError(t, p.factStore.Add(ctx, f2))
|
||||
|
||||
result, err := p.GetStats(ctx)
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, result, "total_facts")
|
||||
|
||||
var stats map[string]interface{}
|
||||
require.NoError(t, json.Unmarshal([]byte(result), &stats))
|
||||
assert.Equal(t, float64(2), stats["total_facts"])
|
||||
}
|
||||
|
||||
func TestProvider_GetStats_Empty(t *testing.T) {
|
||||
p, _, _ := newTestProvider(t)
|
||||
ctx := context.Background()
|
||||
|
||||
result, err := p.GetStats(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
var stats map[string]interface{}
|
||||
require.NoError(t, json.Unmarshal([]byte(result), &stats))
|
||||
assert.Equal(t, float64(0), stats["total_facts"])
|
||||
}
|
||||
|
||||
func TestProvider_GetState(t *testing.T) {
|
||||
p, _, _ := newTestProvider(t)
|
||||
ctx := context.Background()
|
||||
|
||||
// Save a state first.
|
||||
state := session.NewCognitiveStateVector("test-session")
|
||||
state.SetGoal("Build GoMCP", 0.5)
|
||||
state.AddFact("Go 1.25", "requirement", 1.0)
|
||||
checksum := state.Checksum()
|
||||
require.NoError(t, p.stateStore.Save(ctx, state, checksum))
|
||||
|
||||
result, err := p.GetState(ctx, "test-session")
|
||||
require.NoError(t, err)
|
||||
assert.Contains(t, result, "test-session")
|
||||
assert.Contains(t, result, "Build GoMCP")
|
||||
}
|
||||
|
||||
func TestProvider_GetState_NotFound(t *testing.T) {
|
||||
p, _, _ := newTestProvider(t)
|
||||
ctx := context.Background()
|
||||
|
||||
_, err := p.GetState(ctx, "nonexistent")
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestProvider_GetFacts_JSONFormat(t *testing.T) {
|
||||
p, _, _ := newTestProvider(t)
|
||||
ctx := context.Background()
|
||||
|
||||
f := memory.NewFact("JSON test", memory.LevelProject, "test", "")
|
||||
require.NoError(t, p.factStore.Add(ctx, f))
|
||||
|
||||
result, err := p.GetFacts(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Should be valid indented JSON.
|
||||
assert.True(t, json.Valid([]byte(result)))
|
||||
assert.Contains(t, result, "\n") // Indented.
|
||||
}
|
||||
|
||||
func TestProvider_GetStats_JSONFormat(t *testing.T) {
|
||||
p, _, _ := newTestProvider(t)
|
||||
ctx := context.Background()
|
||||
|
||||
result, err := p.GetStats(ctx)
|
||||
require.NoError(t, err)
|
||||
assert.True(t, json.Valid([]byte(result)))
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue