Source identity
| Field | Recorded value |
|---|---|
| Source type | GitHub source |
| Original record | Janady13/missionmatch / internal/modules/ai/memory.go |
| Date | Not specified in source |
| Repository | Janady13/missionmatch |
| Revision | 720d47fae476b0d38477ae4401697d372b1ea2bc |
| Branch | feature/opportunity-to-outcome |
| Path or archive member | internal/modules/ai/memory.go |
| Original SHA-256 | f20d9abc85fdfdee2cbc3d216fb4cf1ce259f6cbf9ddd1e2b9793b9aa015b82c |
| Git blob SHA | 82f51c27cea26c5d44acbcc86fb5bbce1dc07ffb |
| Reading-copy SHA-256 | f20d9abc85fdfdee2cbc3d216fb4cf1ce259f6cbf9ddd1e2b9793b9aa015b82c |
Every recorded occurrence
These 23 records contain identical original source bytes. Their paths and revisions remain part of the archive.
| Original record | Branch or archive | Revision / identifier | Original location |
|---|---|---|---|
| Janady13/missionmatch / internal/modules/ai/memory.go | feature/opportunity-to-outcome | 720d47fae476b0d38477ae4401697d372b1ea2bc | Open original |
| Janady13/missionmatch / internal/modules/ai/memory.go | per-tenant-routing | 9bde0f9a74b89d01980fa658e5253acda7528d0c | Open original |
| Janady13/missionmatch / internal/modules/ai/memory.go | collision-deconfliction | 4ee5a09972608ed89f8377c6665542d5f450f0a6 | Open original |
| Janady13/missionmatch / internal/modules/ai/memory.go | ws6-retrieval | 6c56e29231ec05735927fa265c97d517499dfeaf | Open original |
| Janady13/missionmatch / internal/modules/ai/memory.go | m5-price-to-win | 41000ad30fff4129fdaf5ec84e15ba14c27d4890 | Open original |
| Janady13/missionmatch / internal/modules/ai/memory.go | ws1-ontology-sync | b596f449a32a1016fbd403c36505cc00a1ac9ee6 | Open original |
| Janady13/missionmatch / internal/modules/ai/memory.go | master | 1e9249840a4302ec82e123b9c9cb6f75badea3e4 | Open original |
| Janady13/missionmatch / internal/modules/ai/memory.go | ws8-teaching-loop | c823f0fb6bb2aba0f39001eb6de96f4000d9321f | Open original |
| Janady13/missionmatch / internal/modules/ai/memory.go | mag-substrate | b82c7100a492dec67dfd1eda6b3f53def859be35 | Open original |
| Janady13/missionmatch / internal/modules/ai/memory.go | ws3-clearance | 4b8e7ce594c068621867f9c9deed0ec64ae6c553 | Open original |
| Janady13/missionmatch / internal/modules/ai/memory.go | phase2-eval-fairness | d361af254701975fe239927656ababb56374655e | Open original |
| Janady13/missionmatch / internal/modules/ai/memory.go | time-to-fill-survival | b66e1e505863d4f17741a4b9ede73509e45bd6c6 | Open original |
| Janady13/missionmatch / internal/modules/ai/memory.go | graphrag-foundation | b0ddeb9f633fd138d09309d1a17b7d13bc3a67f7 | Open original |
| Janady13/missionmatch / internal/modules/ai/memory.go | deploy-and-ops | bdacd9d0b4d5998d25fc74bf4007f4c3ec538c7a | Open original |
| Janady13/missionmatch / internal/modules/ai/memory.go | ws9-bench-ingestion | f585a9ef32fa554663ce1fba9a414a54b6e49cf0 | Open original |
| Janady13/missionmatch / internal/modules/ai/memory.go | ws2-alias-relationship | e4dada4601c6eb101830f9d223a9655dfa120616 | Open original |
| Janady13/missionmatch / internal/modules/ai/memory.go | presentation-readiness | eb574acaa29d71ce4d0f852572e87c275c79fdb7 | Open original |
| Janady13/missionmatch / internal/modules/ai/memory.go | vendor-intelligence | fe9796a19c261951d3f2565206c0c1b5ac294465 | Open original |
| Janady13/missionmatch / internal/modules/ai/memory.go | ws7-federal-signal | 6a9f6ce9cfb13345ffb47770d4960e7c2d9c17c2 | Open original |
| Janady13/missionmatch / internal/modules/ai/memory.go | ai-brain-live | aac32fc49c878cc5bca099459307611562d0bac1 | Open original |
| Janady13/missionmatch / internal/modules/ai/memory.go | phase2-connectors | e038d4c687aec16f8bd9bc4d907eea14d91f8704 | Open original |
| Janady13/missionmatch / internal/modules/ai/memory.go | feature/aioe-upgrade | 2178e7298d0e5d9af83afa12402fd587f0ba6ed8 | Open original |
| Janady13/missionmatch / internal/modules/ai/memory.go | capture-readiness | bae6af7cb2997e819174a9e9cfff5e16067a1975 | Open original |
Recovered source transcript
Download complete source text ↓126 lines · 4.2 KB
package ai
import (
"context"
"errors"
"strconv"
"github.com/google/uuid"
"github.com/jackc/pgx/v5"
"github.com/missionworkforce/missionmatch/internal/platform/inference"
"github.com/missionworkforce/missionmatch/internal/platform/tenant"
)
// Memory is the per tenant episodic and semantic memory, stored in the tenant's own database (ai_memory)
// and therefore physically isolated from every other tenant. Episodic memory records what happened (a
// craft note about a turn); semantic memory holds a recallable fact with an embedding. No demographic
// data may enter memory: every write is eeo guarded. Memory about a candidate carries the candidate id,
// so the right to erasure wipes it (ForgetCandidate), the same way anonymize wipes the resume vector.
type Memory struct {
db *tenant.DB
client *inference.Client
}
// NewMemory builds the per tenant memory over the tenant database and the inference client (for semantic
// recall embeddings).
func NewMemory(db *tenant.DB, client *inference.Client) *Memory {
return &Memory{db: db, client: client}
}
// Store writes one memory. candidateID may be nil for a non candidate craft note. content is eeo guarded.
// A semantic memory is embedded so it can be recalled by similarity.
func (m *Memory) Store(ctx context.Context, candidateID *uuid.UUID, kind, content string) error {
if m.db == nil {
return errors.New("ai: no database")
}
if kind != "episodic" && kind != "semantic" {
return errors.New("ai: memory kind must be episodic or semantic")
}
if err := ForbidEEO(content); err != nil {
return err
}
var vecLit any
if kind == "semantic" && m.client != nil {
emb, err := m.client.Embed(ctx, []string{content})
if err != nil {
return err
}
vecLit = vectorLiteral(emb.Embeddings[0])
}
return m.db.RunInTenantTx(ctx, func(ctx context.Context, tx pgx.Tx) error {
_, err := tx.Exec(ctx,
"INSERT INTO ai_memory (organization_id, candidate_id, kind, content, embedding) "+
"VALUES (NULLIF(current_setting('app.current_org_id', true),'')::uuid, $1, $2, $3, $4::vector)",
candidateID, kind, content, vecLit)
return err
})
}
// ForgetCandidate is the standalone erasure hook: it deletes every memory about a candidate in its OWN
// tenant transaction, for an external caller, and it is exercised by the memory erasure integration test.
// The transactional erasure paths (sourcing.Delete and the governance retention sweep) inline the same
// DELETE on their EXISTING transaction instead, so the memory wipe commits atomically with the rest of the
// anonymize. Idempotent.
func (m *Memory) ForgetCandidate(ctx context.Context, candidateID uuid.UUID) error {
if m.db == nil {
return errors.New("ai: no database")
}
return m.db.RunInTenantTx(ctx, func(ctx context.Context, tx pgx.Tx) error {
_, err := tx.Exec(ctx, "DELETE FROM ai_memory WHERE candidate_id = $1", candidateID)
return err
})
}
// Recall returns the semantically closest memories to a query (RLS scoped, eeo guarded). It is the
// retrieval side of memory augmented generation.
func (m *Memory) Recall(ctx context.Context, query string, limit int) ([]string, error) {
if m.db == nil || m.client == nil {
return nil, errors.New("ai: memory recall needs a database and a client")
}
if err := ForbidEEO(query); err != nil {
return nil, err
}
if limit <= 0 || limit > 50 {
limit = 5
}
emb, err := m.client.Embed(ctx, []string{query})
if err != nil {
return nil, err
}
lit := vectorLiteral(emb.Embeddings[0])
var out []string
err = m.db.RunInTenantTx(ctx, func(ctx context.Context, tx pgx.Tx) error {
rows, err := tx.Query(ctx,
"SELECT content FROM ai_memory WHERE embedding IS NOT NULL ORDER BY embedding <=> $1::vector LIMIT $2",
lit, limit)
if err != nil {
return err
}
defer rows.Close()
for rows.Next() {
var c string
if err := rows.Scan(&c); err != nil {
return err
}
out = append(out, c)
}
return rows.Err()
})
return out, err
}
// vectorLiteral formats a 384 dim vector as a pgvector text literal for the $::vector cast.
func vectorLiteral(v []float32) string {
b := make([]byte, 0, len(v)*8+2)
b = append(b, '[')
for i, x := range v {
if i > 0 {
b = append(b, ',')
}
b = strconv.AppendFloat(b, float64(x), 'f', -1, 32)
}
b = append(b, ']')
return string(b)
}