Phase 1 delivers the complete durability and storage layer:
- WAL with crash recovery: Append-only journal with BLAKE3 checksums,
fsync guarantees, and proper seek-to-EOF on reopen
- Storage engine: sled-backed KVStore with scan_prefix for range queries
- Content-addressed storage: H:{hash}, V:{hash}, E:{hash} key patterns
- Ingestor: Background worker tailing WAL, writing to KV with 8-byte
aligned record headers for rkyv zero-copy deserialization
- Comprehensive tests: 31 tests covering crash recovery, round-trips,
and multi-cycle durability
New crates: stemedb-wal, stemedb-storage, stemedb-ingest
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
329 lines
9.6 KiB
Markdown
329 lines
9.6 KiB
Markdown
# ADK-Go Integration Pattern
|
|
|
|
## Summary
|
|
|
|
Tool definitions and callback patterns for Google ADK-Go agents consuming Episteme. Covers query, assert, constraint check, and trace operations with proper struct tags and callback signatures.
|
|
|
|
## Core Mechanism
|
|
|
|
ADK-Go agents interact with Episteme through:
|
|
|
|
1. **Tools** - Structured operations (query, assert, trace) defined as Go structs
|
|
2. **Callbacks** - Hooks for pre-flight checks and audit logging
|
|
3. **State** - Session state for agent-to-agent communication
|
|
|
|
## Tool Definition Pattern
|
|
|
|
All Episteme tools follow this structure:
|
|
|
|
```go
|
|
import (
|
|
"google.golang.org/adk/tool"
|
|
"google.golang.org/adk/tool/functiontool"
|
|
)
|
|
|
|
type [Operation]Input struct {
|
|
// Required fields (no omitempty)
|
|
Subject string `json:"subject" jsonschema:"Entity to query (e.g., auth/jwt)"`
|
|
Predicate string `json:"predicate" jsonschema:"Relation to query (e.g., signing_algorithm)"`
|
|
|
|
// Optional fields (with omitempty)
|
|
Lens string `json:"lens,omitempty" jsonschema:"Resolution: consensus, authority, recency, constraints"`
|
|
}
|
|
|
|
type [Operation]Output struct {
|
|
Value interface{} `json:"value"`
|
|
Confidence float32 `json:"confidence"`
|
|
QueryID string `json:"query_id"` // CRITICAL: for audit trail
|
|
Error string `json:"error,omitempty"`
|
|
}
|
|
|
|
func [operation](ctx tool.Context, input [Operation]Input) [Operation]Output {
|
|
// 1. Call Episteme API
|
|
// 2. Return structured result with QueryID
|
|
}
|
|
|
|
// Register with functiontool.New()
|
|
tool, err := functiontool.New(
|
|
functiontool.Config{
|
|
Name: "episteme_query",
|
|
Description: "Query Episteme knowledge graph",
|
|
},
|
|
queryEpisteme,
|
|
)
|
|
```
|
|
|
|
## Standard Tools
|
|
|
|
### Query Tool
|
|
|
|
```go
|
|
type QueryInput struct {
|
|
Subject string `json:"subject" jsonschema:"Entity to query (e.g., auth/jwt)"`
|
|
Predicate string `json:"predicate" jsonschema:"Relation to query (e.g., signing_algorithm)"`
|
|
Lens string `json:"lens,omitempty" jsonschema:"Resolution: consensus, authority, recency, constraints"`
|
|
Lifecycle string `json:"lifecycle,omitempty" jsonschema:"Filter: proposed, approved, deprecated"`
|
|
MinConfidence float32 `json:"min_confidence,omitempty" jsonschema:"Minimum confidence threshold (0.0-1.0)"`
|
|
AsOf string `json:"as_of,omitempty" jsonschema:"Time-travel: ISO8601 timestamp"`
|
|
}
|
|
|
|
type QueryOutput struct {
|
|
Value interface{} `json:"value"`
|
|
Confidence float32 `json:"confidence"`
|
|
Lifecycle string `json:"lifecycle"`
|
|
Sources []Source `json:"sources"`
|
|
QueryID string `json:"query_id"`
|
|
}
|
|
```
|
|
|
|
### Assert Tool
|
|
|
|
```go
|
|
type AssertInput struct {
|
|
Subject string `json:"subject" jsonschema:"Entity being described"`
|
|
Predicate string `json:"predicate" jsonschema:"Relation being asserted"`
|
|
Object interface{} `json:"object" jsonschema:"Value being claimed"`
|
|
SourceHash string `json:"source_hash" jsonschema:"BLAKE3 hash of evidence"`
|
|
Confidence float32 `json:"confidence" jsonschema:"Certainty level (0.0-1.0)"`
|
|
Lifecycle string `json:"lifecycle,omitempty" jsonschema:"proposed, under_review, approved"`
|
|
ParentHash string `json:"parent_hash,omitempty" jsonschema:"Hash of assertion being updated"`
|
|
Meta *AssertMeta `json:"meta,omitempty" jsonschema:"Additional metadata"`
|
|
}
|
|
|
|
type AssertMeta struct {
|
|
ForbiddenAlternative string `json:"forbidden_alternative,omitempty"`
|
|
Reason string `json:"reason,omitempty"`
|
|
}
|
|
|
|
type AssertOutput struct {
|
|
Hash string `json:"hash"`
|
|
Success bool `json:"success"`
|
|
Error string `json:"error,omitempty"`
|
|
}
|
|
```
|
|
|
|
### Constraint Check Tool
|
|
|
|
```go
|
|
type ConstraintCheckInput struct {
|
|
Context string `json:"context" jsonschema:"Domain context (e.g., python_http, auth_jwt)"`
|
|
}
|
|
|
|
type ConstraintCheckOutput struct {
|
|
Constraints []Constraint `json:"constraints"`
|
|
}
|
|
|
|
type Constraint struct {
|
|
Subject string `json:"subject"`
|
|
MustUse string `json:"must_use,omitempty"`
|
|
Forbidden string `json:"forbidden,omitempty"`
|
|
Reason string `json:"reason"`
|
|
}
|
|
```
|
|
|
|
### Trace Tool (SRE)
|
|
|
|
```go
|
|
type TraceInput struct {
|
|
AgentID string `json:"agent_id" jsonschema:"Agent to trace"`
|
|
From string `json:"from" jsonschema:"Start time (ISO8601 or relative like -6h)"`
|
|
To string `json:"to,omitempty" jsonschema:"End time (default: now)"`
|
|
Subject string `json:"subject,omitempty" jsonschema:"Filter by subject pattern (e.g., auth/*)"`
|
|
}
|
|
|
|
type TraceOutput struct {
|
|
Queries []QueryTrace `json:"queries"`
|
|
}
|
|
|
|
type QueryTrace struct {
|
|
QueryID string `json:"query_id"`
|
|
Timestamp string `json:"timestamp"`
|
|
Subject string `json:"subject"`
|
|
Predicate string `json:"predicate"`
|
|
Lens string `json:"lens"`
|
|
Result string `json:"result"`
|
|
Confidence float32 `json:"confidence"`
|
|
Contributing []string `json:"contributing_assertions"`
|
|
}
|
|
```
|
|
|
|
## Callback Integration
|
|
|
|
### BeforeToolCallback - Constraint Pre-flight
|
|
|
|
Critical for preventing repeat mistakes:
|
|
|
|
```go
|
|
agent, err := llmagent.New(llmagent.Config{
|
|
Name: "implementation_agent",
|
|
Model: model,
|
|
Tools: []tool.Tool{queryTool, assertTool},
|
|
|
|
BeforeToolCallback: func(ctx agent.CallbackContext, call *tool.Call) (*tool.Call, error) {
|
|
// Check constraints before any tool that could use wrong patterns
|
|
if needsConstraintCheck(call) {
|
|
constraints := checkConstraints(ctx, extractContext(call))
|
|
for _, c := range constraints {
|
|
if violates(call, c) {
|
|
return nil, fmt.Errorf("blocked: %s is forbidden - %s",
|
|
c.Forbidden, c.Reason)
|
|
}
|
|
}
|
|
}
|
|
return call, nil
|
|
},
|
|
})
|
|
```
|
|
|
|
### AfterModelCallback - Audit Trail
|
|
|
|
Log agent decisions for debugging:
|
|
|
|
```go
|
|
AfterModelCallback: func(ctx agent.CallbackContext, resp *model.LLMResponse) (*model.LLMResponse, error) {
|
|
// Log what the agent decided for future tracing
|
|
decision := extractDecision(resp)
|
|
logToEpisteme(ctx, AuditEntry{
|
|
AgentID: ctx.Agent().Name(),
|
|
Timestamp: time.Now(),
|
|
Decision: decision,
|
|
Context: ctx.Session().State(),
|
|
})
|
|
return resp, nil
|
|
},
|
|
```
|
|
|
|
### AfterToolCallback - Error Learning
|
|
|
|
Trigger Gardener when tools fail:
|
|
|
|
```go
|
|
AfterToolCallback: func(ctx agent.CallbackContext, call *tool.Call, result *tool.Result) (*tool.Result, error) {
|
|
if result.Error != nil {
|
|
// Notify Gardener of the failure for TrustRank back-propagation
|
|
notifyGardener(ctx, GardenerEvent{
|
|
AgentID: ctx.Agent().Name(),
|
|
ToolCall: call,
|
|
Error: result.Error,
|
|
QueryID: extractQueryID(call),
|
|
})
|
|
}
|
|
return result, nil
|
|
},
|
|
```
|
|
|
|
## Agent-Specific Patterns
|
|
|
|
### Lead Orchestrator
|
|
|
|
Fast queries with confidence thresholds:
|
|
|
|
```go
|
|
result := queryEpisteme(ctx, QueryInput{
|
|
Subject: "auth/jwt",
|
|
Predicate: "signing_algorithm",
|
|
Lens: "authority",
|
|
MinConfidence: 0.8,
|
|
})
|
|
if result.Confidence < 0.8 {
|
|
// Escalate to human or research agent
|
|
return escalate(ctx, result)
|
|
}
|
|
```
|
|
|
|
### Implementation Agent
|
|
|
|
Approved patterns only:
|
|
|
|
```go
|
|
result := queryEpisteme(ctx, QueryInput{
|
|
Subject: "auth/jwt",
|
|
Predicate: "signing_algorithm",
|
|
Lens: "authority",
|
|
Lifecycle: "approved", // CRITICAL: never use proposed patterns
|
|
})
|
|
```
|
|
|
|
### Research Agent
|
|
|
|
Store with uncertainty and contradictions:
|
|
|
|
```go
|
|
assertKnowledge(ctx, AssertInput{
|
|
Subject: "jwt_rotation",
|
|
Predicate: "best_practice",
|
|
Object: "rotate_daily",
|
|
SourceHash: hashURL(sourceURL),
|
|
Confidence: 0.7, // Express uncertainty
|
|
Lifecycle: "proposed",
|
|
})
|
|
|
|
// Store contradicting information - don't flatten
|
|
assertKnowledge(ctx, AssertInput{
|
|
Subject: "jwt_rotation",
|
|
Predicate: "best_practice",
|
|
Object: "rotate_weekly",
|
|
SourceHash: hashURL(differentSourceURL),
|
|
Confidence: 0.6,
|
|
Lifecycle: "proposed",
|
|
})
|
|
```
|
|
|
|
### Human Supervisor
|
|
|
|
Time-travel and corrections:
|
|
|
|
```go
|
|
// What was believed during the incident?
|
|
result := queryEpisteme(ctx, QueryInput{
|
|
Subject: "auth/jwt",
|
|
Predicate: "signing_algorithm",
|
|
AsOf: "2024-01-15T21:00:00Z",
|
|
})
|
|
|
|
// Correct the record
|
|
supersede(ctx, SupersedeInput{
|
|
Hash: badAssertionHash,
|
|
Reason: "Proposal treated as approved - was never reviewed",
|
|
Type: "Invalidate",
|
|
})
|
|
```
|
|
|
|
### On-Call SRE
|
|
|
|
Trace agent decisions:
|
|
|
|
```go
|
|
traces := traceAgentQueries(ctx, TraceInput{
|
|
AgentID: "deployment-agent",
|
|
From: "-6h",
|
|
Subject: "auth/*",
|
|
})
|
|
|
|
for _, t := range traces.Queries {
|
|
fmt.Printf("[%s] %s/%s via %s -> %s (%.2f)\n",
|
|
t.Timestamp, t.Subject, t.Predicate,
|
|
t.Lens, t.Result, t.Confidence)
|
|
fmt.Printf(" Contributing: %v\n", t.Contributing)
|
|
}
|
|
```
|
|
|
|
## State vs Episteme
|
|
|
|
| Use | Mechanism |
|
|
|-----|-----------|
|
|
| Agent-to-agent handoff (same session) | Session State + OutputKey |
|
|
| Persistent organizational knowledge | Episteme Assert |
|
|
| What was decided in this conversation | Session State |
|
|
| What should all agents know forever | Episteme Assert |
|
|
| Temporary working data | `temp:` prefixed state keys |
|
|
| Audit trail | Episteme QueryAudit |
|
|
|
|
## Related
|
|
|
|
- [services/assertion.md](../services/assertion.md) - Core assertion structure
|
|
- [services/lens.md](../services/lens.md) - Lens resolution strategies
|
|
- [services/lifecycle.md](../services/lifecycle.md) - Lifecycle stage filtering
|
|
- [features/gardener.md](../features/gardener.md) - Error back-propagation
|
|
- [features/query-audit.md](../features/query-audit.md) - Trace and debug
|