Skip to content

Latest commit

 

History

History
91 lines (77 loc) · 5.92 KB

File metadata and controls

91 lines (77 loc) · 5.92 KB

GraphStore

Scala 3 reimagining of Graphiti's core ideas (bi-temporal edges, episodic ingestion, hybrid retrieval, contradiction-driven invalidation) on the Typelevel stack, wired into ADK4S as durable agent memory. See docs/graphstore-project.md for the full specification.

Build / verify

  • Scala 3.8.4, sbt 1.12.12, Java 26.
  • sbt projects — list GraphStore's 10 modules + ADK4S's modules (via ProjectRef).
  • sbt compile — compiles all 10 GraphStore modules (and the ADK4S modules they depend on).
  • sbt Test/compile — compile main + test sources (munit, munit-cats-effect, Hedgehog are shared test deps across all modules).
  • sbt scalafmtAll — format.
  • sbt "scalafix --check" — lint (DisableSyntax + RemoveUnused + OrganizeImports + custom regex rules; scoped guards forbid infra imports in domain/core).
  • sbt stryker4s — mutation testing (Ring 5; retarget stryker4s.conf mutate list per spec). Run with JAVA_OPTS="-Xmx4g -XX:+UseG1GC" sbt "api/stryker" (target specific module; root stryker runs all modules and OOMs). In multi-module builds, Stryker4s may report many NoCoverage mutants because the test runner can't trace coverage through smithy4s HTTP indirection — the meaningful metric is "100% on covered code".
  • WartRemover is active (Warts.unsafe minus TripleQuestionMark, Any, DefaultArguments). -Werror is on — use @nowarn with a justification for unavoidable deprecations.

OpenSpec workflow

  • openspec/config.yaml is configured for the verified-scala3 schema (v2).
  • The context section describes GraphStore's actual stack (10 modules, Ciris not PureConfig, munit+Hedgehog not ScalaTest/ScalaCheck, neotypes+Lucene+http4s+smithy4s, otel4s, ADK4S via ProjectRef).
  • The concept-scanner lives at openspec/schemas/verified-scala3/scanner/ (scala-cli based; build artifacts are gitignored).
  • Skills for the OpenSpec workflow are available: openspec-new-change, openspec-continue-change, openspec-apply-change, openspec-verify-change, openspec-archive-change, etc.

ADK4S source dependency (sbt ProjectRef)

GraphStore consumes ADK4S via ProjectRef against the local source checkout at /home/gruggiero/git/rs/adk4s (configured as adk4sBase in build.sbt). This gives live co-development: edits in ADK4S are visible immediately, no publishLocal needed.

Requirements / constraints:

  • sbt version must match ADK4S (1.12.12) — ProjectRef loads ADK4S's project/ (plugins), so version mismatches break the build.
  • Scala version must match ADK4S (3.8.4) — TASTy is backward-compatible only (newer compiler reads older TASTy); 3.4.2 cannot consume 3.8.4 TASTy.
  • sbt-wartremover is in GraphStore's project/plugins.sbt — ADK4S's build applies WartRemover errors via ThisBuild; without the plugin here, the -P:wartremover compiler options fail with "bad option".
  • smithy4s version is 0.18.55 (matching ADK4S) — the codegen output must match the runtime smithy4s jar on the classpath (which comes from ADK4S transitively).

The four ADK4S projects referenced:

  • adk4s-coreChatModel, Embedder, Retriever
  • structured-llmStructuredLLM, Prompt, Schema
  • adk4s-memory-apiAgentMemory, Episode, EpisodeOutcome, MemoryHit, TemporalScope, SourceType
  • adk4s-memory-testkitAgentMemoryLaws (main scope; consumed by episode's Test scope via "test->compile")
  • The episode module also depends on neo4j % "test->test" so its tests can use InMemoryGraphStore (which lives in neo4j Test scope) for AgentMemoryLaws conformance testing.

Module map

domain ─┬─ neo4j ─┐
        ├─ embedder(→ adk4s-core) ┤
        ├─ temporal ┤
        └─ search ─┴─ episode(→ adk4s-core, structured-llm, adk4s-memory-api) ── api

config depends on domain, neo4j; telemetry on domain; core on domain. The smithy IDL for the HTTP API lives in smithy/src/main/smithy/ (consumed by api via Smithy4sCodegenPlugin). The episode module has its own smithy IDL at modules/episode/src/main/smithy/extraction.smithy for the extraction DTOs (consumed by episode via Smithy4sCodegenPlugin).

Notes / deviations from the doc

  • config adds a neo4j dependency so it can reference Neo4jConfig (the doc lists only domain, which would not compile).
  • Neo4jGraphStore.resource is implemented — creates a neotypes AsyncDriver from Neo4jConfig and yields Neo4jGraphStoreImpl. All 13 GraphStore methods are implemented with parameterized Cypher. Instant values are stored as epoch-millis; Map properties are JSON-encoded as strings. Tests use Testcontainers with a shared container and a serializing Semaphore to prevent parallel interference.
  • EpisodeProcessor.build uses a name -> NodeId map (fixing the §8.2 known-gap: matching on labels.contains(name) was wrong because labels holds entity types, not names).
  • InMemoryGraphStore lives in neo4j Test scope; downstream modules' tests that need it must add dependsOn(neo4j % Test) or extract a testkit module.
  • Extraction DTOs (ExtractedEntity, ExtractedRelationship, etc.) are generated by smithy4s codegen from extraction.smithy, not hand-written as case classes. This matches ADK4S's own pattern (structured-llm-test-models). smithy4s generates optional fields as Option[T] and renames reserved words (object_object).
  • Schema.instance signature confirmed: instance(smithy: String, desc: Option[String] = None)(using SmithySchema[A]).
  • MemoryHit has validFrom/validTo fields (both default None); GraphStoreMemory.toHit populates text, score, provenance, payload.
  • GraphStoreServer.build uses SimpleRestJsonBuilder.routes(impl) to convert the smithy4s service implementation into HttpRoutes[F], then wires them into an EmberServerBuilder. The @nowarn("cat=deprecation") was removed because the current wiring no longer triggers deprecation warnings.